From b678d7c3f7dab680c0117b0bf5e88245366132ce Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 15 Aug 2017 16:44:04 -0700 Subject: [PATCH 001/106] cryptfs: remove reference to legacy make_ext4fs Use upstream mke2fs tool to format ext4 filesystem. Bug: 64395169 Change-Id: I383510f25a7c0935ddb280a14ef31fcbd143cba1 --- Android.mk | 9 +-------- cryptfs.cpp | 12 ------------ 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/Android.mk b/Android.mk index d0b199d..59486d9 100644 --- a/Android.mk +++ b/Android.mk @@ -85,14 +85,7 @@ vold_cflags := -Werror -Wall -Wno-missing-field-initializers -Wno-unused-variabl required_modules := ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) - ifeq ($(TARGET_USES_MKE2FS), true) - vold_cflags += -DTARGET_USES_MKE2FS - required_modules += mke2fs - else - # Adoptable storage has fully moved to mke2fs, so we need both tools - required_modules += mke2fs - required_modules += make_ext4fs - endif + required_modules += mke2fs endif include $(CLEAR_VARS) diff --git a/cryptfs.cpp b/cryptfs.cpp index 43c8177..3fc5437 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -1913,7 +1912,6 @@ static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type) int rc = -1; if (type == EXT4_FS) { -#ifdef TARGET_USES_MKE2FS args[0] = "/system/bin/mke2fs"; args[1] = "-M"; args[2] = "/data"; @@ -1925,16 +1923,6 @@ static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type) snprintf(size_str, sizeof(size_str), "%" PRId64, size / (4096 / 512)); args[8] = size_str; num_args = 9; -#else - args[0] = "/system/bin/make_ext4fs"; - args[1] = "-a"; - args[2] = "/data"; - args[3] = "-l"; - snprintf(size_str, sizeof(size_str), "%" PRId64, size * 512); - args[4] = size_str; - args[5] = crypto_blkdev; - num_args = 6; -#endif SLOGI("Making empty filesystem with command %s %s %s %s %s %s\n", args[0], args[1], args[2], args[3], args[4], args[5]); } else if (type == F2FS_FS) { From 068c6be6227949fbf34389b2d4c023c2031b005f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 6 Sep 2017 13:47:40 -0600 Subject: [PATCH 002/106] Start paving the way for vold calls over Binder. This change is the bare minimum needed to publish a new vold Binder service and move the simple "reset" call over to go through the new interface. Test: builds, boots Bug: 13758960 Change-Id: I5b70976653c69f92e1efc8d1f432b2038eb618a4 --- Android.mk | 4 ++ VoldNativeService.cpp | 116 +++++++++++++++++++++++++++++++++++ VoldNativeService.h | 39 ++++++++++++ binder/android/os/IVold.aidl | 22 +++++++ main.cpp | 6 ++ 5 files changed, 187 insertions(+) create mode 100644 VoldNativeService.cpp create mode 100644 VoldNativeService.h create mode 100644 binder/android/os/IVold.aidl diff --git a/Android.mk b/Android.mk index 59486d9..f6a8da9 100644 --- a/Android.mk +++ b/Android.mk @@ -35,6 +35,8 @@ common_src_files := \ secontext.cpp \ EncryptInplace.cpp \ MetadataCrypt.cpp \ + binder/android/os/IVold.aidl \ + VoldNativeService.cpp \ common_c_includes := \ system/extras/f2fs_utils \ @@ -129,6 +131,8 @@ LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) LOCAL_STATIC_LIBRARIES := $(common_static_libraries) LOCAL_REQUIRED_MODULES := $(required_modules) +LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder + include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp new file mode 100644 index 0000000..2d55e14 --- /dev/null +++ b/VoldNativeService.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "VoldNativeService.h" +#include "VolumeManager.h" + +#include + +#include +#include +#include +#include + +#ifndef LOG_TAG +#define LOG_TAG "vold" +#endif + +using android::base::StringPrintf; +using std::endl; + +namespace android { +namespace vold { + +namespace { + +constexpr const char* kDump = "android.permission.DUMP"; + +static binder::Status ok() { + return binder::Status::ok(); +} + +static binder::Status exception(uint32_t code, const std::string& msg) { + return binder::Status::fromExceptionCode(code, String8(msg.c_str())); +} + +binder::Status checkPermission(const char* permission) { + pid_t pid; + uid_t uid; + + if (checkCallingPermission(String16(permission), reinterpret_cast(&pid), + reinterpret_cast(&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)); + } +} + +#define ENFORCE_UID(uid) { \ + binder::Status status = checkUid((uid)); \ + if (!status.isOk()) { \ + return status; \ + } \ +} + +} // namespace + +status_t VoldNativeService::start() { + IPCThreadState::self()->disableBackgroundScheduling(true); + status_t ret = BinderService::publish(); + if (ret != android::OK) { + return ret; + } + sp ps(ProcessState::self()); + ps->startThreadPool(); + ps->giveThreadPoolName(); + return android::OK; +} + +status_t VoldNativeService::dump(int fd, const Vector & /* 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; + } + + out << "vold is happy!" << endl; + out.flush(); + + return NO_ERROR; +} + +binder::Status VoldNativeService::reset() { + ENFORCE_UID(AID_SYSTEM); + + LOG(INFO) << "reset() via Binder!"; + VolumeManager::Instance()->reset(); + return ok(); +} + +} // namespace vold +} // namespace android diff --git a/VoldNativeService.h b/VoldNativeService.h new file mode 100644 index 0000000..1866059 --- /dev/null +++ b/VoldNativeService.h @@ -0,0 +1,39 @@ +/* + * 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 + +#include "android/os/BnVold.h" + +namespace android { +namespace vold { + +class VoldNativeService : public BinderService, public os::BnVold { +public: + static status_t start(); + static char const* getServiceName() { return "vold"; } + virtual status_t dump(int fd, const Vector &args) override; + + binder::Status reset(); +}; + +} // namespace vold +} // namespace android + +#endif // _VOLD_NATIVE_SERVICE_H_ diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl new file mode 100644 index 0000000..5f7a3fe --- /dev/null +++ b/binder/android/os/IVold.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** {@hide} */ +interface IVold { + void reset(); +} diff --git a/main.cpp b/main.cpp index 30c839e..ec240ef 100644 --- a/main.cpp +++ b/main.cpp @@ -19,6 +19,7 @@ #include "CommandListener.h" #include "CryptCommandListener.h" #include "NetlinkManager.h" +#include "VoldNativeService.h" #include "cryptfs.h" #include "sehandle.h" @@ -106,6 +107,11 @@ int main(int argc, char** argv) { exit(1); } + if (android::vold::VoldNativeService::start() != android::OK) { + LOG(ERROR) << "Unable to start VoldNativeService"; + exit(1); + } + bool has_adoptable; bool has_quota; From 9462bdd5125bb5e410292a03aa041895af8f3486 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 7 Sep 2017 15:27:28 -0600 Subject: [PATCH 003/106] Move "volume" commands over to Binder. Keep the old socket-based commands intact for awhile so we can rapidly disable this change using the ENABLE_BINDER feature flag. Define constants in AIDL to keep Java and C++ in sync. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.ExternalStorageHostTest Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Bug: 13758960 Change-Id: I0d6f82cbebe67f671b60949fd727409aeb1fdc0d --- VoldNativeService.cpp | 172 ++++++++++++++++++++++++++++++++++- VoldNativeService.h | 22 +++++ VolumeManager.cpp | 2 +- VolumeManager.h | 2 +- binder/android/os/IVold.aidl | 50 ++++++++++ 5 files changed, 243 insertions(+), 5 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 2d55e14..f98c15d 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -16,6 +16,7 @@ #include "VoldNativeService.h" #include "VolumeManager.h" +#include "MoveTask.h" #include @@ -46,6 +47,19 @@ 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(uint32_t status) { + if (status == 0) { + return binder::Status::ok(); + } else { + return binder::Status::fromExceptionCode(status); + } +} + binder::Status checkPermission(const char* permission) { pid_t pid; uid_t uid; @@ -76,6 +90,8 @@ binder::Status checkUid(uid_t expectedUid) { } \ } +#define ACQUIRE_LOCK std::lock_guard lock(VolumeManager::Instance()->getLock()); + } // namespace status_t VoldNativeService::start() { @@ -98,19 +114,169 @@ status_t VoldNativeService::dump(int fd, const Vector & /* args */) { return PERMISSION_DENIED; } + ACQUIRE_LOCK; out << "vold is happy!" << endl; out.flush(); - return NO_ERROR; } binder::Status VoldNativeService::reset() { ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; - LOG(INFO) << "reset() via Binder!"; - VolumeManager::Instance()->reset(); + return translate(VolumeManager::Instance()->reset()); +} + +binder::Status VoldNativeService::shutdown() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->shutdown()); +} + +binder::Status VoldNativeService::setDebug(bool debug) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->setDebug(debug)); +} + +binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->onUserAdded(userId, userSerial)); +} + +binder::Status VoldNativeService::onUserRemoved(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->onUserRemoved(userId)); +} + +binder::Status VoldNativeService::onUserStarted(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->onUserStarted(userId)); +} + +binder::Status VoldNativeService::onUserStopped(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->onUserStopped(userId)); +} + +binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType, int32_t ratio) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + auto disk = VolumeManager::Instance()->findDisk(diskId); + if (disk == nullptr) { + return error("Failed to find disk " + diskId); + } + switch (partitionType) { + case PARTITION_TYPE_PUBLIC: return translate(disk->partitionPublic()); + case PARTITION_TYPE_PRIVATE: return translate(disk->partitionPrivate()); + case PARTITION_TYPE_MIXED: return translate(disk->partitionMixed(ratio)); + default: return error("Unknown type " + std::to_string(partitionType)); + } +} + +binder::Status VoldNativeService::forgetPartition(const std::string& partGuid) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->forgetPartition(partGuid)); +} + +binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId) { + ENFORCE_UID(AID_SYSTEM); + 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) { + VolumeManager::Instance()->setPrimary(vol); + } + return translate(res); +} + +binder::Status VoldNativeService::unmount(const std::string& volId) { + ENFORCE_UID(AID_SYSTEM); + 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); + ACQUIRE_LOCK; + + auto vol = VolumeManager::Instance()->findVolume(volId); + if (vol == nullptr) { + return error("Failed to find volume " + volId); + } + return translate(vol->format(fsType)); +} + +binder::Status VoldNativeService::benchmark(const std::string& volId, int64_t* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + *_aidl_return = VolumeManager::Instance()->benchmarkPrivate(volId); return ok(); } +binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, const std::string& toVolId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + auto fromVol = VolumeManager::Instance()->findVolume(fromVolId); + auto toVol = VolumeManager::Instance()->findVolume(toVolId); + if (fromVol == nullptr) { + return error("Failed to find volume " + fromVolId); + } else if (toVol == nullptr) { + return error("Failed to find volume " + toVolId); + } + (new android::vold::MoveTask(fromVol, toVol))->start(); + return ok(); +} + +binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + std::string tmp; + switch (remountMode) { + case REMOUNT_MODE_NONE: tmp = "none"; break; + case REMOUNT_MODE_DEFAULT: tmp = "default"; break; + case REMOUNT_MODE_READ: tmp = "read"; break; + case REMOUNT_MODE_WRITE: tmp = "write"; break; + default: return error("Unknown mode " + std::to_string(remountMode)); + } + return translate(VolumeManager::Instance()->remountUid(uid, tmp)); +} + +binder::Status VoldNativeService::mkdirs(const std::string& path) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->mkdirs(path.c_str())); +} + } // namespace vold } // namespace android diff --git a/VoldNativeService.h b/VoldNativeService.h index 1866059..d3bce67 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -31,6 +31,28 @@ public: virtual status_t dump(int fd, const Vector &args) override; binder::Status reset(); + binder::Status shutdown(); + + binder::Status setDebug(bool debug); + + binder::Status onUserAdded(int32_t userId, int32_t userSerial); + binder::Status onUserRemoved(int32_t userId); + binder::Status onUserStarted(int32_t userId); + binder::Status onUserStopped(int32_t userId); + + binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio); + binder::Status forgetPartition(const std::string& partGuid); + + binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId); + binder::Status unmount(const std::string& volId); + binder::Status format(const std::string& volId, const std::string& fsType); + binder::Status benchmark(const std::string& volId, int64_t* _aidl_return); + + binder::Status moveStorage(const std::string& fromVolId, const std::string& toVolId); + + binder::Status remountUid(int32_t uid, int32_t remountMode); + + binder::Status mkdirs(const std::string& path); }; } // namespace vold diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 13a943f..ddf06eb 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -1952,7 +1952,7 @@ bool VolumeManager::isMountpointMounted(const char *mp) return found_mp; } -int VolumeManager::mkdirs(char* path) { +int VolumeManager::mkdirs(const char* path) { // Only offer to create directories for paths managed by vold if (strncmp(path, "/storage/", 9) == 0) { // fs_mkdirs() does symlink checking and relative path enforcement diff --git a/VolumeManager.h b/VolumeManager.h index 537aebe..72c470a 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -196,7 +196,7 @@ 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 char* path); private: VolumeManager(); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 5f7a3fe..43d88bc 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -19,4 +19,54 @@ package android.os; /** {@hide} */ interface IVold { void reset(); + void shutdown(); + + void setDebug(boolean debug); + + void onUserAdded(int userId, int userSerial); + void onUserRemoved(int userId); + void onUserStarted(int userId); + void onUserStopped(int userId); + + void partition(@utf8InCpp String diskId, int partitionType, int ratio); + void forgetPartition(@utf8InCpp String partGuid); + + void mount(@utf8InCpp String volId, int mountFlags, int mountUserId); + void unmount(@utf8InCpp String volId); + void format(@utf8InCpp String volId, @utf8InCpp String fsType); + long benchmark(@utf8InCpp String volId); + + void moveStorage(@utf8InCpp String fromVolId, @utf8InCpp String toVolId); + + void remountUid(int uid, int remountMode); + + void mkdirs(@utf8InCpp String path); + + 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 REMOUNT_MODE_NONE = 0; + const int REMOUNT_MODE_DEFAULT = 1; + const int REMOUNT_MODE_READ = 2; + const int REMOUNT_MODE_WRITE = 3; + + const int STATE_UNMOUNTED = 0; + const int STATE_CHECKING = 1; + const int STATE_MOUNTED = 2; + const int STATE_MOUNTED_READ_ONLY = 3; + const int STATE_FORMATTING = 4; + const int STATE_EJECTING = 5; + const int STATE_UNMOUNTABLE = 6; + const int STATE_REMOVED = 7; + const int STATE_BAD_REMOVAL = 8; + + const int TYPE_PUBLIC = 0; + const int TYPE_PRIVATE = 1; + const int TYPE_EMULATED = 2; + const int TYPE_ASEC = 3; + const int TYPE_OBB = 4; } From f654c04d0148034ce23f44cc3d620eae3c769d60 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 8 Sep 2017 14:58:08 -0700 Subject: [PATCH 004/106] unnecessary in C++. Bug: N/A Test: builds Change-Id: Iddbd364e581477b8304dc6f0764f153dbcf122a7 --- EncryptInplace.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/EncryptInplace.cpp b/EncryptInplace.cpp index 9aa2a21..4ffb8cd 100644 --- a/EncryptInplace.cpp +++ b/EncryptInplace.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include #include From 11c2d380a786d9e304416be98881b90b74ff666d Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 11 Sep 2017 10:32:01 -0600 Subject: [PATCH 005/106] Move even more vold commands over to Binder. This moves fstrim, obb and appfuse commands over to the new Binder interface. This change also separates creating/destroying and mounting/unmounting of OBB volumes, which means they finally flow nicely into the modern VolumeInfo/VolumeBase design. We now generate unique identifiers for all OBB volumes, instead of using a shady MD5 hash. Change all "loop" and "dm" devices to tag the kernel resources with a vold-specific prefix so that we can clean them up if vold crashes; there are new destroyAll() methods that handle this cleanup. Move appfuse mounting/unmounting into VolumeManager so it can be shared. Move various model objects into a separate directory to tidy things up. Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest Bug: 13758960 Change-Id: I7294e32b3fb6efe07cb3b77bd20166e70b66958f --- Android.mk | 11 +- CommandListener.cpp | 214 ++-------------- Devmapper.cpp | 89 ++++++- Devmapper.h | 1 + Loop.cpp | 53 +++- Loop.h | 2 +- MoveTask.h | 2 +- VoldNativeService.cpp | 59 ++++- VoldNativeService.h | 14 +- VolumeManager.cpp | 235 +++++++++++++++++- VolumeManager.h | 17 +- binder/android/os/IVold.aidl | 15 +- main.cpp | 2 +- Disk.cpp => model/Disk.cpp | 0 Disk.h => model/Disk.h | 0 .../EmulatedVolume.cpp | 0 EmulatedVolume.h => model/EmulatedVolume.h | 0 model/ObbVolume.cpp | 130 ++++++++++ model/ObbVolume.h | 57 +++++ PrivateVolume.cpp => model/PrivateVolume.cpp | 0 PrivateVolume.h => model/PrivateVolume.h | 0 PublicVolume.cpp => model/PublicVolume.cpp | 0 PublicVolume.h => model/PublicVolume.h | 0 VolumeBase.cpp => model/VolumeBase.cpp | 0 VolumeBase.h => model/VolumeBase.h | 0 tests/Android.mk | 5 +- 26 files changed, 674 insertions(+), 232 deletions(-) rename Disk.cpp => model/Disk.cpp (100%) rename Disk.h => model/Disk.h (100%) rename EmulatedVolume.cpp => model/EmulatedVolume.cpp (100%) rename EmulatedVolume.h => model/EmulatedVolume.h (100%) create mode 100644 model/ObbVolume.cpp create mode 100644 model/ObbVolume.h rename PrivateVolume.cpp => model/PrivateVolume.cpp (100%) rename PrivateVolume.h => model/PrivateVolume.h (100%) rename PublicVolume.cpp => model/PublicVolume.cpp (100%) rename PublicVolume.h => model/PublicVolume.h (100%) rename VolumeBase.cpp => model/VolumeBase.cpp (100%) rename VolumeBase.h => model/VolumeBase.h (100%) diff --git a/Android.mk b/Android.mk index f6a8da9..7263a5b 100644 --- a/Android.mk +++ b/Android.mk @@ -18,11 +18,12 @@ common_src_files := \ Ext4Crypt.cpp \ VoldUtil.c \ cryptfs.cpp \ - Disk.cpp \ - VolumeBase.cpp \ - PublicVolume.cpp \ - PrivateVolume.cpp \ - EmulatedVolume.cpp \ + model/Disk.cpp \ + model/VolumeBase.cpp \ + model/PublicVolume.cpp \ + model/PrivateVolume.cpp \ + model/EmulatedVolume.cpp \ + model/ObbVolume.cpp \ Utils.cpp \ MoveTask.cpp \ Benchmark.cpp \ diff --git a/CommandListener.cpp b/CommandListener.cpp index 8da3f69..60c0898 100644 --- a/CommandListener.cpp +++ b/CommandListener.cpp @@ -44,7 +44,7 @@ #include "CommandListener.h" #include "VolumeManager.h" -#include "VolumeBase.h" +#include "model/VolumeBase.h" #include "ResponseCode.h" #include "Process.h" #include "Loop.h" @@ -53,7 +53,6 @@ #include "TrimTask.h" #define DUMP_ARGS 0 -#define DEBUG_APPFUSE 0 using android::base::unique_fd; @@ -617,157 +616,6 @@ int CommandListener::FstrimCmd::runCommand(SocketClient *cli, return sendGenericOkFail(cli, 0); } -static size_t kAppFuseMaxMountPointName = 32; - -static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) { - if (name.size() > kAppFuseMaxMountPointName) { - LOG(ERROR) << "AppFuse mount name is too long."; - return -EINVAL; - } - for (size_t i = 0; i < name.size(); i++) { - if (!isalnum(name[i])) { - LOG(ERROR) << "AppFuse mount name contains invalid character."; - return -EINVAL; - } - } - *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str()); - return android::OK; -} - -static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) { - // Remove existing mount. - android::vold::ForceUnmount(path); - - const auto opts = android::base::StringPrintf( - "fd=%i," - "rootmode=40000," - "default_permissions," - "allow_other," - "user_id=%d,group_id=%d," - "context=\"u:object_r:app_fuse_file:s0\"," - "fscontext=u:object_r:app_fusefs:s0", - device_fd, - uid, - uid); - - const int result = TEMP_FAILURE_RETRY(mount( - "/dev/fuse", path.c_str(), "fuse", - MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str())); - if (result != 0) { - PLOG(ERROR) << "Failed to mount " << path; - return -errno; - } - - return android::OK; -} - -static android::status_t runCommandInNamespace(const std::string& command, - uid_t uid, - pid_t pid, - const std::string& path, - int device_fd) { - if (DEBUG_APPFUSE) { - LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path - << " in namespace " << uid; - } - - unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC)); - if (dir.get() == -1) { - PLOG(ERROR) << "Failed to open /proc"; - return -errno; - } - - // Obtains process file descriptor. - const std::string pid_str = android::base::StringPrintf("%d", pid); - const unique_fd pid_fd( - openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); - if (pid_fd.get() == -1) { - PLOG(ERROR) << "Failed to open /proc/" << pid; - return -errno; - } - - // Check UID of process. - { - struct stat sb; - const int result = fstat(pid_fd.get(), &sb); - if (result == -1) { - PLOG(ERROR) << "Failed to stat /proc/" << pid; - return -errno; - } - if (sb.st_uid != AID_SYSTEM) { - LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM - << ", actual=" << sb.st_uid; - return -EPERM; - } - } - - // Matches so far, but refuse to touch if in root namespace - { - char rootName[PATH_MAX]; - char pidName[PATH_MAX]; - const int root_result = - android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX); - const int pid_result = - android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX); - if (root_result == -1) { - LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt"; - return -EPERM; - } - if (pid_result == -1) { - LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt"; - return -EPERM; - } - if (!strcmp(rootName, pidName)) { - LOG(ERROR) << "Don't mount appfuse in root namespace"; - return -EPERM; - } - } - - // We purposefully leave the namespace open across the fork - unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC - if (ns_fd.get() < 0) { - PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt"; - return -errno; - } - - int child = fork(); - if (child == 0) { - if (setns(ns_fd.get(), CLONE_NEWNS) != 0) { - PLOG(ERROR) << "Failed to setns"; - _exit(-errno); - } - - if (command == "mount") { - _exit(mountInNamespace(uid, device_fd, path)); - } else if (command == "unmount") { - // If it's just after all FD opened on mount point are closed, umount2 can fail with - // EBUSY. To avoid the case, specify MNT_DETACH. - if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 && - errno != EINVAL && errno != ENOENT) { - PLOG(ERROR) << "Failed to unmount directory."; - _exit(-errno); - } - if (rmdir(path.c_str()) != 0) { - PLOG(ERROR) << "Failed to remove the mount directory."; - _exit(-errno); - } - _exit(android::OK); - } else { - LOG(ERROR) << "Unknown appfuse command " << command; - _exit(-EPERM); - } - } - - if (child == -1) { - PLOG(ERROR) << "Failed to folk child process"; - return -errno; - } - - android::status_t status; - TEMP_FAILURE_RETRY(waitpid(child, &status, 0)); - - return status; -} CommandListener::AppFuseCmd::AppFuseCmd() : VoldCommand("appfuse") {} @@ -777,66 +625,32 @@ int CommandListener::AppFuseCmd::runCommand(SocketClient *cli, int argc, char ** return 0; } - const std::string command(argv[1]); + VolumeManager *vm = VolumeManager::Instance(); + std::lock_guard lock(vm->getLock()); + const std::string command(argv[1]); if (command == "mount" && argc == 5) { const uid_t uid = atoi(argv[2]); const pid_t pid = atoi(argv[3]); - const std::string name(argv[4]); + const int mountId = atoi(argv[4]); - // Check mount point name. - std::string path; - if (getMountPath(uid, name, &path) != android::OK) { - return cli->sendMsg(ResponseCode::CommandParameterError, - "Invalid mount point name.", - false); + unique_fd device_fd; + int result = vm->mountAppFuse(uid, pid, mountId, &device_fd); + if (result != 0) { + return sendGenericOkFail(cli, result); + } else { + return sendFd(cli, device_fd.get()); } - - // Create directories. - { - const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0); - if (result != android::OK) { - PLOG(ERROR) << "Failed to prepare directory " << path; - return sendGenericOkFail(cli, result); - } - } - - // Open device FD. - unique_fd device_fd(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC - if (device_fd.get() == -1) { - PLOG(ERROR) << "Failed to open /dev/fuse"; - return sendGenericOkFail(cli, -errno); - } - - // Mount. - { - const android::status_t result = - runCommandInNamespace(command, uid, pid, path, device_fd.get()); - if (result != android::OK) { - return sendGenericOkFail(cli, result); - } - } - - return sendFd(cli, device_fd.get()); } else if (command == "unmount" && argc == 5) { const uid_t uid = atoi(argv[2]); const uid_t pid = atoi(argv[3]); - const std::string name(argv[4]); + const int mountId = atoi(argv[4]); - // Check mount point name. - std::string path; - if (getMountPath(uid, name, &path) != android::OK) { - return cli->sendMsg(ResponseCode::CommandParameterError, - "Invalid mount point name.", - false); - } - - const android::status_t result = - runCommandInNamespace(command, uid, pid, path, -1 /* device_fd */); + int result = vm->unmountAppFuse(uid, pid, mountId); return sendGenericOkFail(cli, result); } - return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false); + return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false); } android::status_t CommandListener::AppFuseCmd::sendFd(SocketClient *cli, int fd) { diff --git a/Devmapper.cpp b/Devmapper.cpp index 4b6942d..c945e9f 100644 --- a/Devmapper.cpp +++ b/Devmapper.cpp @@ -32,12 +32,18 @@ #include +#include +#include #include #include "Devmapper.h" #define DEVMAPPER_BUFFER_SIZE 4096 +using android::base::StringPrintf; + +static const char* kVoldPrefix = "vold:"; + int Devmapper::dumpState(SocketClient *c) { char *buffer = (char *) malloc(1024 * 64); @@ -130,7 +136,10 @@ void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize, } } -int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) { +int Devmapper::lookupActive(const char *name_raw, char *ubuffer, size_t len) { + auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw); + const char* name = name_string.c_str(); + char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE); if (!buffer) { SLOGE("Error allocating memory (%s)", strerror(errno)); @@ -163,8 +172,11 @@ int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) { return 0; } -int Devmapper::create(const char *name, const char *loopFile, const char *key, +int Devmapper::create(const char *name_raw, const char *loopFile, const char *key, unsigned long numSectors, char *ubuffer, size_t len) { + auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw); + const char* name = name_string.c_str(); + char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE); if (!buffer) { SLOGE("Error allocating memory (%s)", strerror(errno)); @@ -261,7 +273,10 @@ 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)); @@ -294,6 +309,74 @@ int Devmapper::destroy(const char *name) { return 0; } +int Devmapper::destroyAll() { + char *buffer = (char *) malloc(1024 * 64); + if (!buffer) { + SLOGE("Error allocating memory (%s)", strerror(errno)); + return -1; + } + memset(buffer, 0, (1024 * 64)); + + char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE); + if (!buffer2) { + SLOGE("Error allocating memory (%s)", strerror(errno)); + free(buffer); + return -1; + } + + int fd; + if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) { + SLOGE("Error opening devmapper (%s)", strerror(errno)); + free(buffer); + free(buffer2); + return -1; + } + + struct dm_ioctl *io = (struct dm_ioctl *) buffer; + ioctlInit(io, (1024 * 64), NULL, 0); + + if (ioctl(fd, DM_LIST_DEVICES, io)) { + SLOGE("DM_LIST_DEVICES ioctl failed (%s)", strerror(errno)); + free(buffer); + free(buffer2); + close(fd); + return -1; + } + + struct dm_name_list *n = (struct dm_name_list *) (((char *) buffer) + io->data_start); + if (!n->dev) { + free(buffer); + free(buffer2); + close(fd); + return 0; + } + + unsigned nxt = 0; + do { + n = (struct dm_name_list *) (((char *) n) + nxt); + if (strncmp(n->name, kVoldPrefix, strlen(kVoldPrefix)) == 0) { + LOG(DEBUG) << "Tearing down stale dm device named " << n->name; + + memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE); + struct dm_ioctl *io2 = (struct dm_ioctl *) buffer2; + ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0); + if (ioctl(fd, DM_DEV_REMOVE, io2)) { + if (errno != ENXIO) { + PLOG(WARNING) << "Failed to destroy dm device named " << n->name; + } + } + } else { + LOG(VERBOSE) << "Found unmanaged dm device named " << n->name; + } + nxt = n->next; + } while (nxt); + + free(buffer); + free(buffer2); + close(fd); + return 0; +} + void *Devmapper::_align(void *ptr, unsigned int a) { unsigned long agn = --a; diff --git a/Devmapper.h b/Devmapper.h index 5b65b53..dcc39d8 100644 --- a/Devmapper.h +++ b/Devmapper.h @@ -27,6 +27,7 @@ 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 destroyAll(); static int lookupActive(const char *name, char *buffer, size_t len); static int dumpState(SocketClient *c); diff --git a/Loop.cpp b/Loop.cpp index 6ec5e6d..325b0d3 100644 --- a/Loop.cpp +++ b/Loop.cpp @@ -45,6 +45,8 @@ using android::base::StringPrintf; using android::base::unique_fd; +static const char* kVoldPrefix = "vold:"; + int Loop::dumpState(SocketClient *c) { int i; int fd; @@ -87,7 +89,10 @@ int Loop::dumpState(SocketClient *c) { return 0; } -int Loop::lookupActive(const char *id, char *buffer, size_t len) { +int Loop::lookupActive(const char *id_raw, char *buffer, size_t len) { + auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw); + const char* id = id_string.c_str(); + int i; int fd; char filename[256]; @@ -134,7 +139,10 @@ int Loop::lookupActive(const char *id, char *buffer, size_t len) { return 0; } -int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len) { +int Loop::create(const char *id_raw, const char *loopFile, char *loopDeviceBuffer, size_t len) { + auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw); + const char* id = id_string.c_str(); + int i; int fd; char filename[256]; @@ -267,6 +275,14 @@ 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; } @@ -289,9 +305,36 @@ int Loop::destroyByDevice(const char *loopDevice) { return 0; } -int Loop::destroyByFile(const char * /*loopFile*/) { - errno = ENOSYS; - return -1; +int Loop::destroyAll() { + for (int i = 0; i < LOOP_MAX; i++) { + auto path = StringPrintf("/dev/block/loop%d", i); + + unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC)); + if (fd.get() == -1) { + if (errno != ENOENT) { + PLOG(WARNING) << "Failed to open " << path; + } + continue; + } + + struct loop_info64 li; + if (ioctl(fd.get(), LOOP_GET_STATUS64, &li) < 0) { + PLOG(WARNING) << "Failed to LOOP_GET_STATUS64 " << path; + continue; + } + + char* id = (char*) li.lo_crypt_name; + if (strncmp(id, kVoldPrefix, strlen(kVoldPrefix)) == 0) { + LOG(DEBUG) << "Tearing down stale loop device at " << path << " named " << id; + + if (ioctl(fd.get(), LOOP_CLR_FD, 0) < 0) { + PLOG(WARNING) << "Failed to LOOP_CLR_FD " << path; + } + } else { + LOG(VERBOSE) << "Found unmanaged loop device at " << path << " named " << id; + } + } + return 0; } int Loop::createImageFile(const char *file, unsigned long numSectors) { diff --git a/Loop.h b/Loop.h index 5d8f427..e3ad239 100644 --- a/Loop.h +++ b/Loop.h @@ -32,7 +32,7 @@ public: static int create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len); static int create(const std::string& file, std::string& out_device); static int destroyByDevice(const char *loopDevice); - static int destroyByFile(const char *loopFile); + static int destroyAll(); static int createImageFile(const char *file, unsigned long numSectors); static int resizeImageFile(const char *file, unsigned long numSectors); diff --git a/MoveTask.h b/MoveTask.h index b1777c0..cb184c3 100644 --- a/MoveTask.h +++ b/MoveTask.h @@ -18,7 +18,7 @@ #define ANDROID_VOLD_MOVE_TASK_H #include "Utils.h" -#include "VolumeBase.h" +#include "model/VolumeBase.h" #include diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index f98c15d..3585e96 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -17,12 +17,14 @@ #include "VoldNativeService.h" #include "VolumeManager.h" #include "MoveTask.h" +#include "TrimTask.h" #include #include #include #include +#include #include #ifndef LOG_TAG @@ -56,7 +58,7 @@ static binder::Status translate(uint32_t status) { if (status == 0) { return binder::Status::ok(); } else { - return binder::Status::fromExceptionCode(status); + return binder::Status::fromServiceSpecificError(status); } } @@ -134,11 +136,14 @@ binder::Status VoldNativeService::shutdown() { return translate(VolumeManager::Instance()->shutdown()); } -binder::Status VoldNativeService::setDebug(bool debug) { +binder::Status VoldNativeService::mountAll() { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; - return translate(VolumeManager::Instance()->setDebug(debug)); + struct fstab* fstab = fs_mgr_read_fstab_default(); + int res = fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT); + fs_mgr_free_fstab(fstab); + return translate(res); } binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) { @@ -169,7 +174,8 @@ binder::Status VoldNativeService::onUserStopped(int32_t userId) { return translate(VolumeManager::Instance()->onUserStopped(userId)); } -binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType, int32_t ratio) { +binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType, + int32_t ratio) { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; @@ -192,7 +198,8 @@ binder::Status VoldNativeService::forgetPartition(const std::string& partGuid) { return translate(VolumeManager::Instance()->forgetPartition(partGuid)); } -binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId) { +binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, + int32_t mountUserId) { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; @@ -241,7 +248,8 @@ binder::Status VoldNativeService::benchmark(const std::string& volId, int64_t* _ return ok(); } -binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, const std::string& toVolId) { +binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, + const std::string& toVolId) { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; @@ -278,5 +286,44 @@ binder::Status VoldNativeService::mkdirs(const std::string& path) { return translate(VolumeManager::Instance()->mkdirs(path.c_str())); } +binder::Status VoldNativeService::createObb(const std::string& sourcePath, + const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate( + VolumeManager::Instance()->createObb(sourcePath, sourceKey, ownerGid, _aidl_return)); +} + +binder::Status VoldNativeService::destroyObb(const std::string& volId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->destroyObb(volId)); +} + +binder::Status VoldNativeService::fstrim(int32_t fstrimFlags) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + (new android::vold::TrimTask(fstrimFlags))->start(); + return ok(); +} + +binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t pid, int32_t mountId, + android::base::unique_fd* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->mountAppFuse(uid, pid, mountId, _aidl_return)); +} + +binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->unmountAppFuse(uid, pid, mountId)); +} + } // namespace vold } // namespace android diff --git a/VoldNativeService.h b/VoldNativeService.h index d3bce67..f412bfc 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -17,6 +17,7 @@ #ifndef _VOLD_NATIVE_SERVICE_H_ #define _VOLD_NATIVE_SERVICE_H_ +#include #include #include "android/os/BnVold.h" @@ -32,8 +33,7 @@ public: binder::Status reset(); binder::Status shutdown(); - - binder::Status setDebug(bool debug); + binder::Status mountAll(); binder::Status onUserAdded(int32_t userId, int32_t userSerial); binder::Status onUserRemoved(int32_t userId); @@ -53,6 +53,16 @@ public: binder::Status remountUid(int32_t uid, int32_t remountMode); binder::Status mkdirs(const std::string& path); + + binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey, + int32_t ownerGid, std::string* _aidl_return); + binder::Status destroyObb(const std::string& volId); + + binder::Status fstrim(int32_t fstrimFlags); + + binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId, + android::base::unique_fd* _aidl_return); + binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId); }; } // namespace vold diff --git a/VolumeManager.cpp b/VolumeManager.cpp index ddf06eb..022caff 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -48,7 +48,8 @@ #include #include "Benchmark.h" -#include "EmulatedVolume.h" +#include "model/EmulatedVolume.h" +#include "model/ObbVolume.h" #include "VolumeManager.h" #include "NetlinkManager.h" #include "ResponseCode.h" @@ -68,6 +69,7 @@ + ((number) & (~((1U << (po2)) - 1)))) using android::base::StringPrintf; +using android::base::unique_fd; /* * Path to external storage where *only* root can access ASEC image files @@ -220,6 +222,7 @@ VolumeManager::VolumeManager() { mSavedDirtyRatio = -1; // set dirty ratio to 0 when UMS is active mUmsDirtyRatio = 0; + mNextObbId = 0; } VolumeManager::~VolumeManager() { @@ -317,6 +320,9 @@ int VolumeManager::start() { // directories that we own, in case we crashed. unmountAll(); + Devmapper::destroyAll(); + Loop::destroyAll(); + // Assume that we always have an emulated volume on internal // storage; the framework will decide if it should be mounted. CHECK(mInternalEmulated == nullptr); @@ -437,6 +443,11 @@ std::shared_ptr VolumeManager::findVolume(const std:: return vol; } } + for (const auto& vol : mObbVolumes) { + if (vol->getId() == id) { + return vol; + } + } return nullptr; } @@ -754,7 +765,7 @@ int VolumeManager::unmountAll() { endmntent(fp); for (const auto& path : toUnmount) { - SLOGW("Tearing down stale mount %s", path.c_str()); + LOG(DEBUG) << "Tearing down stale mount " << path; android::vold::ForceUnmount(path); } @@ -1962,3 +1973,223 @@ int VolumeManager::mkdirs(const char* path) { return -EINVAL; } } + +static size_t kAppFuseMaxMountPointName = 32; + +static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) { + if (name.size() > kAppFuseMaxMountPointName) { + LOG(ERROR) << "AppFuse mount name is too long."; + return -EINVAL; + } + for (size_t i = 0; i < name.size(); i++) { + if (!isalnum(name[i])) { + LOG(ERROR) << "AppFuse mount name contains invalid character."; + return -EINVAL; + } + } + *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str()); + return android::OK; +} + +static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) { + // Remove existing mount. + android::vold::ForceUnmount(path); + + const auto opts = android::base::StringPrintf( + "fd=%i," + "rootmode=40000," + "default_permissions," + "allow_other," + "user_id=%d,group_id=%d," + "context=\"u:object_r:app_fuse_file:s0\"," + "fscontext=u:object_r:app_fusefs:s0", + device_fd, + uid, + uid); + + const int result = TEMP_FAILURE_RETRY(mount( + "/dev/fuse", path.c_str(), "fuse", + MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str())); + if (result != 0) { + PLOG(ERROR) << "Failed to mount " << path; + return -errno; + } + + return android::OK; +} + +static android::status_t runCommandInNamespace(const std::string& command, + uid_t uid, + pid_t pid, + const std::string& path, + int device_fd) { + if (DEBUG_APPFUSE) { + LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path + << " in namespace " << uid; + } + + unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + if (dir.get() == -1) { + PLOG(ERROR) << "Failed to open /proc"; + return -errno; + } + + // Obtains process file descriptor. + const std::string pid_str = android::base::StringPrintf("%d", pid); + const unique_fd pid_fd( + openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + if (pid_fd.get() == -1) { + PLOG(ERROR) << "Failed to open /proc/" << pid; + return -errno; + } + + // Check UID of process. + { + struct stat sb; + const int result = fstat(pid_fd.get(), &sb); + if (result == -1) { + PLOG(ERROR) << "Failed to stat /proc/" << pid; + return -errno; + } + if (sb.st_uid != AID_SYSTEM) { + LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM + << ", actual=" << sb.st_uid; + return -EPERM; + } + } + + // Matches so far, but refuse to touch if in root namespace + { + char rootName[PATH_MAX]; + char pidName[PATH_MAX]; + const int root_result = + android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX); + const int pid_result = + android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX); + if (root_result == -1) { + LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt"; + return -EPERM; + } + if (pid_result == -1) { + LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt"; + return -EPERM; + } + if (!strcmp(rootName, pidName)) { + LOG(ERROR) << "Don't mount appfuse in root namespace"; + return -EPERM; + } + } + + // We purposefully leave the namespace open across the fork + unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC + if (ns_fd.get() < 0) { + PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt"; + return -errno; + } + + int child = fork(); + if (child == 0) { + if (setns(ns_fd.get(), CLONE_NEWNS) != 0) { + PLOG(ERROR) << "Failed to setns"; + _exit(-errno); + } + + if (command == "mount") { + _exit(mountInNamespace(uid, device_fd, path)); + } else if (command == "unmount") { + // If it's just after all FD opened on mount point are closed, umount2 can fail with + // EBUSY. To avoid the case, specify MNT_DETACH. + if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 && + errno != EINVAL && errno != ENOENT) { + PLOG(ERROR) << "Failed to unmount directory."; + _exit(-errno); + } + if (rmdir(path.c_str()) != 0) { + PLOG(ERROR) << "Failed to remove the mount directory."; + _exit(-errno); + } + _exit(android::OK); + } else { + LOG(ERROR) << "Unknown appfuse command " << command; + _exit(-EPERM); + } + } + + if (child == -1) { + PLOG(ERROR) << "Failed to folk child process"; + return -errno; + } + + android::status_t status; + TEMP_FAILURE_RETRY(waitpid(child, &status, 0)); + + return status; +} + +int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey, + int32_t ownerGid, std::string* outVolId) { + int id = mNextObbId++; + + auto vol = std::shared_ptr( + new android::vold::ObbVolume(id, sourcePath, sourceKey, ownerGid)); + vol->create(); + + mObbVolumes.push_back(vol); + *outVolId = vol->getId(); + return android::OK; +} + +int VolumeManager::destroyObb(const std::string& volId) { + auto i = mObbVolumes.begin(); + while (i != mObbVolumes.end()) { + if ((*i)->getId() == volId) { + (*i)->destroy(); + i = mObbVolumes.erase(i); + } else { + ++i; + } + } + return android::OK; +} + +int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId, + android::base::unique_fd* device_fd) { + std::string name = std::to_string(mountId); + + // Check mount point name. + std::string path; + if (getMountPath(uid, name, &path) != android::OK) { + LOG(ERROR) << "Invalid mount point name"; + return -1; + } + + // Create directories. + const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory " << path; + return -1; + } + + // Open device FD. + device_fd->reset(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC + if (device_fd->get() == -1) { + PLOG(ERROR) << "Failed to open /dev/fuse"; + return -1; + } + + // Mount. + return runCommandInNamespace("mount", uid, pid, path, device_fd->get()); +} + +int VolumeManager::unmountAppFuse(uid_t uid, pid_t pid, int mountId) { + std::string name = std::to_string(mountId); + + // Check mount point name. + std::string path; + if (getMountPath(uid, name, &path) != android::OK) { + LOG(ERROR) << "Invalid mount point name"; + return -1; + } + + return runCommandInNamespace("unmount", uid, pid, path, -1 /* device_fd */); +} diff --git a/VolumeManager.h b/VolumeManager.h index 72c470a..097ce6a 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -29,18 +29,21 @@ #include #include +#include #include #include #include #include #include -#include "Disk.h" -#include "VolumeBase.h" +#include "model/Disk.h" +#include "model/VolumeBase.h" /* The length of an MD5 hash when encoded into ASCII hex characters */ #define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1) +#define DEBUG_APPFUSE 0 + typedef enum { ASEC, OBB } container_type_t; class ContainerData { @@ -198,6 +201,13 @@ public: */ int mkdirs(const char* path); + int createObb(const std::string& path, const std::string& key, int32_t ownerGid, + std::string* outVolId); + int destroyObb(const std::string& volId); + + int mountAppFuse(uid_t uid, pid_t pid, int mountId, android::base::unique_fd* device_fd); + int unmountAppFuse(uid_t uid, pid_t pid, int mountId); + private: VolumeManager(); void readInitialState(); @@ -211,6 +221,7 @@ private: std::list> mDiskSources; std::list> mDisks; + std::list> mObbVolumes; std::unordered_map mAddedUsers; std::unordered_set mStartedUsers; @@ -219,6 +230,8 @@ private: std::shared_ptr mVirtualDisk; std::shared_ptr mInternalEmulated; std::shared_ptr mPrimary; + + int mNextObbId; }; extern "C" { diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 43d88bc..d945357 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -20,8 +20,7 @@ package android.os; interface IVold { void reset(); void shutdown(); - - void setDebug(boolean debug); + void mountAll(); void onUserAdded(int userId, int userSerial); void onUserRemoved(int userId); @@ -42,6 +41,18 @@ interface IVold { void mkdirs(@utf8InCpp String path); + @utf8InCpp String createObb(@utf8InCpp String sourcePath, + @utf8InCpp String sourceKey, int ownerGid); + void destroyObb(@utf8InCpp String volId); + + void fstrim(int fstrimFlags); + + FileDescriptor mountAppFuse(int uid, int pid, int mountId); + void unmountAppFuse(int uid, int pid, int mountId); + + const int FSTRIM_FLAG_DEEP_TRIM = 1; + const int FSTRIM_FLAG_BENCHMARK_AFTER = 2; + const int MOUNT_FLAG_PRIMARY = 1; const int MOUNT_FLAG_VISIBLE = 2; diff --git a/main.cpp b/main.cpp index ec240ef..8175dc5 100644 --- a/main.cpp +++ b/main.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Disk.h" +#include "model/Disk.h" #include "VolumeManager.h" #include "CommandListener.h" #include "CryptCommandListener.h" diff --git a/Disk.cpp b/model/Disk.cpp similarity index 100% rename from Disk.cpp rename to model/Disk.cpp diff --git a/Disk.h b/model/Disk.h similarity index 100% rename from Disk.h rename to model/Disk.h diff --git a/EmulatedVolume.cpp b/model/EmulatedVolume.cpp similarity index 100% rename from EmulatedVolume.cpp rename to model/EmulatedVolume.cpp diff --git a/EmulatedVolume.h b/model/EmulatedVolume.h similarity index 100% rename from EmulatedVolume.h rename to model/EmulatedVolume.h diff --git a/model/ObbVolume.cpp b/model/ObbVolume.cpp new file mode 100644 index 0000000..709c7a3 --- /dev/null +++ b/model/ObbVolume.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs/Vfat.h" +#include "Devmapper.h" +#include "Loop.h" +#include "ObbVolume.h" +#include "Utils.h" +#include "VoldUtil.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using android::base::StringPrintf; +using android::base::unique_fd; + +namespace android { +namespace vold { + +ObbVolume::ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey, + gid_t ownerGid) : VolumeBase(Type::kObb) { + setId(StringPrintf("obb:%d", id)); + mSourcePath = sourcePath; + mSourceKey = sourceKey; + mOwnerGid = ownerGid; +} + +ObbVolume::~ObbVolume() { +} + +status_t ObbVolume::doCreate() { + if (Loop::create(mSourcePath, mLoopPath)) { + PLOG(ERROR) << getId() << " failed to create loop"; + return -1; + } + + if (!mSourceKey.empty()) { + unsigned long nr_sec = 0; + { + unique_fd loop_fd(open(mLoopPath.c_str(), O_RDWR | O_CLOEXEC)); + if (loop_fd.get() == -1) { + PLOG(ERROR) << getId() << " failed to open loop"; + return -1; + } + + get_blkdev_size(loop_fd.get(), &nr_sec); + if (nr_sec == 0) { + PLOG(ERROR) << getId() << " failed to get loop size"; + return -1; + } + } + + char tmp[PATH_MAX]; + if (Devmapper::create(getId().c_str(), mLoopPath.c_str(), mSourceKey.c_str(), nr_sec, + tmp, PATH_MAX)) { + PLOG(ERROR) << getId() << " failed to create dm"; + return -1; + } + mDmPath = tmp; + mMountPath = mDmPath; + } else { + mMountPath = mLoopPath; + } + return OK; +} + +status_t ObbVolume::doDestroy() { + if (!mDmPath.empty() && Devmapper::destroy(getId().c_str())) { + PLOG(WARNING) << getId() << " failed to destroy dm"; + } + if (!mLoopPath.empty() && Loop::destroyByDevice(mLoopPath.c_str())) { + PLOG(WARNING) << getId() << " failed to destroy loop"; + } + mDmPath.clear(); + mLoopPath.clear(); + return OK; +} + +status_t ObbVolume::doMount() { + auto path = StringPrintf("/mnt/obb/%s", getId().c_str()); + setPath(path); + + if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT)) { + PLOG(ERROR) << getId() << " failed to create mount point"; + return -1; + } + if (android::vold::vfat::Mount(mMountPath, path, + true, false, true, 0, mOwnerGid, 0227, false)) { + PLOG(ERROR) << getId() << " failed to mount"; + return -1; + } + return OK; +} + +status_t ObbVolume::doUnmount() { + auto path = getPath(); + + KillProcessesUsingPath(path); + ForceUnmount(path); + rmdir(path.c_str()); + + return OK; +} + +} // namespace vold +} // namespace android diff --git a/model/ObbVolume.h b/model/ObbVolume.h new file mode 100644 index 0000000..5ec0cde --- /dev/null +++ b/model/ObbVolume.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_VOLD_OBB_VOLUME_H +#define ANDROID_VOLD_OBB_VOLUME_H + +#include "VolumeBase.h" + +#include + +namespace android { +namespace vold { + +/* + * OBB container. + */ +class ObbVolume : public VolumeBase { +public: + ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey, + gid_t ownerGid); + virtual ~ObbVolume(); + +protected: + status_t doCreate() override; + status_t doDestroy() override; + status_t doMount() override; + status_t doUnmount() override; + +private: + std::string mSourcePath; + std::string mSourceKey; + gid_t mOwnerGid; + + std::string mLoopPath; + std::string mDmPath; + std::string mMountPath; + + DISALLOW_COPY_AND_ASSIGN(ObbVolume); +}; + +} // namespace vold +} // namespace android + +#endif diff --git a/PrivateVolume.cpp b/model/PrivateVolume.cpp similarity index 100% rename from PrivateVolume.cpp rename to model/PrivateVolume.cpp diff --git a/PrivateVolume.h b/model/PrivateVolume.h similarity index 100% rename from PrivateVolume.h rename to model/PrivateVolume.h diff --git a/PublicVolume.cpp b/model/PublicVolume.cpp similarity index 100% rename from PublicVolume.cpp rename to model/PublicVolume.cpp diff --git a/PublicVolume.h b/model/PublicVolume.h similarity index 100% rename from PublicVolume.h rename to model/PublicVolume.h diff --git a/VolumeBase.cpp b/model/VolumeBase.cpp similarity index 100% rename from VolumeBase.cpp rename to model/VolumeBase.cpp diff --git a/VolumeBase.h b/model/VolumeBase.h similarity index 100% rename from VolumeBase.h rename to model/VolumeBase.h diff --git a/tests/Android.mk b/tests/Android.mk index 4b6573e..9cebd1a 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -5,9 +5,10 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_C_INCLUDES := \ - system/core/fs_mgr/include + system/core/fs_mgr/include \ + system/vold/ -LOCAL_STATIC_LIBRARIES := libselinux libvold liblog libcrypto +LOCAL_STATIC_LIBRARIES := libbase libselinux libvold liblog libcrypto LOCAL_SRC_FILES := VolumeManager_test.cpp LOCAL_MODULE := vold_tests From ec4fda24593e758029504e1be4bba4cbc6668160 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 12 Sep 2017 13:19:24 -0600 Subject: [PATCH 006/106] Add some Binder argument sanity checking. Yell if the remote caller is trying to pass shady arguments. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest Bug: 13758960 Change-Id: I925dc9290a72fb4389574cd505fc4edfc8fbf0e1 --- VoldNativeService.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 3585e96..7cf45d9 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -85,6 +85,47 @@ binder::Status checkUid(uid_t expectedUid) { } } +binder::Status checkArgumentId(const std::string& id) { + if (id.empty()) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing ID"); + } + for (const char& c : id) { + if (!std::isalnum(c) && c != ':' && c != ',') { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("ID %s is malformed", id.c_str())); + } + } + return ok(); +} + +binder::Status checkArgumentPath(const std::string& path) { + if (path.empty()) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing path"); + } + if (path[0] != '/') { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Path %s is relative", path.c_str())); + } + for (const char& c : path) { + if (c == '\0' || c == '\n') { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Path %s is malformed", path.c_str())); + } + } + return ok(); +} + +binder::Status checkArgumentHex(const std::string& hex) { + // Empty hex strings are allowed + for (const char& c : hex) { + if (!std::isxdigit(c) && c != ':' && c != '-') { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Hex %s is malformed", hex.c_str())); + } + } + return ok(); +} + #define ENFORCE_UID(uid) { \ binder::Status status = checkUid((uid)); \ if (!status.isOk()) { \ @@ -92,6 +133,27 @@ binder::Status checkUid(uid_t expectedUid) { } \ } +#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 lock(VolumeManager::Instance()->getLock()); } // namespace @@ -177,6 +239,7 @@ binder::Status VoldNativeService::onUserStopped(int32_t userId) { binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType, int32_t ratio) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_ID(diskId); ACQUIRE_LOCK; auto disk = VolumeManager::Instance()->findDisk(diskId); @@ -193,6 +256,7 @@ binder::Status VoldNativeService::partition(const std::string& diskId, int32_t p binder::Status VoldNativeService::forgetPartition(const std::string& partGuid) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_HEX(partGuid); ACQUIRE_LOCK; return translate(VolumeManager::Instance()->forgetPartition(partGuid)); @@ -201,6 +265,7 @@ binder::Status VoldNativeService::forgetPartition(const std::string& partGuid) { binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; auto vol = VolumeManager::Instance()->findVolume(volId); @@ -220,6 +285,7 @@ binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountF binder::Status VoldNativeService::unmount(const std::string& volId) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; auto vol = VolumeManager::Instance()->findVolume(volId); @@ -231,6 +297,7 @@ binder::Status VoldNativeService::unmount(const std::string& volId) { 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); @@ -242,6 +309,7 @@ binder::Status VoldNativeService::format(const std::string& volId, const std::st binder::Status VoldNativeService::benchmark(const std::string& volId, int64_t* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; *_aidl_return = VolumeManager::Instance()->benchmarkPrivate(volId); @@ -251,6 +319,8 @@ binder::Status VoldNativeService::benchmark(const std::string& volId, int64_t* _ binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, const std::string& toVolId) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_ID(fromVolId); + CHECK_ARGUMENT_ID(toVolId); ACQUIRE_LOCK; auto fromVol = VolumeManager::Instance()->findVolume(fromVolId); @@ -281,6 +351,7 @@ binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) { binder::Status VoldNativeService::mkdirs(const std::string& path) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(path); ACQUIRE_LOCK; return translate(VolumeManager::Instance()->mkdirs(path.c_str())); @@ -289,6 +360,8 @@ binder::Status VoldNativeService::mkdirs(const std::string& 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( @@ -297,6 +370,7 @@ binder::Status VoldNativeService::createObb(const std::string& sourcePath, binder::Status VoldNativeService::destroyObb(const std::string& volId) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; return translate(VolumeManager::Instance()->destroyObb(volId)); From 83b559ced41c1be0d7a65ba99e179efd79d8d257 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 12 Sep 2017 16:30:52 -0600 Subject: [PATCH 007/106] Move all crypto commands over to Binder. Prefix FDE related commands with "fde" to make it clear which devices they apply to. This will also make it easier to remove once FDE is fully deprecated in a future release. To emulate the single-threaded nature of the old socket, introduce a lock that is acquired for all encryption related methods. Sprinkle some "const" around older files to make C++ happy. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.DirectBootHostTest Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest Bug: 13758960 Change-Id: I0a6ec6e3660bbddc61424c344ff6ac6da953ccf0 --- Android.mk | 9 +- VoldNativeService.cpp | 271 ++++++++++++++++++++++++++++++++++- VoldNativeService.h | 38 +++++ VolumeManager.h | 2 + binder/android/os/IVold.aidl | 51 +++++++ cryptfs.cpp | 8 +- cryptfs.h | 6 +- 7 files changed, 371 insertions(+), 14 deletions(-) diff --git a/Android.mk b/Android.mk index 7263a5b..49d58c2 100644 --- a/Android.mk +++ b/Android.mk @@ -80,6 +80,7 @@ common_static_libraries := \ # TODO: include "cert-err34-c" once we move to Binder # TODO: include "cert-err58-cpp" once 36656327 is fixed +common_local_tidy_enabled := true common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-* common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err34-c,-cert-err58-cpp @@ -96,7 +97,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := libvold LOCAL_CLANG := true -LOCAL_TIDY := true +LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES := $(common_src_files) @@ -115,7 +116,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := vold LOCAL_CLANG := true -LOCAL_TIDY := true +LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES := \ @@ -140,7 +141,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CLANG := true -LOCAL_TIDY := true +LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES := vdc.cpp @@ -156,7 +157,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CLANG := true -LOCAL_TIDY := true +LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES:= \ diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 7cf45d9..374cb4c 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -17,8 +17,13 @@ #include "VoldNativeService.h" #include "VolumeManager.h" #include "MoveTask.h" +#include "Process.h" #include "TrimTask.h" +#include "cryptfs.h" +#include "Ext4Crypt.h" +#include "MetadataCrypt.h" + #include #include @@ -54,7 +59,7 @@ static binder::Status error(const std::string& msg) { return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str())); } -static binder::Status translate(uint32_t status) { +static binder::Status translate(int status) { if (status == 0) { return binder::Status::ok(); } else { @@ -62,6 +67,14 @@ static binder::Status translate(uint32_t 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; @@ -154,7 +167,11 @@ binder::Status checkArgumentHex(const std::string& hex) { } \ } -#define ACQUIRE_LOCK std::lock_guard lock(VolumeManager::Instance()->getLock()); +#define ACQUIRE_LOCK \ + std::lock_guard lock(VolumeManager::Instance()->getLock()); + +#define ACQUIRE_CRYPT_LOCK \ + std::lock_guard lock(VolumeManager::Instance()->getCryptLock()); } // namespace @@ -277,7 +294,7 @@ binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountF vol->setMountUserId(mountUserId); int res = vol->mount(); - if (mountFlags & MOUNT_FLAG_PRIMARY) { + if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) { VolumeManager::Instance()->setPrimary(vol); } return translate(res); @@ -399,5 +416,253 @@ binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t pid, int32 return translate(VolumeManager::Instance()->unmountAppFuse(uid, pid, mountId)); } +binder::Status VoldNativeService::fdeCheckPassword(const std::string& password) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translate(cryptfs_check_passwd(password.c_str())); +} + +binder::Status VoldNativeService::fdeRestart() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + // Spawn as thread so init can issue commands back to vold without + // causing deadlock, usually as a result of prep_data_fs. + std::thread(&cryptfs_restart).detach(); + return ok(); +} + +binder::Status VoldNativeService::fdeComplete(int32_t* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + *_aidl_return = cryptfs_crypto_complete(); + return ok(); +} + +static int fdeEnableInternal(int32_t passwordType, const std::string& password, + int32_t encryptionFlags) { + bool noUi = (encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_NO_UI) != 0; + + std::string how; + if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_IN_PLACE) != 0) { + how = "inplace"; + } else if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_WIPE) != 0) { + how = "wipe"; + } else { + LOG(ERROR) << "Missing encryption flag"; + return -1; + } + + for (int tries = 0; tries < 2; ++tries) { + int rc; + if (passwordType == VoldNativeService::PASSWORD_TYPE_DEFAULT) { + rc = cryptfs_enable_default(how.c_str(), noUi); + } else { + rc = cryptfs_enable(how.c_str(), passwordType, password.c_str(), noUi); + } + + if (rc == 0) { + return 0; + } else if (tries == 0) { + Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL); + } + } + + return -1; +} + +binder::Status VoldNativeService::fdeEnable(int32_t passwordType, + const std::string& password, int32_t encryptionFlags) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + if (e4crypt_is_native()) { + if (passwordType != PASSWORD_TYPE_DEFAULT) { + return error("Unexpected password type"); + } + if (encryptionFlags != (ENCRYPTION_FLAG_IN_PLACE | ENCRYPTION_FLAG_NO_UI)) { + return error("Unexpected flags"); + } + return translateBool(e4crypt_enable_crypto()); + } + + // Spawn as thread so init can issue commands back to vold without + // causing deadlock, usually as a result of prep_data_fs. + std::thread(&fdeEnableInternal, passwordType, password, encryptionFlags).detach(); + return ok(); +} + +binder::Status VoldNativeService::fdeChangePassword(int32_t passwordType, + const std::string& password) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translate(cryptfs_changepw(passwordType, password.c_str())); +} + +binder::Status VoldNativeService::fdeVerifyPassword(const std::string& password) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translate(cryptfs_verify_passwd(password.c_str())); +} + +binder::Status VoldNativeService::fdeGetField(const std::string& key, + std::string* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + char buf[PROPERTY_VALUE_MAX]; + if (cryptfs_getfield(key.c_str(), buf, sizeof(buf)) != CRYPTO_GETFIELD_OK) { + return error(StringPrintf("Failed to read field %s", key.c_str())); + } else { + *_aidl_return = buf; + return ok(); + } +} + +binder::Status VoldNativeService::fdeSetField(const std::string& key, + const std::string& value) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translate(cryptfs_setfield(key.c_str(), value.c_str())); +} + +binder::Status VoldNativeService::fdeGetPasswordType(int32_t* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + *_aidl_return = cryptfs_get_password_type(); + return ok(); +} + +binder::Status VoldNativeService::fdeGetPassword(std::string* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + const char* res = cryptfs_get_password(); + if (res != nullptr) { + *_aidl_return = res; + } + return ok(); +} + +binder::Status VoldNativeService::fdeClearPassword() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + cryptfs_clear_password(); + return ok(); +} + +binder::Status VoldNativeService::fbeEnable() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_initialize_global_de()); +} + +binder::Status VoldNativeService::mountDefaultEncrypted() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + if (e4crypt_is_native()) { + return translateBool(e4crypt_mount_metadata_encrypted()); + } else { + // Spawn as thread so init can issue commands back to vold without + // causing deadlock, usually as a result of prep_data_fs. + std::thread(&cryptfs_mount_default_encrypted).detach(); + return ok(); + } +} + +binder::Status VoldNativeService::initUser0() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_init_user0()); +} + +binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + *_aidl_return = cryptfs_isConvertibleToFBE() != 0; + return ok(); +} + +binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial, + bool ephemeral) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_vold_create_user_key(userId, userSerial, ephemeral)); +} + +binder::Status VoldNativeService::destroyUserKey(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_destroy_user_key(userId)); +} + +binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSerial, + const std::string& token, const std::string& secret) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_add_user_key_auth(userId, userSerial, token.c_str(), secret.c_str())); +} + +binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_fixate_newest_user_key_auth(userId)); +} + +binder::Status VoldNativeService::unlockUserKey(int32_t userId, int32_t userSerial, + const std::string& token, const std::string& secret) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_unlock_user_key(userId, userSerial, token.c_str(), secret.c_str())); +} + +binder::Status VoldNativeService::lockUserKey(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_lock_user_key(userId)); +} + +binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr& uuid, + int32_t userId, int32_t userSerial, int32_t flags) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + return translateBool(e4crypt_prepare_user_storage(uuid_, userId, userSerial, flags)); +} + +binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr& uuid, + int32_t userId, int32_t flags) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + return translateBool(e4crypt_destroy_user_storage(uuid_, userId, flags)); +} + +binder::Status VoldNativeService::secdiscard(const std::string& path) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_secdiscard(path.c_str())); +} + } // namespace vold } // namespace android diff --git a/VoldNativeService.h b/VoldNativeService.h index f412bfc..50244d2 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -63,6 +63,44 @@ public: binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId, android::base::unique_fd* _aidl_return); binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId); + + binder::Status fdeCheckPassword(const std::string& password); + binder::Status fdeRestart(); + binder::Status fdeComplete(int32_t* _aidl_return); + binder::Status fdeEnable(int32_t passwordType, + const std::string& password, int32_t encryptionFlags); + binder::Status fdeChangePassword(int32_t passwordType, + const std::string& password); + binder::Status fdeVerifyPassword(const std::string& password); + binder::Status fdeGetField(const std::string& key, std::string* _aidl_return); + binder::Status fdeSetField(const std::string& key, const std::string& value); + binder::Status fdeGetPasswordType(int32_t* _aidl_return); + binder::Status fdeGetPassword(std::string* _aidl_return); + binder::Status fdeClearPassword(); + + binder::Status fbeEnable(); + + binder::Status mountDefaultEncrypted(); + binder::Status initUser0(); + binder::Status isConvertibleToFbe(bool* _aidl_return); + + binder::Status createUserKey(int32_t userId, int32_t userSerial, bool ephemeral); + binder::Status destroyUserKey(int32_t userId); + + binder::Status addUserKeyAuth(int32_t userId, int32_t userSerial, + const std::string& token, const std::string& secret); + binder::Status fixateNewestUserKeyAuth(int32_t userId); + + binder::Status unlockUserKey(int32_t userId, int32_t userSerial, + const std::string& token, const std::string& secret); + binder::Status lockUserKey(int32_t userId); + + binder::Status prepareUserStorage(const std::unique_ptr& uuid, + int32_t userId, int32_t userSerial, int32_t flags); + binder::Status destroyUserStorage(const std::unique_ptr& uuid, + int32_t userId, int32_t flags); + + binder::Status secdiscard(const std::string& path); }; } // namespace vold diff --git a/VolumeManager.h b/VolumeManager.h index 097ce6a..7dc69f3 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -94,6 +94,7 @@ public: // TODO: pipe all requests through VM to avoid exposing this lock std::mutex& getLock() { return mLock; } + std::mutex& getCryptLock() { return mCryptLock; } int start(); int stop(); @@ -218,6 +219,7 @@ private: int linkPrimary(userid_t userId); std::mutex mLock; + std::mutex mCryptLock; std::list> mDiskSources; std::list> mDisks; diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index d945357..e8a8f2a 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -50,6 +50,49 @@ interface IVold { FileDescriptor mountAppFuse(int uid, int pid, int mountId); void unmountAppFuse(int uid, int pid, int mountId); + void fdeCheckPassword(@utf8InCpp String password); + void fdeRestart(); + int fdeComplete(); + void fdeEnable(int passwordType, @utf8InCpp String password, int encryptionFlags); + void fdeChangePassword(int passwordType, @utf8InCpp String password); + void fdeVerifyPassword(@utf8InCpp String password); + @utf8InCpp String fdeGetField(@utf8InCpp String key); + void fdeSetField(@utf8InCpp String key, @utf8InCpp String value); + int fdeGetPasswordType(); + @utf8InCpp String fdeGetPassword(); + void fdeClearPassword(); + + void fbeEnable(); + + void mountDefaultEncrypted(); + void initUser0(); + boolean isConvertibleToFbe(); + + void createUserKey(int userId, int userSerial, boolean ephemeral); + void destroyUserKey(int userId); + + void addUserKeyAuth(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret); + void fixateNewestUserKeyAuth(int userId); + + void unlockUserKey(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret); + void lockUserKey(int userId); + + void prepareUserStorage(@nullable @utf8InCpp String uuid, int userId, int userSerial, int storageFlags); + void destroyUserStorage(@nullable @utf8InCpp String uuid, int userId, int storageFlags); + + void secdiscard(@utf8InCpp String path); + + const int ENCRYPTION_FLAG_WIPE = 1; + const int ENCRYPTION_FLAG_IN_PLACE = 2; + const int ENCRYPTION_FLAG_NO_UI = 4; + + const int ENCRYPTION_STATE_NONE = 1; + const int ENCRYPTION_STATE_OK = 0; + const int ENCRYPTION_STATE_ERROR_UNKNOWN = -1; + const int ENCRYPTION_STATE_ERROR_INCOMPLETE = -2; + const int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3; + const int ENCRYPTION_STATE_ERROR_CORRUPT = -4; + const int FSTRIM_FLAG_DEEP_TRIM = 1; const int FSTRIM_FLAG_BENCHMARK_AFTER = 2; @@ -60,6 +103,14 @@ interface IVold { 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; diff --git a/cryptfs.cpp b/cryptfs.cpp index 764d441..adfb284 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1813,7 +1813,7 @@ int cryptfs_check_passwd(const char *passwd) return rc; } -int cryptfs_verify_passwd(char *passwd) +int cryptfs_verify_passwd(const char *passwd) { struct crypt_mnt_ftr crypt_ftr; /* Allocate enough space for a 256 bit key, but we may use less */ @@ -2058,7 +2058,7 @@ static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how, return rc; } -int cryptfs_enable_internal(char *howarg, int crypt_type, const char *passwd, +int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *passwd, int no_ui) { int how = 0; @@ -2417,12 +2417,12 @@ error_shutting_down: return -1; } -int cryptfs_enable(char *howarg, int type, char *passwd, int no_ui) +int cryptfs_enable(const char *howarg, int type, const char *passwd, int no_ui) { return cryptfs_enable_internal(howarg, type, passwd, no_ui); } -int cryptfs_enable_default(char *howarg, int no_ui) +int cryptfs_enable_default(const char *howarg, int no_ui) { return cryptfs_enable_internal(howarg, CRYPT_TYPE_DEFAULT, DEFAULT_PASSWORD, no_ui); diff --git a/cryptfs.h b/cryptfs.h index d20d96d..a7b650f 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -229,11 +229,11 @@ extern "C" { int cryptfs_crypto_complete(void); int cryptfs_check_passwd(const char *pw); - int cryptfs_verify_passwd(char *newpw); + int cryptfs_verify_passwd(const char *pw); int cryptfs_restart(void); - int cryptfs_enable(char *flag, int type, char *passwd, int no_ui); + int cryptfs_enable(const char *flag, int type, const char *passwd, int no_ui); int cryptfs_changepw(int type, const char *newpw); - int cryptfs_enable_default(char *flag, int no_ui); + int cryptfs_enable_default(const char *flag, int no_ui); int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const unsigned char* key, int keysize, char* out_crypto_blkdev); int cryptfs_revert_ext_volume(const char* label); From 814e9d308e89b721e70025d3469b021b4ff10042 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 13 Sep 2017 11:49:44 -0600 Subject: [PATCH 008/106] Move unsolicited vold events to Binder. Create IVoldListener and move most unsolicited vold events over to this new interface. The remaining events will be routed through method-specific listeners instead of a global one. Move to upstream DISALLOW_COPY_AND_ASSIGN macro. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.DirectBootHostTest Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest Bug: 13758960 Change-Id: Ib9293487db2d525a76b9b9c2e9ac18d98601c6cf --- Android.mk | 3 +++ Utils.h | 11 +++------ VoldNativeService.cpp | 9 +++++++ VoldNativeService.h | 2 ++ VolumeManager.h | 7 ++++++ binder/android/os/IVold.aidl | 32 +++++++++++++----------- binder/android/os/IVoldListener.aidl | 37 ++++++++++++++++++++++++++++ model/Disk.cpp | 26 +++++++++++++++++++ model/PrivateVolume.cpp | 5 ++++ model/PublicVolume.cpp | 5 ++++ model/VolumeBase.cpp | 34 +++++++++++++++++++++++++ model/VolumeBase.h | 3 +++ 12 files changed, 152 insertions(+), 22 deletions(-) create mode 100644 binder/android/os/IVoldListener.aidl diff --git a/Android.mk b/Android.mk index 49d58c2..1fc560c 100644 --- a/Android.mk +++ b/Android.mk @@ -37,6 +37,7 @@ common_src_files := \ EncryptInplace.cpp \ MetadataCrypt.cpp \ binder/android/os/IVold.aidl \ + binder/android/os/IVoldListener.aidl \ VoldNativeService.cpp \ common_c_includes := \ @@ -109,6 +110,8 @@ LOCAL_CFLAGS := $(vold_cflags) LOCAL_CONLYFLAGS := $(vold_conlyflags) LOCAL_REQUIRED_MODULES := $(required_modules) +LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder + include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) diff --git a/Utils.h b/Utils.h index 82ac440..153c320 100644 --- a/Utils.h +++ b/Utils.h @@ -19,6 +19,7 @@ #include "KeyBuffer.h" +#include #include #include #include @@ -26,16 +27,10 @@ #include #include -// 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; +#define ENABLE_BINDER 1 + namespace android { namespace vold { diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 374cb4c..f5f0838 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -201,6 +201,15 @@ status_t VoldNativeService::dump(int fd, const Vector & /* args */) { return NO_ERROR; } +binder::Status VoldNativeService::setListener( + const android::sp& listener) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + VolumeManager::Instance()->setListener(listener); + return ok(); +} + binder::Status VoldNativeService::reset() { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; diff --git a/VoldNativeService.h b/VoldNativeService.h index 50244d2..b6b5d75 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -31,6 +31,8 @@ public: static char const* getServiceName() { return "vold"; } virtual status_t dump(int fd, const Vector &args) override; + binder::Status setListener(const android::sp& listener); + binder::Status reset(); binder::Status shutdown(); binder::Status mountAll(); diff --git a/VolumeManager.h b/VolumeManager.h index 7dc69f3..2751ad5 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -36,6 +36,8 @@ #include #include +#include "android/os/IVoldListener.h" + #include "model/Disk.h" #include "model/VolumeBase.h" @@ -96,6 +98,9 @@ public: std::mutex& getLock() { return mLock; } std::mutex& getCryptLock() { return mCryptLock; } + void setListener(android::sp listener) { mListener = listener; } + android::sp getListener() { return mListener; } + int start(); int stop(); @@ -221,6 +226,8 @@ private: std::mutex mLock; std::mutex mCryptLock; + android::sp mListener; + std::list> mDiskSources; std::list> mDisks; std::list> mObbVolumes; diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index e8a8f2a..0a05e6e 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -16,8 +16,12 @@ package android.os; +import android.os.IVoldListener; + /** {@hide} */ interface IVold { + void setListener(IVoldListener listener); + void reset(); void shutdown(); void mountAll(); @@ -116,19 +120,19 @@ interface IVold { const int REMOUNT_MODE_READ = 2; const int REMOUNT_MODE_WRITE = 3; - const int STATE_UNMOUNTED = 0; - const int STATE_CHECKING = 1; - const int STATE_MOUNTED = 2; - const int STATE_MOUNTED_READ_ONLY = 3; - const int STATE_FORMATTING = 4; - const int STATE_EJECTING = 5; - const int STATE_UNMOUNTABLE = 6; - const int STATE_REMOVED = 7; - const int STATE_BAD_REMOVAL = 8; + const int 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 TYPE_PUBLIC = 0; - const int TYPE_PRIVATE = 1; - const int TYPE_EMULATED = 2; - const int TYPE_ASEC = 3; - const int TYPE_OBB = 4; + 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; } diff --git a/binder/android/os/IVoldListener.aidl b/binder/android/os/IVoldListener.aidl new file mode 100644 index 0000000..0dcfc04 --- /dev/null +++ b/binder/android/os/IVoldListener.aidl @@ -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); +} diff --git a/model/Disk.cpp b/model/Disk.cpp index 9c22400..151937f 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -151,7 +151,12 @@ void Disk::listVolumes(VolumeBase::Type type, std::list& list) { status_t Disk::create() { CHECK(!mCreated); mCreated = true; +#if ENABLE_BINDER + auto listener = VolumeManager::Instance()->getListener(); + if (listener) listener->onDiskCreated(getId(), mFlags); +#else notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags)); +#endif readMetadata(); readPartitions(); return OK; @@ -161,7 +166,12 @@ status_t Disk::destroy() { CHECK(mCreated); destroyAllVolumes(); mCreated = false; +#if ENABLE_BINDER + auto listener = VolumeManager::Instance()->getListener(); + if (listener) listener->onDiskDestroyed(getId()); +#else notifyEvent(ResponseCode::DiskDestroyed); +#endif return OK; } @@ -281,9 +291,15 @@ status_t Disk::readMetadata() { } } +#if ENABLE_BINDER + auto listener = VolumeManager::Instance()->getListener(); + if (listener) listener->onDiskMetadataChanged(getId(), + mSize, mLabel, mSysPath); +#else notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize)); notifyEvent(ResponseCode::DiskLabelChanged, mLabel); notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath); +#endif return OK; } @@ -306,7 +322,12 @@ status_t Disk::readPartitions() { status_t res = ForkExecvp(cmd, output); if (res != OK) { LOG(WARNING) << "sgdisk failed to scan " << mDevPath; +#if ENABLE_BINDER + auto listener = VolumeManager::Instance()->getListener(); + if (listener) listener->onDiskScanned(getId()); +#else notifyEvent(ResponseCode::DiskScanned); +#endif mJustPartitioned = false; return res; } @@ -372,7 +393,12 @@ status_t Disk::readPartitions() { } } +#if ENABLE_BINDER + auto listener = VolumeManager::Instance()->getListener(); + if (listener) listener->onDiskScanned(getId()); +#else notifyEvent(ResponseCode::DiskScanned); +#endif mJustPartitioned = false; return OK; } diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index e66e04d..9a96082 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -55,9 +55,14 @@ PrivateVolume::~PrivateVolume() { status_t PrivateVolume::readMetadata() { status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel); +#if ENABLE_BINDER + auto listener = getListener(); + if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel); +#else notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType); notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid); notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel); +#endif return res; } diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index f976c4a..04bafed 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -53,9 +53,14 @@ PublicVolume::~PublicVolume() { status_t PublicVolume::readMetadata() { status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel); +#if ENABLE_BINDER + auto listener = getListener(); + if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel); +#else notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType); notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid); notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel); +#endif return res; } diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index 3f27d87..b2eff3b 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -44,7 +44,12 @@ VolumeBase::~VolumeBase() { void VolumeBase::setState(State state) { mState = state; +#if ENABLE_BINDER + auto listener = getListener(); + if (listener) listener->onVolumeStateChanged(getId(), static_cast(mState)); +#else notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState)); +#endif } status_t VolumeBase::setDiskId(const std::string& diskId) { @@ -114,7 +119,12 @@ status_t VolumeBase::setPath(const std::string& path) { } mPath = path; +#if ENABLE_BINDER + auto listener = getListener(); + if (listener) listener->onVolumePathChanged(getId(), mPath); +#else notifyEvent(ResponseCode::VolumePathChanged, mPath); +#endif return OK; } @@ -125,7 +135,12 @@ status_t VolumeBase::setInternalPath(const std::string& internalPath) { } mInternalPath = internalPath; +#if ENABLE_BINDER + auto listener = getListener(); + if (listener) listener->onVolumeInternalPathChanged(getId(), mInternalPath); +#else notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath); +#endif return OK; } @@ -141,6 +156,14 @@ void VolumeBase::notifyEvent(int event, const std::string& value) { StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false); } +android::sp VolumeBase::getListener() { + if (mSilent) { + return nullptr; + } else { + return VolumeManager::Instance()->getListener(); + } +} + void VolumeBase::addVolume(const std::shared_ptr& volume) { mVolumes.push_back(volume); } @@ -163,8 +186,14 @@ status_t VolumeBase::create() { mCreated = true; status_t res = doCreate(); +#if ENABLE_BINDER + auto listener = getListener(); + if (listener) listener->onVolumeCreated(getId(), + static_cast(mType), mDiskId, mPartGuid); +#else notifyEvent(ResponseCode::VolumeCreated, StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str())); +#endif setState(State::kUnmounted); return res; } @@ -183,7 +212,12 @@ status_t VolumeBase::destroy() { setState(State::kRemoved); } +#if ENABLE_BINDER + auto listener = getListener(); + if (listener) listener->onVolumeDestroyed(getId()); +#else notifyEvent(ResponseCode::VolumeDestroyed); +#endif status_t res = doDestroy(); mCreated = false; return res; diff --git a/model/VolumeBase.h b/model/VolumeBase.h index d417019..ac111c2 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -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 @@ -117,6 +118,8 @@ protected: void notifyEvent(int msg); void notifyEvent(int msg, const std::string& value); + android::sp getListener(); + private: /* ID that uniquely references volume while alive */ std::string mId; From 99f92689de18328cade9f31e55a8a6943d9ce15b Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 13 Sep 2017 18:43:44 -0600 Subject: [PATCH 009/106] Move vdc commands over to Binder. Use nice clean AIDL instead of dirty sockets. Test: vdc cryptfs init_user0 Bug: 13758960 Change-Id: Ia9dc2e8e1d23e694f1c299fa16d346b07b516718 --- Android.mk | 6 ++++-- vdc.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Android.mk b/Android.mk index 49d58c2..44ebb77 100644 --- a/Android.mk +++ b/Android.mk @@ -144,13 +144,15 @@ LOCAL_CLANG := true LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) -LOCAL_SRC_FILES := vdc.cpp +LOCAL_SRC_FILES := vdc.cpp binder/android/os/IVold.aidl LOCAL_MODULE := vdc -LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SHARED_LIBRARIES := libbase libbinder libcutils libutils LOCAL_CFLAGS := $(vold_cflags) LOCAL_CONLYFLAGS := $(vold_conlyflags) LOCAL_INIT_RC := vdc.rc +LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder + include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) diff --git a/vdc.cpp b/vdc.cpp index 7ab5fcc..3a38641 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -30,15 +30,23 @@ #include #include +#include "android/os/IVold.h" + #include #include +#include #include #include +#define ENABLE_BINDER 1 + static void usage(char *progname); + +#if !ENABLE_BINDER static int do_monitor(int sock, int stop_after_cmd); static int do_cmd(int sock, int argc, char **argv); +#endif static constexpr int kCommandTimeoutMs = 20 * 1000; @@ -62,11 +70,39 @@ int main(int argc, char **argv) { argc--; } - if (argc < 2) { + if (argc < 3) { usage(progname); exit(5); } +#if ENABLE_BINDER + std::string arg1 = argv[1]; + std::string arg2 = argv[2]; + + android::sp binder = android::defaultServiceManager()->getService( + android::String16("vold")); + if (!binder) { + LOG(ERROR) << "Failed to obtain vold Binder"; + exit(EINVAL); + } + auto vold = android::interface_cast(binder); + + if (arg1 == "cryptfs" && arg2 == "enablefilecrypto") { + exit(vold->fbeEnable().isOk() ? 0 : ENOTTY); + } else if (arg1 == "cryptfs" && arg2 == "init_user0") { + exit(vold->initUser0().isOk() ? 0 : ENOTTY); + } else if (arg1 == "cryptfs" && arg2 == "enablecrypto") { + int passwordType = android::os::IVold::PASSWORD_TYPE_DEFAULT; + int encryptionFlags = android::os::IVold::ENCRYPTION_FLAG_IN_PLACE + | android::os::IVold::ENCRYPTION_FLAG_NO_UI; + exit(vold->fdeEnable(passwordType, "", encryptionFlags).isOk() ? 0 : ENOTTY); + } else if (arg1 == "volume" && arg2 == "shutdown") { + exit(vold->shutdown().isOk() ? 0 : ENOTTY); + } else { + LOG(ERROR) << "Raw commands are no longer supported"; + exit(EINVAL); + } +#else const char* sockname = "vold"; if (!strcmp(argv[1], "cryptfs")) { sockname = "cryptd"; @@ -88,8 +124,10 @@ int main(int argc, char **argv) { } else { exit(do_cmd(sock, argc, argv)); } +#endif } +#if !ENABLE_BINDER static int do_cmd(int sock, int argc, char **argv) { int seq = getpid(); @@ -175,6 +213,7 @@ static int do_monitor(int sock, int stop_after_seq) { } return EIO; } +#endif static void usage(char *progname) { LOG(INFO) << "Usage: " << progname << " [--wait] | [arg1] [arg2...]"; From 0990b69d6bf9288c90e45f933294d6db7e81256c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 14 Sep 2017 17:24:26 -0600 Subject: [PATCH 010/106] Fix build breakage. Change-Id: I4d79762acf81a7402e6579624da32ce8da236611 --- Android.mk | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Android.mk b/Android.mk index a89d84c..ccbbb56 100644 --- a/Android.mk +++ b/Android.mk @@ -147,7 +147,12 @@ LOCAL_CLANG := true LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) -LOCAL_SRC_FILES := vdc.cpp binder/android/os/IVold.aidl + +LOCAL_SRC_FILES := \ + vdc.cpp \ + binder/android/os/IVold.aidl \ + binder/android/os/IVoldListener.aidl \ + LOCAL_MODULE := vdc LOCAL_SHARED_LIBRARIES := libbase libbinder libcutils libutils LOCAL_CFLAGS := $(vold_cflags) From 52f7a9193479a48c3377fa597191d4dac71f4416 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 15 Sep 2017 12:57:44 -0600 Subject: [PATCH 011/106] Move long-running calls to async with listeners. Now that we're using Binder, we can have callers provide explicit listeners for every request instead of trying to squeeze them all into unsolicited socket events. Move benchmarking to be async to avoid blocking other commands for up to several minutes. Remove post-trim benchmarking flag, since benchmarking now requires a separate callback. Will bring back in a future CL. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Test: adb shell sm fstrim Bug: 62201209, 13758960 Change-Id: I0f2ebf1ac3b4252ecd6b44303f2887adfdb58e86 --- Android.mk | 25 ++++--- Benchmark.cpp => BenchmarkTask.cpp | 73 ++++++++++++------- BenchmarkTask.h | 50 +++++++++++++ CommandListener.cpp | 12 ++- MoveTask.cpp | 18 +++-- MoveTask.h | 11 ++- TrimTask.cpp | 45 ++++++------ TrimTask.h | 5 +- VoldNativeService.cpp | 36 +++++++-- VoldNativeService.h | 9 ++- VolumeManager.cpp | 20 ----- VolumeManager.h | 2 - binder/android/os/IVold.aidl | 9 ++- .../android/os/IVoldTaskListener.aidl | 25 ++----- 14 files changed, 210 insertions(+), 130 deletions(-) rename Benchmark.cpp => BenchmarkTask.cpp (71%) create mode 100644 BenchmarkTask.h rename Benchmark.h => binder/android/os/IVoldTaskListener.aidl (59%) diff --git a/Android.mk b/Android.mk index ccbbb56..78d60df 100644 --- a/Android.mk +++ b/Android.mk @@ -26,7 +26,7 @@ common_src_files := \ model/ObbVolume.cpp \ Utils.cpp \ MoveTask.cpp \ - Benchmark.cpp \ + BenchmarkTask.cpp \ TrimTask.cpp \ KeyBuffer.cpp \ Keymaster.cpp \ @@ -36,9 +36,16 @@ common_src_files := \ secontext.cpp \ EncryptInplace.cpp \ MetadataCrypt.cpp \ + VoldNativeService.cpp \ + +common_aidl_files := \ binder/android/os/IVold.aidl \ binder/android/os/IVoldListener.aidl \ - VoldNativeService.cpp \ + binder/android/os/IVoldTaskListener.aidl \ + +common_aidl_includes := \ + $(LOCAL_PATH)/binder \ + frameworks/native/aidl/binder \ common_c_includes := \ system/extras/f2fs_utils \ @@ -101,7 +108,7 @@ LOCAL_CLANG := true LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) -LOCAL_SRC_FILES := $(common_src_files) +LOCAL_SRC_FILES := $(common_src_files) $(common_aidl_files) LOCAL_C_INCLUDES := $(common_c_includes) LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) LOCAL_STATIC_LIBRARIES := $(common_static_libraries) @@ -110,7 +117,7 @@ LOCAL_CFLAGS := $(vold_cflags) LOCAL_CONLYFLAGS := $(vold_conlyflags) LOCAL_REQUIRED_MODULES := $(required_modules) -LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder +LOCAL_AIDL_INCLUDES := $(common_aidl_includes) include $(BUILD_STATIC_LIBRARY) @@ -124,7 +131,8 @@ LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES := \ main.cpp \ - $(common_src_files) + $(common_src_files) \ + $(common_aidl_files) \ LOCAL_INIT_RC := vold.rc @@ -136,7 +144,7 @@ LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) LOCAL_STATIC_LIBRARIES := $(common_static_libraries) LOCAL_REQUIRED_MODULES := $(required_modules) -LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder +LOCAL_AIDL_INCLUDES := $(common_aidl_includes) include $(BUILD_EXECUTABLE) @@ -150,8 +158,7 @@ LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES := \ vdc.cpp \ - binder/android/os/IVold.aidl \ - binder/android/os/IVoldListener.aidl \ + $(common_aidl_files) \ LOCAL_MODULE := vdc LOCAL_SHARED_LIBRARIES := libbase libbinder libcutils libutils @@ -159,7 +166,7 @@ LOCAL_CFLAGS := $(vold_cflags) LOCAL_CONLYFLAGS := $(vold_conlyflags) LOCAL_INIT_RC := vdc.rc -LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder +LOCAL_AIDL_INCLUDES := $(common_aidl_includes) include $(BUILD_EXECUTABLE) diff --git a/Benchmark.cpp b/BenchmarkTask.cpp similarity index 71% rename from Benchmark.cpp rename to BenchmarkTask.cpp index bbab792..5ec249a 100644 --- a/Benchmark.cpp +++ b/BenchmarkTask.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Benchmark.h" +#include "BenchmarkTask.h" #include "BenchmarkGen.h" #include "VolumeManager.h" #include "ResponseCode.h" @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -36,19 +37,35 @@ 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); +static const char* kWakeLock = "BenchmarkTask"; + +BenchmarkTask::BenchmarkTask(const std::string& path, + const android::sp& listener) : + mPath(path), mListener(listener) { } -static nsecs_t benchmark(const std::string& path) { +BenchmarkTask::~BenchmarkTask() { +} + +void BenchmarkTask::start() { + mThread = std::thread(&BenchmarkTask::run, this); +} + +static status_t runInternal(const std::string& rootPath, android::os::PersistableBundle& extras) { + auto path = rootPath; + path += "/misc"; + if (android::vold::PrepareDir(path, 01771, AID_SYSTEM, AID_MISC)) { + return -1; + } + path += "/vold"; + if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) { + return -1; + } + path += "/bench"; + if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) { + return -1; + } + errno = 0; int orig_prio = getpriority(PRIO_PROCESS, 0); if (errno != 0) { @@ -127,26 +144,26 @@ static nsecs_t benchmark(const std::string& path) { 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); + extras.putString(String16("path"), String16(path.c_str())); + extras.putString(String16("ident"), String16(BenchmarkIdent().c_str())); + extras.putLong(String16("create"), create_d); + extras.putLong(String16("drop"), drop_d); + extras.putLong(String16("run"), run_d); + extras.putLong(String16("destroy"), destroy_d); - return run_d; + return 0; } -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 BenchmarkTask::run() { + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); + + android::os::PersistableBundle extras; + status_t res = runInternal(mPath, extras); + if (mListener) { + mListener->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 diff --git a/BenchmarkTask.h b/BenchmarkTask.h new file mode 100644 index 0000000..dfa3922 --- /dev/null +++ b/BenchmarkTask.h @@ -0,0 +1,50 @@ +/* + * 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 ANDROID_VOLD_BENCHMARK_TASK_H +#define ANDROID_VOLD_BENCHMARK_TASK_H + +#include "android/os/IVoldTaskListener.h" +#include "Utils.h" + +#include +#include + +namespace android { +namespace vold { + +class BenchmarkTask { +public: + BenchmarkTask(const std::string& path, + const android::sp& listener); + virtual ~BenchmarkTask(); + + void start(); + +private: + std::string mPath; + android::sp mListener; + std::thread mThread; + + void run(); + + DISALLOW_COPY_AND_ASSIGN(BenchmarkTask); +}; + +} // namespace vold +} // namespace android + +#endif diff --git a/CommandListener.cpp b/CommandListener.cpp index 60c0898..a402ffa 100644 --- a/CommandListener.cpp +++ b/CommandListener.cpp @@ -256,13 +256,14 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli, return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false); } - (new android::vold::MoveTask(fromVol, toVol))->start(); + (new android::vold::MoveTask(fromVol, toVol, nullptr))->start(); return sendGenericOkFail(cli, 0); } else if (cmd == "benchmark" && argc > 2) { // benchmark [volId] std::string id(argv[2]); - nsecs_t res = vm->benchmarkPrivate(id); + LOG(WARNING) << "Benchmarking has moved to Binder interface"; + nsecs_t res = 0; return cli->sendMsg(ResponseCode::CommandOkay, android::base::StringPrintf("%" PRId64, res).c_str(), false); @@ -603,16 +604,13 @@ int CommandListener::FstrimCmd::runCommand(SocketClient *cli, 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; + flags = android::vold::TrimTask::Flags::kDeepTrim; } - (new android::vold::TrimTask(flags))->start(); + (new android::vold::TrimTask(flags, nullptr))->start(); return sendGenericOkFail(cli, 0); } diff --git a/MoveTask.cpp b/MoveTask.cpp index c565752..8c0efac 100644 --- a/MoveTask.cpp +++ b/MoveTask.cpp @@ -45,9 +45,9 @@ static const char* kRmPath = "/system/bin/rm"; static const char* kWakeLock = "MoveTask"; -MoveTask::MoveTask(const std::shared_ptr& from, - const std::shared_ptr& to) : - mFrom(from), mTo(to) { +MoveTask::MoveTask(const std::shared_ptr& from, const std::shared_ptr& to, + const android::sp& listener) : + mFrom(from), mTo(to), mListener(listener) { } MoveTask::~MoveTask() { @@ -57,9 +57,11 @@ 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); +void MoveTask::notifyProgress(int progress) { + if (mListener) { + android::os::PersistableBundle extras; + mListener->onStatus(progress, extras); + } } static status_t pushBackContents(const std::string& path, std::vector& cmd, @@ -85,7 +87,7 @@ static status_t pushBackContents(const std::string& path, std::vector& from, const std::shared_ptr& to); + MoveTask(const std::shared_ptr& from, const std::shared_ptr& to, + const android::sp& listener); virtual ~MoveTask(); void start(); @@ -35,10 +37,17 @@ public: private: std::shared_ptr mFrom; std::shared_ptr mTo; + android::sp mListener; std::thread mThread; void run(); + void notifyProgress(int progress); + + status_t execRm(const std::string& path, int startProgress, int stepProgress); + status_t execCp(const std::string& fromPath, const std::string& toPath, + int startProgress, int stepProgress); + DISALLOW_COPY_AND_ASSIGN(MoveTask); }; diff --git a/TrimTask.cpp b/TrimTask.cpp index 08e6499..d37ec20 100644 --- a/TrimTask.cpp +++ b/TrimTask.cpp @@ -15,7 +15,6 @@ */ #include "TrimTask.h" -#include "Benchmark.h" #include "Utils.h" #include "VolumeManager.h" #include "ResponseCode.h" @@ -37,8 +36,6 @@ /* From a would-be kernel header */ #define FIDTRIM _IOWR('f', 128, struct fstrim_range) /* Deep discard trim */ -#define BENCHMARK_ENABLED 1 - using android::base::StringPrintf; namespace android { @@ -46,7 +43,8 @@ namespace vold { static const char* kWakeLock = "TrimTask"; -TrimTask::TrimTask(int flags) : mFlags(flags) { +TrimTask::TrimTask(int flags, const android::sp& listener) : + mFlags(flags), mListener(listener) { // Collect both fstab and vold volumes addFromFstab(); @@ -102,23 +100,21 @@ 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; + 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 (mListener) { + mListener->onStatus(-1, extras); + } continue; } @@ -129,22 +125,25 @@ void TrimTask::run() { nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); if (ioctl(fd, (mFlags & Flags::kDeepTrim) ? FIDTRIM : FITRIM, &range)) { PLOG(WARNING) << "Trim failed on " << path; - notifyResult(path, -1, -1); + if (mListener) { + mListener->onStatus(-1, extras); + } } else { - nsecs_t delta = systemTime(SYSTEM_TIME_BOOTTIME) - start; + nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start; LOG(INFO) << "Trimmed " << range.len << " bytes on " << path - << " in " << nanoseconds_to_milliseconds(delta) << "ms"; - notifyResult(path, range.len, delta); + << " in " << nanoseconds_to_milliseconds(time) << "ms"; + extras.putLong(String16("bytes"), range.len); + extras.putLong(String16("time"), time); + if (mListener) { + mListener->onStatus(0, extras); + } } close(fd); + } - if (mFlags & Flags::kBenchmarkAfter) { -#if BENCHMARK_ENABLED - BenchmarkPrivate(path); -#else - LOG(DEBUG) << "Benchmark disabled"; -#endif - } + if (mListener) { + android::os::PersistableBundle extras; + mListener->onFinished(0, extras); } release_wake_lock(kWakeLock); diff --git a/TrimTask.h b/TrimTask.h index 2ade7b5..a87728b 100644 --- a/TrimTask.h +++ b/TrimTask.h @@ -17,6 +17,7 @@ #ifndef ANDROID_VOLD_TRIM_TASK_H #define ANDROID_VOLD_TRIM_TASK_H +#include "android/os/IVoldTaskListener.h" #include "Utils.h" #include @@ -27,18 +28,18 @@ namespace vold { class TrimTask { public: - explicit TrimTask(int flags); + explicit TrimTask(int flags, const android::sp& listener); virtual ~TrimTask(); enum Flags { kDeepTrim = 1 << 0, - kBenchmarkAfter = 1 << 1, }; void start(); private: int mFlags; + android::sp mListener; std::list mPaths; std::thread mThread; diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index f5f0838..6c25674 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -16,6 +16,7 @@ #include "VoldNativeService.h" #include "VolumeManager.h" +#include "BenchmarkTask.h" #include "MoveTask.h" #include "Process.h" #include "TrimTask.h" @@ -333,17 +334,39 @@ binder::Status VoldNativeService::format(const std::string& volId, const std::st return translate(vol->format(fsType)); } -binder::Status VoldNativeService::benchmark(const std::string& volId, int64_t* _aidl_return) { +binder::Status VoldNativeService::benchmark(const std::string& volId, + const android::sp& listener) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; - *_aidl_return = VolumeManager::Instance()->benchmarkPrivate(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"); + } + + (new android::vold::BenchmarkTask(path, listener))->start(); return ok(); } binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, - const std::string& toVolId) { + const std::string& toVolId, const android::sp& listener) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_ID(fromVolId); CHECK_ARGUMENT_ID(toVolId); @@ -356,7 +379,7 @@ binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, } else if (toVol == nullptr) { return error("Failed to find volume " + toVolId); } - (new android::vold::MoveTask(fromVol, toVol))->start(); + (new android::vold::MoveTask(fromVol, toVol, listener))->start(); return ok(); } @@ -402,11 +425,12 @@ binder::Status VoldNativeService::destroyObb(const std::string& volId) { return translate(VolumeManager::Instance()->destroyObb(volId)); } -binder::Status VoldNativeService::fstrim(int32_t fstrimFlags) { +binder::Status VoldNativeService::fstrim(int32_t fstrimFlags, + const android::sp& listener) { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; - (new android::vold::TrimTask(fstrimFlags))->start(); + (new android::vold::TrimTask(fstrimFlags, listener))->start(); return ok(); } diff --git a/VoldNativeService.h b/VoldNativeService.h index b6b5d75..a00010b 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -48,9 +48,11 @@ public: binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId); binder::Status unmount(const std::string& volId); binder::Status format(const std::string& volId, const std::string& fsType); - binder::Status benchmark(const std::string& volId, int64_t* _aidl_return); + binder::Status benchmark(const std::string& volId, + const android::sp& listener); - binder::Status moveStorage(const std::string& fromVolId, const std::string& toVolId); + binder::Status moveStorage(const std::string& fromVolId, const std::string& toVolId, + const android::sp& listener); binder::Status remountUid(int32_t uid, int32_t remountMode); @@ -60,7 +62,8 @@ public: int32_t ownerGid, std::string* _aidl_return); binder::Status destroyObb(const std::string& volId); - binder::Status fstrim(int32_t fstrimFlags); + binder::Status fstrim(int32_t fstrimFlags, + const android::sp& listener); binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId, android::base::unique_fd* _aidl_return); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 022caff..3150997 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -47,7 +47,6 @@ #include -#include "Benchmark.h" #include "model/EmulatedVolume.h" #include "model/ObbVolume.h" #include "VolumeManager.h" @@ -459,25 +458,6 @@ void VolumeManager::listVolumes(android::vold::VolumeBase::Type type, } } -nsecs_t VolumeManager::benchmarkPrivate(const std::string& id) { - std::string path; - if (id == "private" || id == "null") { - path = "/data"; - } else { - auto vol = findVolume(id); - if (vol != nullptr && vol->getState() == android::vold::VolumeBase::State::kMounted) { - path = vol->getPath(); - } - } - - if (path.empty()) { - LOG(WARNING) << "Failed to find volume for " << id; - return -1; - } - - return android::vold::BenchmarkPrivate(path); -} - int VolumeManager::forgetPartition(const std::string& partGuid) { std::string normalizedGuid; if (android::vold::NormalizeHex(partGuid, normalizedGuid)) { diff --git a/VolumeManager.h b/VolumeManager.h index 2751ad5..a00520e 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -132,8 +132,6 @@ public: void listVolumes(android::vold::VolumeBase::Type type, std::list& list); - nsecs_t benchmarkPrivate(const std::string& id); - int forgetPartition(const std::string& partGuid); int onUserAdded(userid_t userId, int userSerialNumber); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 0a05e6e..1736829 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -17,6 +17,7 @@ package android.os; import android.os.IVoldListener; +import android.os.IVoldTaskListener; /** {@hide} */ interface IVold { @@ -37,9 +38,10 @@ interface IVold { void mount(@utf8InCpp String volId, int mountFlags, int mountUserId); void unmount(@utf8InCpp String volId); void format(@utf8InCpp String volId, @utf8InCpp String fsType); - long benchmark(@utf8InCpp String volId); + void benchmark(@utf8InCpp String volId, IVoldTaskListener listener); - void moveStorage(@utf8InCpp String fromVolId, @utf8InCpp String toVolId); + void moveStorage(@utf8InCpp String fromVolId, @utf8InCpp String toVolId, + IVoldTaskListener listener); void remountUid(int uid, int remountMode); @@ -49,7 +51,7 @@ interface IVold { @utf8InCpp String sourceKey, int ownerGid); void destroyObb(@utf8InCpp String volId); - void fstrim(int fstrimFlags); + void fstrim(int fstrimFlags, IVoldTaskListener listener); FileDescriptor mountAppFuse(int uid, int pid, int mountId); void unmountAppFuse(int uid, int pid, int mountId); @@ -98,7 +100,6 @@ interface IVold { const int ENCRYPTION_STATE_ERROR_CORRUPT = -4; const int FSTRIM_FLAG_DEEP_TRIM = 1; - const int FSTRIM_FLAG_BENCHMARK_AFTER = 2; const int MOUNT_FLAG_PRIMARY = 1; const int MOUNT_FLAG_VISIBLE = 2; diff --git a/Benchmark.h b/binder/android/os/IVoldTaskListener.aidl similarity index 59% rename from Benchmark.h rename to binder/android/os/IVoldTaskListener.aidl index 13f9009..e2bac04 100644 --- a/Benchmark.h +++ b/binder/android/os/IVoldTaskListener.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 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,21 +14,12 @@ * limitations under the License. */ -#ifndef ANDROID_VOLD_BENCHMARK_H -#define ANDROID_VOLD_BENCHMARK_H +package android.os; -#include -#include +import android.os.PersistableBundle; -#include - -namespace android { -namespace vold { - -/* Benchmark a private volume mounted at the given path */ -nsecs_t BenchmarkPrivate(const std::string& path); - -} // namespace vold -} // namespace android - -#endif +/** {@hide} */ +oneway interface IVoldTaskListener { + void onStatus(int status, in PersistableBundle extras); + void onFinished(int status, in PersistableBundle extras); +} From 57b1874505cadea1aef7480ba05ed81686b9c259 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 18 Sep 2017 13:49:51 -0600 Subject: [PATCH 012/106] Add "mountdefaultencrypted" command to vdc. It's being used by the emulator. Test: vdc --wait cryptfs mountdefaultencrypted Bug: 65795120 Change-Id: I8a5d622e4fa1ef93bb8e22f2665c882b1a152b3d --- vdc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vdc.cpp b/vdc.cpp index 3a38641..3335908 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -96,6 +96,8 @@ int main(int argc, char **argv) { int encryptionFlags = android::os::IVold::ENCRYPTION_FLAG_IN_PLACE | android::os::IVold::ENCRYPTION_FLAG_NO_UI; exit(vold->fdeEnable(passwordType, "", encryptionFlags).isOk() ? 0 : ENOTTY); + } else if (arg1 == "cryptfs" && arg2 == "mountdefaultencrypted") { + exit(vold->mountDefaultEncrypted().isOk() ? 0 : ENOTTY); } else if (arg1 == "volume" && arg2 == "shutdown") { exit(vold->shutdown().isOk() ? 0 : ENOTTY); } else { From 7bdf4d5a0f43f4073c87ff794f6efe91aa356b70 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 18 Sep 2017 14:47:10 -0600 Subject: [PATCH 013/106] Timeout if device isn't mounted. If the invoked FUSE binary fails to mount the requested filesystem, the dev_t won't actually change. To avoid getting waiting forever and triggering the watchdog, timeout after 5 seconds. Test: manually hang after fork and verify that we timeout Bug: 65756209 Change-Id: I6ea5fd08ed14c72c1d7f7064bfd0d9ac81d4897b --- model/EmulatedVolume.cpp | 8 ++++++++ model/PublicVolume.cpp | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 21b290a..d40cf3f 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -100,9 +101,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, WNOHANG)); diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 04bafed..6ad2ae1 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -191,9 +192,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, WNOHANG)); From cbe69fc060d021be972af44904dd76ed1aa2a5a2 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 15 Sep 2017 16:50:28 -0600 Subject: [PATCH 014/106] Destroy vold socket interface completely. Long live Binder. Test: yes Bug: 13758960 Change-Id: If6be379b5a873f1b0c66dd1522b87413ad10fc46 --- Android.mk | 4 - Asec.h | 43 -- BenchmarkTask.cpp | 1 - CommandListener.cpp | 689 ----------------- CommandListener.h | 87 --- CryptCommandListener.cpp | 448 ----------- CryptCommandListener.h | 42 -- Devmapper.cpp | 77 -- Devmapper.h | 3 - Loop.cpp | 87 --- Loop.h | 5 - MoveTask.cpp | 1 - ResponseCode.cpp | 42 -- ResponseCode.h | 91 --- TrimTask.cpp | 1 - Utils.h | 2 - VoldCommand.cpp | 21 - VoldCommand.h | 28 - VoldNativeService.cpp | 14 + VoldNativeService.h | 1 + VolumeManager.cpp | 1353 ---------------------------------- VolumeManager.h | 83 --- binder/android/os/IVold.aidl | 1 + main.cpp | 27 - model/Disk.cpp | 41 +- model/Disk.h | 3 - model/PrivateVolume.cpp | 9 +- model/PublicVolume.cpp | 9 +- model/VolumeBase.cpp | 43 +- model/VolumeBase.h | 3 - tests/VolumeManager_test.cpp | 27 - vdc.cpp | 129 +--- vold.rc | 3 - 33 files changed, 40 insertions(+), 3378 deletions(-) delete mode 100644 Asec.h delete mode 100644 CommandListener.cpp delete mode 100644 CommandListener.h delete mode 100644 CryptCommandListener.cpp delete mode 100644 CryptCommandListener.h delete mode 100644 ResponseCode.cpp delete mode 100644 ResponseCode.h delete mode 100644 VoldCommand.cpp delete mode 100644 VoldCommand.h diff --git a/Android.mk b/Android.mk index 78d60df..5957df7 100644 --- a/Android.mk +++ b/Android.mk @@ -2,9 +2,6 @@ LOCAL_PATH:= $(call my-dir) common_src_files := \ VolumeManager.cpp \ - CommandListener.cpp \ - CryptCommandListener.cpp \ - VoldCommand.cpp \ NetlinkManager.cpp \ NetlinkHandler.cpp \ Process.cpp \ @@ -13,7 +10,6 @@ common_src_files := \ fs/Vfat.cpp \ Loop.cpp \ Devmapper.cpp \ - ResponseCode.cpp \ CheckBattery.cpp \ Ext4Crypt.cpp \ VoldUtil.c \ diff --git a/Asec.h b/Asec.h deleted file mode 100644 index dd64fd0..0000000 --- a/Asec.h +++ /dev/null @@ -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 diff --git a/BenchmarkTask.cpp b/BenchmarkTask.cpp index 5ec249a..d10d792 100644 --- a/BenchmarkTask.cpp +++ b/BenchmarkTask.cpp @@ -17,7 +17,6 @@ #include "BenchmarkTask.h" #include "BenchmarkGen.h" #include "VolumeManager.h" -#include "ResponseCode.h" #include #include diff --git a/CommandListener.cpp b/CommandListener.cpp deleted file mode 100644 index a402ffa..0000000 --- a/CommandListener.cpp +++ /dev/null @@ -1,689 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOG_TAG "VoldCmdListener" - -#include -#include -#include -#include - -#include -#include - -#include "CommandListener.h" -#include "VolumeManager.h" -#include "model/VolumeBase.h" -#include "ResponseCode.h" -#include "Process.h" -#include "Loop.h" -#include "Devmapper.h" -#include "MoveTask.h" -#include "TrimTask.h" - -#define DUMP_ARGS 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 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, nullptr))->start(); - return sendGenericOkFail(cli, 0); - - } else if (cmd == "benchmark" && argc > 2) { - // benchmark [volId] - std::string id(argv[2]); - LOG(WARNING) << "Benchmarking has moved to Binder interface"; - nsecs_t res = 0; - 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 ", 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 " - "", 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 ", 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 ", 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 ", 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 ", 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 [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 ", 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 [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 ", 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 ", 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 ", 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 ", 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 [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 ", 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 lock(vm->getLock()); - - int flags = 0; - - std::string cmd(argv[1]); - if (cmd == "dotrim") { - flags = 0; - } else if (cmd == "dodtrim") { - flags = android::vold::TrimTask::Flags::kDeepTrim; - } else if (cmd == "dodtrimbench") { - flags = android::vold::TrimTask::Flags::kDeepTrim; - } - - (new android::vold::TrimTask(flags, nullptr))->start(); - return sendGenericOkFail(cli, 0); -} - - -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; - } - - VolumeManager *vm = VolumeManager::Instance(); - std::lock_guard lock(vm->getLock()); - - const std::string command(argv[1]); - if (command == "mount" && argc == 5) { - const uid_t uid = atoi(argv[2]); - const pid_t pid = atoi(argv[3]); - const int mountId = atoi(argv[4]); - - unique_fd device_fd; - int result = vm->mountAppFuse(uid, pid, mountId, &device_fd); - if (result != 0) { - return sendGenericOkFail(cli, result); - } else { - return sendFd(cli, device_fd.get()); - } - } else if (command == "unmount" && argc == 5) { - const uid_t uid = atoi(argv[2]); - const uid_t pid = atoi(argv[3]); - const int mountId = atoi(argv[4]); - - int result = vm->unmountAppFuse(uid, pid, mountId); - 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; -} diff --git a/CommandListener.h b/CommandListener.h deleted file mode 100644 index f858ac0..0000000 --- a/CommandListener.h +++ /dev/null @@ -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 -#include -#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 diff --git a/CryptCommandListener.cpp b/CryptCommandListener.cpp deleted file mode 100644 index 779338f..0000000 --- a/CryptCommandListener.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define LOG_TAG "VoldCryptCmdListener" - -#include -#include - -#include -#include -#include - -#include -#include - -#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, "")) 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 " - "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, "")) return 0; - SLOGD("cryptfs verifypw {}"); - rc = cryptfs_verify_passwd(argv[2]); - } else if (subcommand == "getfield") { - if (!check_argc(cli, subcommand, argc, 3, "")) 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, " ")) 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, " ")) 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, "")) 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, " ")) 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, "")) 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, " ")) 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, "")) 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, " ")) 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, " ")) 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, "")) 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; -} diff --git a/CryptCommandListener.h b/CryptCommandListener.h deleted file mode 100644 index 478ac02..0000000 --- a/CryptCommandListener.h +++ /dev/null @@ -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 -#include -#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 diff --git a/Devmapper.cpp b/Devmapper.cpp index c945e9f..ed498a3 100644 --- a/Devmapper.cpp +++ b/Devmapper.cpp @@ -34,7 +34,6 @@ #include #include -#include #include "Devmapper.h" @@ -44,82 +43,6 @@ using android::base::StringPrintf; static const char* kVoldPrefix = "vold:"; -int Devmapper::dumpState(SocketClient *c) { - - 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; -} - void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags) { memset(io, 0, dataSize); diff --git a/Devmapper.h b/Devmapper.h index dcc39d8..086ad78 100644 --- a/Devmapper.h +++ b/Devmapper.h @@ -20,8 +20,6 @@ #include #include -class SocketClient; - class Devmapper { public: static int create(const char *name, const char *loopFile, const char *key, @@ -29,7 +27,6 @@ public: static int destroy(const char *name); static int destroyAll(); static int lookupActive(const char *name, char *buffer, size_t len); - static int dumpState(SocketClient *c); private: static void *_align(void *ptr, unsigned int a); diff --git a/Loop.cpp b/Loop.cpp index 325b0d3..fc3909b 100644 --- a/Loop.cpp +++ b/Loop.cpp @@ -36,9 +36,7 @@ #include #include -#include #include "Loop.h" -#include "Asec.h" #include "VoldUtil.h" #include "sehandle.h" @@ -47,48 +45,6 @@ using android::base::unique_fd; static const char* kVoldPrefix = "vold:"; -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_raw, char *buffer, size_t len) { auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw); const char* id = id_string.c_str(); @@ -380,46 +336,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; -} diff --git a/Loop.h b/Loop.h index e3ad239..654b8ad 100644 --- a/Loop.h +++ b/Loop.h @@ -21,22 +21,17 @@ #include #include -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 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 diff --git a/MoveTask.cpp b/MoveTask.cpp index 8c0efac..4268ed4 100644 --- a/MoveTask.cpp +++ b/MoveTask.cpp @@ -17,7 +17,6 @@ #include "MoveTask.h" #include "Utils.h" #include "VolumeManager.h" -#include "ResponseCode.h" #include #include diff --git a/ResponseCode.cpp b/ResponseCode.cpp deleted file mode 100644 index d7e778d..0000000 --- a/ResponseCode.cpp +++ /dev/null @@ -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 -#include -#include - -#define LOG_TAG "Vold" - -#include - -#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); -} diff --git a/ResponseCode.h b/ResponseCode.h deleted file mode 100644 index f2c533e..0000000 --- a/ResponseCode.h +++ /dev/null @@ -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 diff --git a/TrimTask.cpp b/TrimTask.cpp index d37ec20..fafb345 100644 --- a/TrimTask.cpp +++ b/TrimTask.cpp @@ -17,7 +17,6 @@ #include "TrimTask.h" #include "Utils.h" #include "VolumeManager.h" -#include "ResponseCode.h" #include #include diff --git a/Utils.h b/Utils.h index 153c320..4e2be96 100644 --- a/Utils.h +++ b/Utils.h @@ -29,8 +29,6 @@ struct DIR; -#define ENABLE_BINDER 1 - namespace android { namespace vold { diff --git a/VoldCommand.cpp b/VoldCommand.cpp deleted file mode 100644 index 3c0d58d..0000000 --- a/VoldCommand.cpp +++ /dev/null @@ -1,21 +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 "VoldCommand.h" - -VoldCommand::VoldCommand(const char *cmd) : - FrameworkCommand(cmd) { -} diff --git a/VoldCommand.h b/VoldCommand.h deleted file mode 100644 index e435159..0000000 --- a/VoldCommand.h +++ /dev/null @@ -1,28 +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 _VOLD_COMMAND_H -#define _VOLD_COMMAND_H - -#include - -class VoldCommand : public FrameworkCommand { -public: - explicit VoldCommand(const char *cmd); - virtual ~VoldCommand() {} -}; - -#endif diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 6c25674..310610c 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -211,6 +211,20 @@ binder::Status VoldNativeService::setListener( 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; diff --git a/VoldNativeService.h b/VoldNativeService.h index a00010b..dd2b854 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -33,6 +33,7 @@ public: binder::Status setListener(const android::sp& listener); + binder::Status monitor(); binder::Status reset(); binder::Status shutdown(); binder::Status mountAll(); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 3150997..70f71f9 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -51,45 +51,18 @@ #include "model/ObbVolume.h" #include "VolumeManager.h" #include "NetlinkManager.h" -#include "ResponseCode.h" #include "Loop.h" #include "fs/Ext4.h" #include "fs/Vfat.h" #include "Utils.h" #include "Devmapper.h" #include "Process.h" -#include "Asec.h" #include "VoldUtil.h" #include "cryptfs.h" -#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file" - -#define ROUND_UP_POWER_OF_2(number, po2) (((!!((number) & ((1U << (po2)) - 1))) << (po2))\ - + ((number) & (~((1U << (po2)) - 1)))) - using android::base::StringPrintf; using android::base::unique_fd; -/* - * Path to external storage where *only* root can access ASEC image files - */ -const char *VolumeManager::SEC_ASECDIR_EXT = "/mnt/secure/asec"; - -/* - * Path to internal storage where *only* root can access ASEC image files - */ -const char *VolumeManager::SEC_ASECDIR_INT = "/data/app-asec"; - -/* - * Path to where secure containers are mounted - */ -const char *VolumeManager::ASECDIR = "/mnt/asec"; - -/* - * Path to where OBBs are mounted - */ -const char *VolumeManager::LOOPDIR = "/mnt/obb"; - bool VolumeManager::shutting_down = false; static const char* kPathUserMount = "/mnt/user"; @@ -104,107 +77,6 @@ static const unsigned int kMajorBlockMmc = 179; static const unsigned int kMajorBlockExperimentalMin = 240; static const unsigned int kMajorBlockExperimentalMax = 254; -/* writes superblock at end of file or device given by name */ -static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) { - int sbfd = open(name, O_RDWR | O_CLOEXEC); - if (sbfd < 0) { - SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno)); - return -1; - } - - if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) { - SLOGE("Failed to lseek for superblock (%s)", strerror(errno)); - close(sbfd); - return -1; - } - - if (write(sbfd, sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) { - SLOGE("Failed to write superblock (%s)", strerror(errno)); - close(sbfd); - return -1; - } - close(sbfd); - return 0; -} - -static unsigned long adjustSectorNumExt4(unsigned long numSectors) { - // Ext4 started to reserve 2% or 4096 clusters, whichever is smaller for - // preventing costly operations or unexpected ENOSPC error. - // Ext4::format() uses default block size without clustering. - unsigned long clusterSectors = 4096 / 512; - unsigned long reservedSectors = (numSectors * 2)/100 + (numSectors % 50 > 0); - numSectors += reservedSectors > (4096 * clusterSectors) ? (4096 * clusterSectors) : reservedSectors; - return ROUND_UP_POWER_OF_2(numSectors, 3); -} - -static unsigned long adjustSectorNumFAT(unsigned long numSectors) { - /* - * Add some headroom - */ - unsigned long fatSize = (((numSectors * 4) / 512) + 1) * 2; - numSectors += fatSize + 2; - /* - * FAT is aligned to 32 kb with 512b sectors. - */ - return ROUND_UP_POWER_OF_2(numSectors, 6); -} - -static int setupLoopDevice(char* buffer, size_t len, const char* asecFileName, const char* idHash, bool debug) { - if (Loop::lookupActive(idHash, buffer, len)) { - if (Loop::create(idHash, asecFileName, buffer, len)) { - SLOGE("ASEC loop device creation failed for %s (%s)", asecFileName, strerror(errno)); - return -1; - } - if (debug) { - SLOGD("New loop device created at %s", buffer); - } - } else { - if (debug) { - SLOGD("Found active loopback for %s at %s", asecFileName, buffer); - } - } - return 0; -} - -static int setupDevMapperDevice(char* buffer, size_t len, const char* loopDevice, const char* asecFileName, const char* key, const char* idHash , unsigned long numImgSectors, bool* createdDMDevice, bool debug) { - if (strcmp(key, "none")) { - if (Devmapper::lookupActive(idHash, buffer, len)) { - if (Devmapper::create(idHash, loopDevice, key, numImgSectors, - buffer, len)) { - SLOGE("ASEC device mapping failed for %s (%s)", asecFileName, strerror(errno)); - return -1; - } - if (debug) { - SLOGD("New devmapper instance created at %s", buffer); - } - } else { - if (debug) { - SLOGD("Found active devmapper for %s at %s", asecFileName, buffer); - } - } - *createdDMDevice = true; - } else { - strlcpy(buffer, loopDevice, len); - *createdDMDevice = false; - } - return 0; -} - -static void waitForDevMapper(const char *dmDevice) { - /* - * Wait for the device mapper node to be created. Sometimes it takes a - * while. Wait for up to 1 second. We could also inspect incoming uevents, - * but that would take more effort. - */ - int tries = 25; - while (tries--) { - if (!access(dmDevice, F_OK) || errno != ENOENT) { - break; - } - usleep(40 * 1000); - } -} - VolumeManager *VolumeManager::sInstance = NULL; VolumeManager *VolumeManager::Instance() { @@ -215,49 +87,10 @@ VolumeManager *VolumeManager::Instance() { VolumeManager::VolumeManager() { mDebug = false; - mActiveContainers = new AsecIdCollection(); - mBroadcaster = NULL; - mUmsSharingCount = 0; - mSavedDirtyRatio = -1; - // set dirty ratio to 0 when UMS is active - mUmsDirtyRatio = 0; mNextObbId = 0; } VolumeManager::~VolumeManager() { - delete mActiveContainers; -} - -char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) { - static const char* digits = "0123456789abcdef"; - - unsigned char sig[MD5_DIGEST_LENGTH]; - - if (buffer == NULL) { - SLOGE("Destination buffer is NULL"); - errno = ESPIPE; - return NULL; - } else if (id == NULL) { - SLOGE("Source buffer is NULL"); - errno = ESPIPE; - return NULL; - } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) { - SLOGE("Target hash buffer size < %d bytes (%zu)", - MD5_ASCII_LENGTH_PLUS_NULL, len); - errno = ESPIPE; - return NULL; - } - - MD5(reinterpret_cast(id), strlen(id), sig); - - char *p = buffer; - for (int i = 0; i < MD5_DIGEST_LENGTH; i++) { - *p++ = digits[sig[i] >> 4]; - *p++ = digits[sig[i] & 0x0F]; - } - *p = '\0'; - - return buffer; } int VolumeManager::updateVirtualDisk() { @@ -752,1197 +585,11 @@ int VolumeManager::unmountAll() { return 0; } -int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) { - char idHash[33]; - if (!asecHash(sourceFile, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno)); - return -1; - } - - memset(mountPath, 0, mountPathLen); - int written = snprintf(mountPath, mountPathLen, "%s/%s", VolumeManager::LOOPDIR, idHash); - if ((written < 0) || (written >= mountPathLen)) { - errno = EINVAL; - return -1; - } - - if (access(mountPath, F_OK)) { - errno = ENOENT; - return -1; - } - - return 0; -} - -int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) { - char asecFileName[255]; - - if (!isLegalAsecId(id)) { - SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("Couldn't find ASEC %s", id); - return -1; - } - - memset(buffer, 0, maxlen); - if (access(asecFileName, F_OK)) { - errno = ENOENT; - return -1; - } - - int written = snprintf(buffer, maxlen, "%s/%s", VolumeManager::ASECDIR, id); - if ((written < 0) || (written >= maxlen)) { - SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id); - errno = EINVAL; - return -1; - } - - return 0; -} - -int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) { - char asecFileName[255]; - - if (!isLegalAsecId(id)) { - SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("Couldn't find ASEC %s", id); - return -1; - } - - memset(buffer, 0, maxlen); - if (access(asecFileName, F_OK)) { - errno = ENOENT; - return -1; - } - - int written = snprintf(buffer, maxlen, "%s", asecFileName); - if ((written < 0) || (written >= maxlen)) { - errno = EINVAL; - return -1; - } - - return 0; -} - -int VolumeManager::createAsec(const char *id, unsigned long numSectors, const char *fstype, - const char *key, const int ownerUid, bool isExternal) { - struct asec_superblock sb; - memset(&sb, 0, sizeof(sb)); - - if (!isLegalAsecId(id)) { - SLOGE("createAsec: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - const bool wantFilesystem = strcmp(fstype, "none"); - bool usingExt4 = false; - if (wantFilesystem) { - usingExt4 = !strcmp(fstype, "ext4"); - if (usingExt4) { - sb.c_opts |= ASEC_SB_C_OPTS_EXT4; - } else if (strcmp(fstype, "fat")) { - SLOGE("Invalid filesystem type %s", fstype); - errno = EINVAL; - return -1; - } - } - - sb.magic = ASEC_SB_MAGIC; - sb.ver = ASEC_SB_VER; - - if (numSectors < ((1024*1024)/512)) { - SLOGE("Invalid container size specified (%lu sectors)", numSectors); - errno = EINVAL; - return -1; - } - - char asecFileName[255]; - - if (!findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)", - asecFileName, strerror(errno)); - errno = EADDRINUSE; - return -1; - } - - const char *asecDir = isExternal ? VolumeManager::SEC_ASECDIR_EXT : VolumeManager::SEC_ASECDIR_INT; - - int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id); - if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) { - errno = EINVAL; - return -1; - } - - if (!access(asecFileName, F_OK)) { - SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)", - asecFileName, strerror(errno)); - errno = EADDRINUSE; - return -1; - } - - unsigned long numImgSectors; - if (usingExt4) - numImgSectors = adjustSectorNumExt4(numSectors); - else - numImgSectors = adjustSectorNumFAT(numSectors); - - // Add +1 for our superblock which is at the end - if (Loop::createImageFile(asecFileName, numImgSectors + 1)) { - SLOGE("ASEC image file creation failed (%s)", strerror(errno)); - return -1; - } - - char idHash[33]; - if (!asecHash(id, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); - unlink(asecFileName); - return -1; - } - - char loopDevice[255]; - if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { - SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); - unlink(asecFileName); - return -1; - } - - char dmDevice[255]; - bool cleanupDm = false; - - if (strcmp(key, "none")) { - // XXX: This is all we support for now - sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH; - if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice, - sizeof(dmDevice))) { - SLOGE("ASEC device mapping failed (%s)", strerror(errno)); - Loop::destroyByDevice(loopDevice); - unlink(asecFileName); - return -1; - } - cleanupDm = true; - } else { - sb.c_cipher = ASEC_SB_C_CIPHER_NONE; - strlcpy(dmDevice, loopDevice, sizeof(dmDevice)); - } - - /* - * Drop down the superblock at the end of the file - */ - if (writeSuperBlock(loopDevice, &sb, numImgSectors)) { - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - unlink(asecFileName); - return -1; - } - - if (wantFilesystem) { - int formatStatus; - char mountPoint[255]; - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("ASEC fs format failed: couldn't construct mountPoint"); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - unlink(asecFileName); - return -1; - } - - if (usingExt4) { - formatStatus = android::vold::ext4::Format(dmDevice, numImgSectors, mountPoint); - } else { - formatStatus = android::vold::vfat::Format(dmDevice, numImgSectors); - } - - if (formatStatus < 0) { - SLOGE("ASEC fs format failed (%s)", strerror(errno)); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - unlink(asecFileName); - return -1; - } - - if (mkdir(mountPoint, 0000)) { - if (errno != EEXIST) { - SLOGE("Mountpoint creation failed (%s)", strerror(errno)); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - unlink(asecFileName); - return -1; - } - } - - int mountStatus; - if (usingExt4) { - mountStatus = android::vold::ext4::Mount(dmDevice, mountPoint, - false, false, false); - } else { - mountStatus = android::vold::vfat::Mount(dmDevice, mountPoint, - false, false, false, ownerUid, 0, 0000, false); - } - - if (mountStatus) { - SLOGE("ASEC FAT mount failed (%s)", strerror(errno)); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - unlink(asecFileName); - return -1; - } - - if (usingExt4) { - int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC); - if (dirfd >= 0) { - if (fchown(dirfd, ownerUid, AID_SYSTEM) - || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) { - SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint); - } - close(dirfd); - } - } - } else { - SLOGI("Created raw secure container %s (no filesystem)", id); - } - - mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); - return 0; -} - -int VolumeManager::resizeAsec(const char *id, unsigned long numSectors, const char *key) { - char asecFileName[255]; - char mountPoint[255]; - bool cleanupDm = false; - - if (!isLegalAsecId(id)) { - SLOGE("resizeAsec: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("Couldn't find ASEC %s", id); - return -1; - } - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("ASEC resize failed for %s: couldn't construct mountpoint", id); - return -1; - } - - if (isMountpointMounted(mountPoint)) { - SLOGE("ASEC %s mounted. Unmount before resizing", id); - errno = EBUSY; - return -1; - } - - struct asec_superblock sb; - int fd; - unsigned long oldNumSec = 0; - - if ((fd = open(asecFileName, O_RDONLY | O_CLOEXEC)) < 0) { - SLOGE("Failed to open ASEC file (%s)", strerror(errno)); - return -1; - } - - struct stat info; - if (fstat(fd, &info) < 0) { - SLOGE("Failed to get file size (%s)", strerror(errno)); - close(fd); - return -1; - } - - oldNumSec = info.st_size / 512; - - /* - * Try to read superblock. - */ - memset(&sb, 0, sizeof(struct asec_superblock)); - if (lseek(fd, ((oldNumSec - 1) * 512), SEEK_SET) < 0) { - SLOGE("lseek failed (%s)", strerror(errno)); - close(fd); - return -1; - } - if (read(fd, &sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) { - SLOGE("superblock read failed (%s)", strerror(errno)); - close(fd); - return -1; - } - close(fd); - - if (mDebug) { - SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); - } - if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { - SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver); - errno = EMEDIUMTYPE; - return -1; - } - - unsigned long numImgSectors; - if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) { - SLOGE("Only ext4 partitions are supported for resize"); - errno = EINVAL; - return -1; - } else { - numImgSectors = adjustSectorNumExt4(numSectors); - } - - /* - * add one block for the superblock - */ - SLOGD("Resizing from %lu sectors to %lu sectors", oldNumSec, numImgSectors + 1); - if (oldNumSec == numImgSectors + 1) { - SLOGW("Size unchanged; ignoring resize request"); - return 0; - } else if (oldNumSec > numImgSectors + 1) { - SLOGE("Only growing is currently supported."); - close(fd); - return -1; - } - - if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) { - SLOGE("Resize of ASEC image file failed. Could not resize %s", id); - return -1; - } - - /* - * Drop down a copy of the superblock at the end of the file - */ - if (writeSuperBlock(asecFileName, &sb, numImgSectors)) - goto fail; - - char idHash[33]; - if (!asecHash(id, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); - goto fail; - } - - char loopDevice[255]; - if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug)) - goto fail; - - char dmDevice[255]; - - if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash, numImgSectors, &cleanupDm, mDebug)) { - Loop::destroyByDevice(loopDevice); - goto fail; - } - - /* - * Wait for the device mapper node to be created. - */ - waitForDevMapper(dmDevice); - - if (android::vold::ext4::Resize(dmDevice, numImgSectors)) { - SLOGE("Unable to resize %s (%s)", id, strerror(errno)); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - goto fail; - } - - return 0; -fail: - Loop::resizeImageFile(asecFileName, oldNumSec); - return -1; -} - -int VolumeManager::finalizeAsec(const char *id) { - char asecFileName[255]; - char loopDevice[255]; - char mountPoint[255]; - - if (!isLegalAsecId(id)) { - SLOGE("finalizeAsec: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("Couldn't find ASEC %s", id); - return -1; - } - - char idHash[33]; - if (!asecHash(id, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); - return -1; - } - - if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { - SLOGE("Unable to finalize %s (%s)", id, strerror(errno)); - return -1; - } - - unsigned long nr_sec = 0; - struct asec_superblock sb; - - if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { - return -1; - } - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("ASEC finalize failed: couldn't construct mountPoint"); - return -1; - } - - int result = 0; - if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { - result = android::vold::ext4::Mount(loopDevice, mountPoint, - true, true, true); - } else { - result = android::vold::vfat::Mount(loopDevice, mountPoint, - true, true, true, 0, 0, 0227, false); - } - - if (result) { - SLOGE("ASEC finalize mount failed (%s)", strerror(errno)); - return -1; - } - - if (mDebug) { - SLOGD("ASEC %s finalized", id); - } - return 0; -} - -int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) { - char asecFileName[255]; - char loopDevice[255]; - char mountPoint[255]; - - if (gid < AID_APP) { - SLOGE("Group ID is not in application range"); - return -1; - } - - if (!isLegalAsecId(id)) { - SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("Couldn't find ASEC %s", id); - return -1; - } - - char idHash[33]; - if (!asecHash(id, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); - return -1; - } - - if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { - SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno)); - return -1; - } - - unsigned long nr_sec = 0; - struct asec_superblock sb; - - if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { - return -1; - } - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id); - return -1; - } - - int result = 0; - if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) { - return 0; - } - - int ret = android::vold::ext4::Mount(loopDevice, mountPoint, - false /* read-only */, - true /* remount */, - false /* executable */); - if (ret) { - SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno)); - return -1; - } - - char *paths[] = { mountPoint, NULL }; - - FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL); - if (fts) { - // Traverse the entire hierarchy and chown to system UID. - for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) { - // We don't care about the lost+found directory. - if (!strcmp(ftsent->fts_name, "lost+found")) { - continue; - } - - /* - * There can only be one file marked as private right now. - * This should be more robust, but it satisfies the requirements - * we have for right now. - */ - const bool privateFile = !strcmp(ftsent->fts_name, filename); - - int fd = open(ftsent->fts_accpath, O_NOFOLLOW | O_CLOEXEC); - if (fd < 0) { - SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno)); - result = -1; - continue; - } - - result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM); - - if (ftsent->fts_info & FTS_D) { - result |= fchmod(fd, 0755); - } else if (ftsent->fts_info & FTS_F) { - result |= fchmod(fd, privateFile ? 0640 : 0644); - } - - if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) { - SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno)); - result |= -1; - } - - close(fd); - } - fts_close(fts); - - // Finally make the directory readable by everyone. - int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC); - if (dirfd < 0 || fchmod(dirfd, 0755)) { - SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno)); - result |= -1; - } - close(dirfd); - } else { - result |= -1; - } - - result |= android::vold::ext4::Mount(loopDevice, mountPoint, - true /* read-only */, - true /* remount */, - true /* execute */); - - if (result) { - SLOGE("ASEC fix permissions failed (%s)", strerror(errno)); - return -1; - } - - if (mDebug) { - SLOGD("ASEC %s permissions fixed", id); - } - return 0; -} - -int VolumeManager::renameAsec(const char *id1, const char *id2) { - char asecFilename1[255]; - char *asecFilename2; - char mountPoint[255]; - - const char *dir; - - if (!isLegalAsecId(id1)) { - SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1); - errno = EINVAL; - return -1; - } - - if (!isLegalAsecId(id2)) { - SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2); - errno = EINVAL; - return -1; - } - - if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) { - SLOGE("Couldn't find ASEC %s", id1); - return -1; - } - - asprintf(&asecFilename2, "%s/%s.asec", dir, id2); - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id1); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("Rename failed: couldn't construct mountpoint"); - goto out_err; - } - - if (isMountpointMounted(mountPoint)) { - SLOGW("Rename attempt when src mounted"); - errno = EBUSY; - goto out_err; - } - - written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id2); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("Rename failed: couldn't construct mountpoint2"); - goto out_err; - } - - if (isMountpointMounted(mountPoint)) { - SLOGW("Rename attempt when dst mounted"); - errno = EBUSY; - goto out_err; - } - - if (!access(asecFilename2, F_OK)) { - SLOGE("Rename attempt when dst exists"); - errno = EADDRINUSE; - goto out_err; - } - - if (rename(asecFilename1, asecFilename2)) { - SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno)); - goto out_err; - } - - free(asecFilename2); - return 0; - -out_err: - free(asecFilename2); - return -1; -} - -#define UNMOUNT_RETRIES 5 -#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000) -int VolumeManager::unmountAsec(const char *id, bool force) { - char asecFileName[255]; - char mountPoint[255]; - - if (!isLegalAsecId(id)) { - SLOGE("unmountAsec: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("Couldn't find ASEC %s", id); - return -1; - } - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id); - return -1; - } - - char idHash[33]; - if (!asecHash(id, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); - return -1; - } - - return unmountLoopImage(id, idHash, asecFileName, mountPoint, force); -} - -int VolumeManager::unmountObb(const char *fileName, bool force) { - char mountPoint[255]; - - char idHash[33]; - if (!asecHash(fileName, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno)); - return -1; - } - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName); - return -1; - } - - return unmountLoopImage(fileName, idHash, fileName, mountPoint, force); -} - -int VolumeManager::unmountLoopImage(const char *id, const char *idHash, - const char *fileName, const char *mountPoint, bool force) { - if (!isMountpointMounted(mountPoint)) { - SLOGE("Unmount request for %s when not mounted", id); - errno = ENOENT; - return -1; - } - - int i, rc; - for (i = 1; i <= UNMOUNT_RETRIES; i++) { - rc = umount(mountPoint); - if (!rc) { - break; - } - if (rc && (errno == EINVAL || errno == ENOENT)) { - SLOGI("Container %s unmounted OK", id); - rc = 0; - break; - } - SLOGW("%s unmount attempt %d failed (%s)", - id, i, strerror(errno)); - - int signal = 0; // default is to just complain - - if (force) { - if (i > (UNMOUNT_RETRIES - 2)) - signal = SIGKILL; - else if (i > (UNMOUNT_RETRIES - 3)) - signal = SIGTERM; - } - - Process::killProcessesWithOpenFiles(mountPoint, signal); - usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); - } - - if (rc) { - errno = EBUSY; - SLOGE("Failed to unmount container %s (%s)", id, strerror(errno)); - return -1; - } - - int retries = 10; - - while(retries--) { - if (!rmdir(mountPoint)) { - break; - } - - SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno)); - usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); - } - - if (!retries) { - SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno)); - } - - for (i=1; i <= UNMOUNT_RETRIES; i++) { - if (Devmapper::destroy(idHash) && errno != ENXIO) { - SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno)); - usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); - continue; - } else { - break; - } - } - - char loopDevice[255]; - if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { - Loop::destroyByDevice(loopDevice); - } else { - SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno)); - } - - AsecIdCollection::iterator it; - for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) { - ContainerData* cd = *it; - if (!strcmp(cd->id, id)) { - free(*it); - mActiveContainers->erase(it); - break; - } - } - if (it == mActiveContainers->end()) { - SLOGW("mActiveContainers is inconsistent!"); - } - return 0; -} - -int VolumeManager::destroyAsec(const char *id, bool force) { - char asecFileName[255]; - char mountPoint[255]; - - if (!isLegalAsecId(id)) { - SLOGE("destroyAsec: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("Couldn't find ASEC %s", id); - return -1; - } - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id); - return -1; - } - - if (isMountpointMounted(mountPoint)) { - if (mDebug) { - SLOGD("Unmounting container before destroy"); - } - if (unmountAsec(id, force)) { - SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno)); - return -1; - } - } - - if (unlink(asecFileName)) { - SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno)); - return -1; - } - - if (mDebug) { - SLOGD("ASEC %s destroyed", id); - } - return 0; -} - -/* - * Legal ASEC ids consist of alphanumeric characters, '-', - * '_', or '.'. ".." is not allowed. The first or last character - * of the ASEC id cannot be '.' (dot). - */ -bool VolumeManager::isLegalAsecId(const char *id) const { - size_t i; - size_t len = strlen(id); - - if (len == 0) { - return false; - } - if ((id[0] == '.') || (id[len - 1] == '.')) { - return false; - } - - for (i = 0; i < len; i++) { - if (id[i] == '.') { - // i=0 is guaranteed never to have a dot. See above. - if (id[i-1] == '.') return false; - continue; - } - if (id[i] == '_' || id[i] == '-') continue; - if (id[i] >= 'a' && id[i] <= 'z') continue; - if (id[i] >= 'A' && id[i] <= 'Z') continue; - if (id[i] >= '0' && id[i] <= '9') continue; - return false; - } - - return true; -} - -bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const { - int dirfd = open(dir, O_DIRECTORY | O_CLOEXEC); - if (dirfd < 0) { - SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno)); - return false; - } - - struct stat sb; - bool ret = (fstatat(dirfd, asecName, &sb, AT_SYMLINK_NOFOLLOW) == 0) - && S_ISREG(sb.st_mode); - - close(dirfd); - - return ret; -} - -int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen, - const char **directory) const { - char *asecName; - - if (!isLegalAsecId(id)) { - SLOGE("findAsec: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (asprintf(&asecName, "%s.asec", id) < 0) { - SLOGE("Couldn't allocate string to write ASEC name"); - return -1; - } - - const char *dir; - if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_INT, asecName)) { - dir = VolumeManager::SEC_ASECDIR_INT; - } else if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_EXT, asecName)) { - dir = VolumeManager::SEC_ASECDIR_EXT; - } else { - free(asecName); - return -1; - } - - if (directory != NULL) { - *directory = dir; - } - - if (asecPath != NULL) { - int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName); - if ((written < 0) || (size_t(written) >= asecPathLen)) { - SLOGE("findAsec failed for %s: couldn't construct ASEC path", id); - free(asecName); - return -1; - } - } - - free(asecName); - return 0; -} - -int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool readOnly) { - char asecFileName[255]; - char mountPoint[255]; - - if (!isLegalAsecId(id)) { - SLOGE("mountAsec: Invalid asec id \"%s\"", id); - errno = EINVAL; - return -1; - } - - if (findAsec(id, asecFileName, sizeof(asecFileName))) { - SLOGE("Couldn't find ASEC %s", id); - return -1; - } - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id); - return -1; - } - - if (isMountpointMounted(mountPoint)) { - SLOGE("ASEC %s already mounted", id); - errno = EBUSY; - return -1; - } - - char idHash[33]; - if (!asecHash(id, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); - return -1; - } - - char loopDevice[255]; - if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug)) - return -1; - - char dmDevice[255]; - bool cleanupDm = false; - - unsigned long nr_sec = 0; - struct asec_superblock sb; - - if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { - return -1; - } - - if (mDebug) { - SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); - } - if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { - SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver); - Loop::destroyByDevice(loopDevice); - errno = EMEDIUMTYPE; - return -1; - } - nr_sec--; // We don't want the devmapping to extend onto our superblock - - if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash , nr_sec, &cleanupDm, mDebug)) { - Loop::destroyByDevice(loopDevice); - return -1; - } - - if (mkdir(mountPoint, 0000)) { - if (errno != EEXIST) { - SLOGE("Mountpoint creation failed (%s)", strerror(errno)); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - return -1; - } - } - - /* - * Wait for the device mapper node to be created. - */ - waitForDevMapper(dmDevice); - - int result; - if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { - result = android::vold::ext4::Mount(dmDevice, mountPoint, - readOnly, false, readOnly); - } else { - result = android::vold::vfat::Mount(dmDevice, mountPoint, - readOnly, false, readOnly, ownerUid, 0, 0222, false); - } - - if (result) { - SLOGE("ASEC mount failed (%s)", strerror(errno)); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - return -1; - } - - mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); - if (mDebug) { - SLOGD("ASEC %s mounted", id); - } - return 0; -} - -/** - * Mounts an image file img. - */ -int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) { - char mountPoint[255]; - - char idHash[33]; - if (!asecHash(img, idHash, sizeof(idHash))) { - SLOGE("Hash of '%s' failed (%s)", img, strerror(errno)); - return -1; - } - - int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash); - if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { - SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img); - return -1; - } - - if (isMountpointMounted(mountPoint)) { - SLOGE("Image %s already mounted", img); - errno = EBUSY; - return -1; - } - - char loopDevice[255]; - if (setupLoopDevice(loopDevice, sizeof(loopDevice), img, idHash, mDebug)) - return -1; - - char dmDevice[255]; - bool cleanupDm = false; - int fd; - unsigned long nr_sec = 0; - - if ((fd = open(loopDevice, O_RDWR | O_CLOEXEC)) < 0) { - SLOGE("Failed to open loopdevice (%s)", strerror(errno)); - Loop::destroyByDevice(loopDevice); - return -1; - } - - get_blkdev_size(fd, &nr_sec); - if (nr_sec == 0) { - SLOGE("Failed to get loop size (%s)", strerror(errno)); - Loop::destroyByDevice(loopDevice); - close(fd); - return -1; - } - - close(fd); - - if (setupDevMapperDevice(dmDevice, sizeof(loopDevice), loopDevice, img,key, idHash, nr_sec, &cleanupDm, mDebug)) { - Loop::destroyByDevice(loopDevice); - return -1; - } - - if (mkdir(mountPoint, 0755)) { - if (errno != EEXIST) { - SLOGE("Mountpoint creation failed (%s)", strerror(errno)); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - return -1; - } - } - - /* - * Wait for the device mapper node to be created. - */ - waitForDevMapper(dmDevice); - - if (android::vold::vfat::Mount(dmDevice, mountPoint, - true, false, true, 0, ownerGid, 0227, false)) { - SLOGE("Image mount failed (%s)", strerror(errno)); - if (cleanupDm) { - Devmapper::destroy(idHash); - } - Loop::destroyByDevice(loopDevice); - return -1; - } - - mActiveContainers->push_back(new ContainerData(strdup(img), OBB)); - if (mDebug) { - SLOGD("Image %s mounted", img); - } - return 0; -} - -int VolumeManager::listMountedObbs(SocketClient* cli) { - FILE *fp = setmntent("/proc/mounts", "r"); - if (fp == NULL) { - SLOGE("Error opening /proc/mounts (%s)", strerror(errno)); - return -1; - } - - // Create a string to compare against that has a trailing slash - int loopDirLen = strlen(VolumeManager::LOOPDIR); - char loopDir[loopDirLen + 2]; - strlcpy(loopDir, VolumeManager::LOOPDIR, sizeof(loopDir)); - loopDir[loopDirLen++] = '/'; - loopDir[loopDirLen] = '\0'; - - mntent* mentry; - while ((mentry = getmntent(fp)) != NULL) { - if (!strncmp(mentry->mnt_dir, loopDir, loopDirLen)) { - int fd = open(mentry->mnt_fsname, O_RDONLY | O_CLOEXEC); - if (fd >= 0) { - struct loop_info64 li; - if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) { - cli->sendMsg(ResponseCode::AsecListResult, - (const char*) li.lo_file_name, false); - } - close(fd); - } - } - } - endmntent(fp); - return 0; -} - extern "C" int vold_unmountAll(void) { VolumeManager *vm = VolumeManager::Instance(); return vm->unmountAll(); } -bool VolumeManager::isMountpointMounted(const char *mp) -{ - FILE *fp = setmntent("/proc/mounts", "r"); - if (fp == NULL) { - SLOGE("Error opening /proc/mounts (%s)", strerror(errno)); - return false; - } - - bool found_mp = false; - mntent* mentry; - while ((mentry = getmntent(fp)) != NULL) { - if (strcmp(mentry->mnt_dir, mp) == 0) { - found_mp = true; - break; - } - } - endmntent(fp); - return found_mp; -} - int VolumeManager::mkdirs(const char* path) { // Only offer to create directories for paths managed by vold if (strncmp(path, "/storage/", 9) == 0) { diff --git a/VolumeManager.h b/VolumeManager.h index a00520e..dcfbdad 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "android/os/IVoldListener.h" @@ -41,56 +40,18 @@ #include "model/Disk.h" #include "model/VolumeBase.h" -/* The length of an MD5 hash when encoded into ASCII hex characters */ -#define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1) - #define DEBUG_APPFUSE 0 -typedef enum { ASEC, OBB } container_type_t; - -class ContainerData { -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 AsecIdCollection; - 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(); @@ -150,52 +111,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 @@ -215,9 +135,6 @@ public: 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); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 1736829..d47f113 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -23,6 +23,7 @@ import android.os.IVoldTaskListener; interface IVold { void setListener(IVoldListener listener); + void monitor(); void reset(); void shutdown(); void mountAll(); diff --git a/main.cpp b/main.cpp index 8175dc5..37d02e7 100644 --- a/main.cpp +++ b/main.cpp @@ -16,8 +16,6 @@ #include "model/Disk.h" #include "VolumeManager.h" -#include "CommandListener.h" -#include "CryptCommandListener.h" #include "NetlinkManager.h" #include "VoldNativeService.h" #include "cryptfs.h" @@ -27,7 +25,6 @@ #include #include #include -#include #include #include @@ -62,8 +59,6 @@ int main(int argc, char** argv) { << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : ""); VolumeManager *vm; - CommandListener *cl; - CryptCommandListener *ccl; NetlinkManager *nm; parse_args(argc, argv); @@ -73,10 +68,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 */ @@ -97,11 +88,6 @@ int main(int argc, char** argv) { 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); @@ -124,19 +110,6 @@ int main(int argc, char** argv) { 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); - } - // 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"); diff --git a/model/Disk.cpp b/model/Disk.cpp index 151937f..f9799ad 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -20,7 +20,6 @@ #include "Utils.h" #include "VolumeBase.h" #include "VolumeManager.h" -#include "ResponseCode.h" #include "Ext4Crypt.h" #include @@ -151,12 +150,10 @@ void Disk::listVolumes(VolumeBase::Type type, std::list& list) { status_t Disk::create() { CHECK(!mCreated); mCreated = true; -#if ENABLE_BINDER + auto listener = VolumeManager::Instance()->getListener(); if (listener) listener->onDiskCreated(getId(), mFlags); -#else - notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags)); -#endif + readMetadata(); readPartitions(); return OK; @@ -166,12 +163,10 @@ status_t Disk::destroy() { CHECK(mCreated); destroyAllVolumes(); mCreated = false; -#if ENABLE_BINDER + auto listener = VolumeManager::Instance()->getListener(); if (listener) listener->onDiskDestroyed(getId()); -#else - notifyEvent(ResponseCode::DiskDestroyed); -#endif + return OK; } @@ -291,15 +286,10 @@ status_t Disk::readMetadata() { } } -#if ENABLE_BINDER auto listener = VolumeManager::Instance()->getListener(); if (listener) listener->onDiskMetadataChanged(getId(), mSize, mLabel, mSysPath); -#else - notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize)); - notifyEvent(ResponseCode::DiskLabelChanged, mLabel); - notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath); -#endif + return OK; } @@ -322,12 +312,10 @@ status_t Disk::readPartitions() { status_t res = ForkExecvp(cmd, output); if (res != OK) { LOG(WARNING) << "sgdisk failed to scan " << mDevPath; -#if ENABLE_BINDER + auto listener = VolumeManager::Instance()->getListener(); if (listener) listener->onDiskScanned(getId()); -#else - notifyEvent(ResponseCode::DiskScanned); -#endif + mJustPartitioned = false; return res; } @@ -393,12 +381,9 @@ status_t Disk::readPartitions() { } } -#if ENABLE_BINDER auto listener = VolumeManager::Instance()->getListener(); if (listener) listener->onDiskScanned(getId()); -#else - notifyEvent(ResponseCode::DiskScanned); -#endif + mJustPartitioned = false; return OK; } @@ -560,16 +545,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); diff --git a/model/Disk.h b/model/Disk.h index 77ec7df..63acf6a 100644 --- a/model/Disk.h +++ b/model/Disk.h @@ -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; diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index 9a96082..3152313 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -20,7 +20,6 @@ #include "EmulatedVolume.h" #include "Utils.h" #include "VolumeManager.h" -#include "ResponseCode.h" #include "cryptfs.h" #include @@ -55,14 +54,10 @@ PrivateVolume::~PrivateVolume() { status_t PrivateVolume::readMetadata() { status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel); -#if ENABLE_BINDER + auto listener = getListener(); if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel); -#else - notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType); - notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid); - notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel); -#endif + return res; } diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 04bafed..569203c 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -18,7 +18,6 @@ #include "PublicVolume.h" #include "Utils.h" #include "VolumeManager.h" -#include "ResponseCode.h" #include #include @@ -53,14 +52,10 @@ PublicVolume::~PublicVolume() { status_t PublicVolume::readMetadata() { status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel); -#if ENABLE_BINDER + auto listener = getListener(); if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel); -#else - notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType); - notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid); - notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel); -#endif + return res; } diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index b2eff3b..429f134 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -17,7 +17,6 @@ #include "Utils.h" #include "VolumeBase.h" #include "VolumeManager.h" -#include "ResponseCode.h" #include #include @@ -44,12 +43,9 @@ VolumeBase::~VolumeBase() { void VolumeBase::setState(State state) { mState = state; -#if ENABLE_BINDER + auto listener = getListener(); if (listener) listener->onVolumeStateChanged(getId(), static_cast(mState)); -#else - notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState)); -#endif } status_t VolumeBase::setDiskId(const std::string& diskId) { @@ -119,12 +115,10 @@ status_t VolumeBase::setPath(const std::string& path) { } mPath = path; -#if ENABLE_BINDER + auto listener = getListener(); if (listener) listener->onVolumePathChanged(getId(), mPath); -#else - notifyEvent(ResponseCode::VolumePathChanged, mPath); -#endif + return OK; } @@ -135,27 +129,13 @@ status_t VolumeBase::setInternalPath(const std::string& internalPath) { } mInternalPath = internalPath; -#if ENABLE_BINDER + auto listener = getListener(); if (listener) listener->onVolumeInternalPathChanged(getId(), mInternalPath); -#else - notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath); -#endif + 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 VolumeBase::getListener() { if (mSilent) { return nullptr; @@ -186,14 +166,11 @@ status_t VolumeBase::create() { mCreated = true; status_t res = doCreate(); -#if ENABLE_BINDER + auto listener = getListener(); if (listener) listener->onVolumeCreated(getId(), static_cast(mType), mDiskId, mPartGuid); -#else - notifyEvent(ResponseCode::VolumeCreated, - StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str())); -#endif + setState(State::kUnmounted); return res; } @@ -212,12 +189,10 @@ status_t VolumeBase::destroy() { setState(State::kRemoved); } -#if ENABLE_BINDER + auto listener = getListener(); if (listener) listener->onVolumeDestroyed(getId()); -#else - notifyEvent(ResponseCode::VolumeDestroyed); -#endif + status_t res = doDestroy(); mCreated = false; return res; diff --git a/model/VolumeBase.h b/model/VolumeBase.h index ac111c2..4aa8b02 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -115,9 +115,6 @@ 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 getListener(); private: diff --git a/tests/VolumeManager_test.cpp b/tests/VolumeManager_test.cpp index c0c1fa5..f661d49 100644 --- a/tests/VolumeManager_test.cpp +++ b/tests/VolumeManager_test.cpp @@ -34,31 +34,4 @@ protected: } }; -TEST_F(VolumeManagerTest, AsecHashTests) { - char buffer[MD5_ASCII_LENGTH_PLUS_NULL]; - char* dst = reinterpret_cast(&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"; -} - } diff --git a/vdc.cpp b/vdc.cpp index 3a38641..b249987 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -36,23 +35,13 @@ #include #include -#include #include -#define ENABLE_BINDER 1 - static void usage(char *progname); -#if !ENABLE_BINDER -static int do_monitor(int sock, int stop_after_cmd); -static int do_cmd(int sock, int argc, char **argv); -#endif - -static constexpr int kCommandTimeoutMs = 20 * 1000; - int main(int argc, char **argv) { int sock; - int wait_for_socket; + int wait; char *progname; progname = argv[0]; @@ -64,8 +53,8 @@ int main(int argc, char **argv) { android::base::InitLogging(argv, &android::base::StderrLogger); } - wait_for_socket = argc > 1 && strcmp(argv[1], "--wait") == 0; - if (wait_for_socket) { + wait = argc > 1 && strcmp(argv[1], "--wait") == 0; + if (wait) { argv++; argc--; } @@ -75,7 +64,6 @@ int main(int argc, char **argv) { exit(5); } -#if ENABLE_BINDER std::string arg1 = argv[1]; std::string arg2 = argv[2]; @@ -102,119 +90,8 @@ int main(int argc, char **argv) { LOG(ERROR) << "Raw commands are no longer supported"; exit(EINVAL); } -#else - const char* sockname = "vold"; - if (!strcmp(argv[1], "cryptfs")) { - sockname = "cryptd"; - } - - 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)); - } else { - exit(do_cmd(sock, argc, argv)); - } -#endif } -#if !ENABLE_BINDER -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; -} -#endif - static void usage(char *progname) { LOG(INFO) << "Usage: " << progname << " [--wait] | [arg1] [arg2...]"; } diff --git a/vold.rc b/vold.rc index 87e2fd8..c27aeda 100644 --- a/vold.rc +++ b/vold.rc @@ -2,9 +2,6 @@ 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 - From 95440ebd97ef6a0d24920803af62dd3eefa0f7b7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 18 Sep 2017 18:19:28 -0600 Subject: [PATCH 015/106] Enable "cert-err34-c" tidy checks. Now that we've moved to Binder, we only have a few lingering atoi() usages that are cleaned up in this CL. Rewrite match_multi_entry() entirely, with tests to verify both old and new implementations. Test: adb shell /data/nativetest/vold_tests/vold_tests Bug: 36655947 Change-Id: Ib79dc1ddc2366db4d5b4e1a1e2ed9456a06a983e --- Android.mk | 3 +-- Ext4Crypt.cpp | 2 +- VolumeManager.cpp | 4 ++-- cryptfs.cpp | 39 +++++++++++++----------------- cryptfs.h | 1 + model/Disk.cpp | 4 ++-- tests/Android.mk | 5 +++- tests/cryptfs_test.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 81 insertions(+), 31 deletions(-) create mode 100644 tests/cryptfs_test.cpp diff --git a/Android.mk b/Android.mk index 5957df7..4d812b7 100644 --- a/Android.mk +++ b/Android.mk @@ -82,11 +82,10 @@ common_static_libraries := \ libbatteryservice \ libavb \ -# TODO: include "cert-err34-c" once we move to Binder # TODO: include "cert-err58-cpp" once 36656327 is fixed common_local_tidy_enabled := true common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-* -common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err34-c,-cert-err58-cpp +common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err58-cpp vold_conlyflags := -std=c11 vold_cflags := -Werror -Wall -Wno-missing-field-initializers -Wno-unused-variable -Wno-unused-parameter diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index dc2e42a..3ac6428 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -304,7 +304,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; diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 70f71f9..6bed2bf 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -189,8 +189,8 @@ void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { if (devType != "disk") return; - int major = atoi(evt->findParam("MAJOR")); - int minor = atoi(evt->findParam("MINOR")); + int major = std::stoi(evt->findParam("MAJOR")); + int minor = std::stoi(evt->findParam("MINOR")); dev_t device = makedev(major, minor); switch (evt->getAction()) { diff --git a/cryptfs.cpp b/cryptfs.cpp index adfb284..132b31f 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1419,7 +1419,7 @@ static int cryptfs_restart_internal(int restart_main) */ char ro_prop[PROPERTY_VALUE_MAX]; property_get("ro.crypto.readonly", ro_prop, ""); - if (strlen(ro_prop) > 0 && atoi(ro_prop)) { + if (strlen(ro_prop) > 0 && std::stoi(ro_prop)) { struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); rec->flags |= MS_RDONLY; } @@ -2553,30 +2553,23 @@ static int persist_set_key(const char *fieldname, const char *value, int encrypt * Test if key is part of the multi-entry (field, index) sequence. Return non-zero if key is in the * sequence and its index is greater than or equal to index. Return 0 otherwise. */ -static int match_multi_entry(const char *key, const char *field, unsigned index) { - unsigned int field_len; - unsigned int key_index; - field_len = strlen(field); +int match_multi_entry(const char *key, const char *field, unsigned index) { + std::string key_ = key; + std::string field_ = field; - if (index == 0) { - // The first key in a multi-entry field is just the filedname itself. - if (!strcmp(key, field)) { - return 1; - } + std::string parsed_field; + unsigned parsed_index; + + std::string::size_type split = key_.find_last_of('_'); + if (split == std::string::npos) { + parsed_field = key_; + parsed_index = 0; + } else { + parsed_field = key_.substr(0, split); + parsed_index = std::stoi(key_.substr(split + 1)); } - // Match key against "%s_%d" % (field, index) - if (strlen(key) < field_len + 1 + 1) { - // Need at least a '_' and a digit. - return 0; - } - if (strncmp(key, field, field_len)) { - // If the key does not begin with field, it's not a match. - return 0; - } - if (1 != sscanf(&key[field_len],"_%d", &key_index)) { - return 0; - } - return key_index >= index; + + return parsed_field == field_ && parsed_index >= index; } /* diff --git a/cryptfs.h b/cryptfs.h index a7b650f..2169f54 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -222,6 +222,7 @@ struct crypt_persist_data { extern "C" { #endif + int match_multi_entry(const char *key, const char *field, unsigned index); int wait_and_unmount(const char *mountpoint, bool kill); typedef int (*kdf_func)(const char *passwd, const unsigned char *salt, diff --git a/model/Disk.cpp b/model/Disk.cpp index f9799ad..c889a35 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -555,7 +555,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: @@ -571,7 +571,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)) { diff --git a/tests/Android.mk b/tests/Android.mk index 9cebd1a..3127352 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -10,7 +10,10 @@ LOCAL_C_INCLUDES := \ LOCAL_STATIC_LIBRARIES := libbase libselinux libvold liblog libcrypto -LOCAL_SRC_FILES := VolumeManager_test.cpp +LOCAL_SRC_FILES := \ + cryptfs_test.cpp \ + VolumeManager_test.cpp \ + LOCAL_MODULE := vold_tests LOCAL_MODULE_TAGS := eng tests diff --git a/tests/cryptfs_test.cpp b/tests/cryptfs_test.cpp new file mode 100644 index 0000000..6875c0f --- /dev/null +++ b/tests/cryptfs_test.cpp @@ -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 + +#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)); +} + +} From 67b8c4953051cb14d0333856a057e5acba273d0e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 21 Sep 2017 17:08:43 -0600 Subject: [PATCH 016/106] Make Loop::destroyAll() smarter. Instead of blindly looping across 4096 possible devices, use readdir() to only look at valid devices. This speeds up destroyAll() from 40ms to 0.7ms. Add tracing information in several places. Test: external/chromium-trace/systrace.py -b 128768 sched freq am pm ss core_services binder_driver -a system_server,installd,vold Bug: 65634729, 65737446 Change-Id: If581de47fb55850c0fcd6e25bf33ed246e1b079d --- Devmapper.cpp | 4 ++++ Loop.cpp | 23 +++++++++++++++++++++-- VoldNativeService.cpp | 9 +++++++-- VolumeManager.cpp | 7 +++++++ main.cpp | 15 +++++++++++++++ 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/Devmapper.cpp b/Devmapper.cpp index ed498a3..2cbed86 100644 --- a/Devmapper.cpp +++ b/Devmapper.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER + #include #include #include @@ -34,6 +36,7 @@ #include #include +#include #include "Devmapper.h" @@ -233,6 +236,7 @@ int Devmapper::destroy(const char *name_raw) { } int Devmapper::destroyAll() { + ATRACE_NAME("Devmapper::destroyAll"); char *buffer = (char *) malloc(1024 * 64); if (!buffer) { SLOGE("Error allocating memory (%s)", strerror(errno)); diff --git a/Loop.cpp b/Loop.cpp index fc3909b..1eb9865 100644 --- a/Loop.cpp +++ b/Loop.cpp @@ -14,8 +14,11 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER + #include #include +#include #include #include #include @@ -35,6 +38,7 @@ #include #include #include +#include #include "Loop.h" #include "VoldUtil.h" @@ -262,9 +266,22 @@ int Loop::destroyByDevice(const char *loopDevice) { } int Loop::destroyAll() { - for (int i = 0; i < LOOP_MAX; i++) { - auto path = StringPrintf("/dev/block/loop%d", i); + ATRACE_NAME("Loop::destroyAll"); + DIR* dir; + struct dirent* de; + + std::string root = "/dev/block/"; + if (!(dir = opendir(root.c_str()))) { + PLOG(ERROR) << "Failed to opendir"; + return -1; + } + + // Poke through all devices looking for loops + while ((de = readdir(dir))) { + if (strncmp(de->d_name, "loop", 4) != 0) 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) { @@ -290,6 +307,8 @@ int Loop::destroyAll() { LOG(VERBOSE) << "Found unmanaged loop device at " << path << " named " << id; } } + + closedir(dir); return 0; } diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 310610c..049f5ba 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER + #include "VoldNativeService.h" #include "VolumeManager.h" #include "BenchmarkTask.h" @@ -32,6 +34,7 @@ #include #include #include +#include #ifndef LOG_TAG #define LOG_TAG "vold" @@ -169,10 +172,12 @@ binder::Status checkArgumentHex(const std::string& hex) { } #define ACQUIRE_LOCK \ - std::lock_guard lock(VolumeManager::Instance()->getLock()); + std::lock_guard lock(VolumeManager::Instance()->getLock()); \ + ATRACE_CALL(); #define ACQUIRE_CRYPT_LOCK \ - std::lock_guard lock(VolumeManager::Instance()->getCryptLock()); + std::lock_guard lock(VolumeManager::Instance()->getCryptLock()); \ + ATRACE_CALL(); } // namespace diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 70f71f9..e96b7ac 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER + #include #include #include @@ -40,6 +42,7 @@ #include #include #include +#include #include @@ -94,6 +97,7 @@ VolumeManager::~VolumeManager() { } int VolumeManager::updateVirtualDisk() { + ATRACE_NAME("VolumeManager::updateVirtualDisk"); if (property_get_bool(kPropVirtualDisk, false)) { if (access(kPathVirtualDisk, F_OK) != 0) { Loop::createImageFile(kPathVirtualDisk, kSizeVirtualDisk / 512); @@ -148,6 +152,8 @@ int VolumeManager::setDebug(bool enable) { } int VolumeManager::start() { + ATRACE_NAME("VolumeManager::start"); + // Always start from a clean slate by unmounting everything in // directories that we own, in case we crashed. unmountAll(); @@ -548,6 +554,7 @@ int VolumeManager::shutdown() { int VolumeManager::unmountAll() { std::lock_guard lock(mLock); + ATRACE_NAME("VolumeManager::unmountAll()"); // First, try gracefully unmounting all known devices if (mInternalEmulated != nullptr) { diff --git a/main.cpp b/main.cpp index 37d02e7..f317f3d 100644 --- a/main.cpp +++ b/main.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER + #include "model/Disk.h" #include "VolumeManager.h" #include "NetlinkManager.h" @@ -25,6 +27,7 @@ #include #include #include +#include #include #include @@ -51,6 +54,8 @@ int main(int argc, char** argv) { setenv("ANDROID_LOG_TAGS", "*:v", 1); android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); + ATRACE_BEGIN("main"); + LOG(INFO) << "Vold 3.0 (the awakening) firing up"; LOG(VERBOSE) << "Detected support for:" @@ -93,10 +98,12 @@ int main(int argc, char** argv) { exit(1); } + ATRACE_BEGIN("VoldNativeService::start"); if (android::vold::VoldNativeService::start() != android::OK) { LOG(ERROR) << "Unable to start VoldNativeService"; exit(1); } + ATRACE_END(); bool has_adoptable; bool has_quota; @@ -105,10 +112,12 @@ int main(int argc, char** argv) { PLOG(ERROR) << "Error reading configuration... continuing anyways"; } + ATRACE_BEGIN("NetlinkManager::start"); if (nm->start()) { PLOG(ERROR) << "Unable to start NetlinkManager"; 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) @@ -119,6 +128,9 @@ int main(int argc, char** argv) { // also the cold boot is needed in case we have flash drive // connected before Vold launched coldboot("/sys/block"); + + ATRACE_END(); + // Eventually we'll become the monitoring thread while(1) { pause(); @@ -188,6 +200,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); @@ -196,6 +209,8 @@ static void coldboot(const char *path) { } static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota) { + ATRACE_NAME("process_config"); + fstab = fs_mgr_read_fstab_default(); if (!fstab) { PLOG(ERROR) << "Failed to open default fstab"; From 4a53a9edb306d292fe9f1d32801bfd4673801b2f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 21 Sep 2017 18:20:45 -0600 Subject: [PATCH 017/106] Be more aggressive about obtaining vold service. vdc is typically invoked very early during boot, where it races with vold starting up. The default getService() implementation waits a whole second between retrying, so write a local getServiceAggressive() that only waits 10ms between attempts. Test: builds, boots Bug: 65737446 Change-Id: I581db3afcf7f81dd7cd9cc84dc03194759861669 --- vdc.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/vdc.cpp b/vdc.cpp index 4eb988d..4e0c3a9 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -39,6 +39,21 @@ static void usage(char *progname); +static android::sp getServiceAggressive() { + android::sp res; + auto sm = android::defaultServiceManager(); + auto name = android::String16("vold"); + for (int i = 0; i < 500; 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; @@ -46,6 +61,7 @@ int main(int argc, char **argv) { progname = argv[0]; + 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); @@ -67,8 +83,7 @@ int main(int argc, char **argv) { std::string arg1 = argv[1]; std::string arg2 = argv[2]; - android::sp binder = android::defaultServiceManager()->getService( - android::String16("vold")); + android::sp binder = getServiceAggressive(); if (!binder) { LOG(ERROR) << "Failed to obtain vold Binder"; exit(EINVAL); From 5687066dcc819729338df723ea0dc6ed7915e4a2 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 25 Sep 2017 23:21:24 +0000 Subject: [PATCH 018/106] Revert "Be more aggressive about obtaining vold service." This reverts commit 4a53a9edb306d292fe9f1d32801bfd4673801b2f. Change-Id: Ie4058488226bf53b78063dd3feb011dbd0167d1e --- vdc.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/vdc.cpp b/vdc.cpp index 4e0c3a9..4eb988d 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -39,21 +39,6 @@ static void usage(char *progname); -static android::sp getServiceAggressive() { - android::sp res; - auto sm = android::defaultServiceManager(); - auto name = android::String16("vold"); - for (int i = 0; i < 500; 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; @@ -61,7 +46,6 @@ int main(int argc, char **argv) { progname = argv[0]; - 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); @@ -83,7 +67,8 @@ int main(int argc, char **argv) { std::string arg1 = argv[1]; std::string arg2 = argv[2]; - android::sp binder = getServiceAggressive(); + android::sp binder = android::defaultServiceManager()->getService( + android::String16("vold")); if (!binder) { LOG(ERROR) << "Failed to obtain vold Binder"; exit(EINVAL); From e2ee152e4641a6d59ab702ac2a7bd41be57089e1 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Tue, 26 Sep 2017 14:05:26 -0700 Subject: [PATCH 019/106] Refactor of use of fstab in advance of fix. Test: Ensure device still boots. Bug: 65737446 Change-Id: Ie466db9f5d8c77656cc525c0d49fe6a3cce154f1 --- Android.mk | 2 +- MetadataCrypt.cpp | 9 ++++----- VoldUtil.c => VoldUtil.cpp | 2 ++ VoldUtil.h | 5 +++-- cryptfs.cpp | 24 +++++++++++------------- main.cpp | 24 ++++++++++++------------ 6 files changed, 33 insertions(+), 33 deletions(-) rename VoldUtil.c => VoldUtil.cpp (96%) diff --git a/Android.mk b/Android.mk index 4d812b7..dae747e 100644 --- a/Android.mk +++ b/Android.mk @@ -12,7 +12,7 @@ common_src_files := \ Devmapper.cpp \ CheckBattery.cpp \ Ext4Crypt.cpp \ - VoldUtil.c \ + VoldUtil.cpp \ cryptfs.cpp \ model/Disk.cpp \ model/VolumeBase.cpp \ diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 8311813..24047f9 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -42,7 +42,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 +57,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(mount_point), + auto mount_rc = fs_mgr_do_mount(fstab_default, const_cast(mount_point), const_cast(blk_device), nullptr); if (setexeccon(nullptr)) { PLOG(ERROR) << "Failed to clear setexeccon"; @@ -73,7 +72,7 @@ static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) { } static bool read_key(bool create_if_absent, KeyBuffer* key) { - auto data_rec = fs_mgr_get_crypt_entry(fstab); + auto data_rec = fs_mgr_get_crypt_entry(fstab_default); if (!data_rec) { LOG(ERROR) << "Failed to get data_rec"; return false; @@ -253,7 +252,7 @@ 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); + auto data_rec = fs_mgr_get_crypt_entry(fstab_default); if (!data_rec) { LOG(ERROR) << "Failed to get data_rec"; return false; @@ -283,7 +282,7 @@ bool e4crypt_enable_crypto() { 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_crypt_entry(fstab_default); if (!data_rec) { LOG(ERROR) << "Failed to get data_rec"; return false; diff --git a/VoldUtil.c b/VoldUtil.cpp similarity index 96% rename from VoldUtil.c rename to VoldUtil.cpp index e5bc912..afe8b53 100644 --- a/VoldUtil.c +++ b/VoldUtil.cpp @@ -17,6 +17,8 @@ #include #include +struct fstab *fstab_default; + void get_blkdev_size(int fd, unsigned long* nr_sec) { if ((ioctl(fd, BLKGETSIZE, nr_sec)) == -1) { *nr_sec = 0; diff --git a/VoldUtil.h b/VoldUtil.h index 5738382..fd66672 100644 --- a/VoldUtil.h +++ b/VoldUtil.h @@ -17,12 +17,13 @@ #ifndef _VOLDUTIL_H #define _VOLDUTIL_H +#include #include +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 diff --git a/cryptfs.cpp b/cryptfs.cpp index 132b31f..40b1e07 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -191,8 +191,6 @@ static char* password = 0; static int password_expiry_time = 0; static const int password_max_age_seconds = 60; -extern struct fstab *fstab; - enum class RebootType {reboot, recovery, shutdown}; static void cryptfs_reboot(RebootType rt) { @@ -295,7 +293,7 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off) int rc = -1; if (!cached_data) { - fs_mgr_get_crypt_info(fstab, key_loc, real_blkdev, sizeof(key_loc)); + fs_mgr_get_crypt_info(fstab_default, key_loc, real_blkdev, sizeof(key_loc)); if (!strcmp(key_loc, KEY_IN_FOOTER)) { if ( (fd = open(real_blkdev, O_RDWR|O_CLOEXEC)) < 0) { @@ -1420,7 +1418,7 @@ static int cryptfs_restart_internal(int restart_main) char ro_prop[PROPERTY_VALUE_MAX]; property_get("ro.crypto.readonly", ro_prop, ""); if (strlen(ro_prop) > 0 && std::stoi(ro_prop)) { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); + struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT); rec->flags |= MS_RDONLY; } @@ -1436,7 +1434,7 @@ static int cryptfs_restart_internal(int restart_main) SLOGE("Failed to setexeccon"); return -1; } - while ((mount_rc = fs_mgr_do_mount(fstab, DATA_MNT_POINT, + while ((mount_rc = fs_mgr_do_mount(fstab_default, DATA_MNT_POINT, crypto_blkdev, 0)) != 0) { if (mount_rc == FS_MGR_DOMNT_BUSY) { @@ -1517,7 +1515,7 @@ static int do_crypto_complete(const char *mount_point) } if (get_crypt_ftr_and_key(&crypt_ftr)) { - fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc)); + fs_mgr_get_crypt_info(fstab_default, key_loc, 0, sizeof(key_loc)); /* * Only report this error if key_loc is a file and it exists. @@ -1585,7 +1583,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, } } - fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev)); + fs_mgr_get_crypt_info(fstab_default, 0, real_blkdev, sizeof(real_blkdev)); // Create crypto block device - all (non fatal) code paths // need it @@ -1617,7 +1615,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, snprintf(tmp_mount_point, sizeof(tmp_mount_point), "%s/tmp_mnt", mount_point); mkdir(tmp_mount_point, 0755); - if (fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) { + if (fs_mgr_do_mount(fstab_default, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) { SLOGE("Error temp mounting decrypted block device\n"); delete_crypto_blk_dev(label); @@ -2021,7 +2019,7 @@ static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how, tot_encryption_size = crypt_ftr->fs_size; if (how == CRYPTO_ENABLE_WIPE) { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); + struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT); int fs_type = get_fs_type(rec); if (fs_type < 0) { SLOGE("cryptfs_enable: unsupported fs type %s\n", rec->fs_type); @@ -2121,8 +2119,8 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass } // TODO refactor fs_mgr_get_crypt_info to get both in one call - fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc)); - fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev)); + fs_mgr_get_crypt_info(fstab_default, key_loc, 0, sizeof(key_loc)); + fs_mgr_get_crypt_info(fstab_default, 0, real_blkdev, sizeof(real_blkdev)); /* Get the size of the real block device */ fd = open(real_blkdev, O_RDONLY|O_CLOEXEC); @@ -2870,7 +2868,7 @@ void cryptfs_clear_password() int cryptfs_isConvertibleToFBE() { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); + struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT); return fs_mgr_is_convertible_to_fbe(rec) ? 1 : 0; } @@ -2943,6 +2941,6 @@ int cryptfs_set_password(struct crypt_mnt_ftr* ftr, const char* password, void cryptfs_get_file_encryption_modes(const char **contents_mode_ret, const char **filenames_mode_ret) { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); + struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT); fs_mgr_get_file_encryption_modes(rec, contents_mode_ret, filenames_mode_ret); } diff --git a/main.cpp b/main.cpp index f317f3d..1bb7639 100644 --- a/main.cpp +++ b/main.cpp @@ -20,6 +20,7 @@ #include "VolumeManager.h" #include "NetlinkManager.h" #include "VoldNativeService.h" +#include "VoldUtil.h" #include "cryptfs.h" #include "sehandle.h" @@ -44,8 +45,6 @@ static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quot 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; @@ -211,8 +210,8 @@ static void coldboot(const char *path) { static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota) { ATRACE_NAME("process_config"); - fstab = fs_mgr_read_fstab_default(); - if (!fstab) { + fstab_default = fs_mgr_read_fstab_default(); + if (!fstab_default) { PLOG(ERROR) << "Failed to open default fstab"; return -1; } @@ -220,26 +219,27 @@ 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])) { + 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 (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]) + if (fs_mgr_is_noemulatedsd(rec) || property_get_bool("vold.debug.default_primary", false)) { flags |= android::vold::Disk::Flags::kDefaultPrimary; } From 3188805e357197e171b239565f06b95f6a3ca51c Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Wed, 27 Sep 2017 10:56:54 -0700 Subject: [PATCH 020/106] Read the configuration before starting the native service. Bug: 66739076 Bug: 65737446 Test: reboot-cycle.sh doesn't show a problem. Change-Id: Ia0699cca7e07475d4df266b482a3b2c96519ed3b --- main.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/main.cpp b/main.cpp index 1bb7639..30f60a1 100644 --- a/main.cpp +++ b/main.cpp @@ -97,13 +97,6 @@ int main(int argc, char** argv) { exit(1); } - ATRACE_BEGIN("VoldNativeService::start"); - if (android::vold::VoldNativeService::start() != android::OK) { - LOG(ERROR) << "Unable to start VoldNativeService"; - exit(1); - } - ATRACE_END(); - bool has_adoptable; bool has_quota; @@ -111,6 +104,13 @@ int main(int argc, char** argv) { 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(); + ATRACE_BEGIN("NetlinkManager::start"); if (nm->start()) { PLOG(ERROR) << "Unable to start NetlinkManager"; From 3c3e3605460c54b7dd5733f60bb210d9c9858cad Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Wed, 27 Sep 2017 16:44:33 +0000 Subject: [PATCH 021/106] Revert "Revert "Be more aggressive about obtaining vold service."" This reverts commit 5687066dcc819729338df723ea0dc6ed7915e4a2. Reason for revert: ag/2966951 fixes the underlying problem. Bug: 66739076 Bug: 65737446 Test: reboot-cycle.sh doesn't show a problem. Change-Id: If4b9c5cc39e9e905d2b1e78f091609be641fc22a --- vdc.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/vdc.cpp b/vdc.cpp index 4eb988d..4e0c3a9 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -39,6 +39,21 @@ static void usage(char *progname); +static android::sp getServiceAggressive() { + android::sp res; + auto sm = android::defaultServiceManager(); + auto name = android::String16("vold"); + for (int i = 0; i < 500; 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; @@ -46,6 +61,7 @@ int main(int argc, char **argv) { progname = argv[0]; + 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); @@ -67,8 +83,7 @@ int main(int argc, char **argv) { std::string arg1 = argv[1]; std::string arg2 = argv[2]; - android::sp binder = android::defaultServiceManager()->getService( - android::String16("vold")); + android::sp binder = getServiceAggressive(); if (!binder) { LOG(ERROR) << "Failed to obtain vold Binder"; exit(EINVAL); From 5385417922a51499beb10f3f6e3e5e7df9c9bb5e Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 2 Oct 2017 16:18:56 -0700 Subject: [PATCH 022/106] Remove CheckBattery altogether Test: changed Angler fstab to encryptable and encrypted. Bug: 16868177 Change-Id: I17d36ea838d6d96f0752b2d6d03b1f9a781ed018 --- Android.mk | 1 - CheckBattery.cpp | 33 --------------------------------- CheckBattery.h | 31 ------------------------------- EncryptInplace.cpp | 15 --------------- cryptfs.cpp | 6 ------ 5 files changed, 86 deletions(-) delete mode 100644 CheckBattery.cpp delete mode 100644 CheckBattery.h diff --git a/Android.mk b/Android.mk index f59ac76..e22bf0f 100644 --- a/Android.mk +++ b/Android.mk @@ -10,7 +10,6 @@ common_src_files := \ fs/Vfat.cpp \ Loop.cpp \ Devmapper.cpp \ - CheckBattery.cpp \ Ext4Crypt.cpp \ VoldUtil.cpp \ cryptfs.cpp \ diff --git a/CheckBattery.cpp b/CheckBattery.cpp deleted file mode 100644 index 27b3b0b..0000000 --- a/CheckBattery.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2014 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 LOG_TAG "VoldCheckBattery" -#include - -extern "C" -{ - int is_battery_ok_to_start() - { - // Bug 16868177 exists to purge this code completely - return true; //is_battery_ok(START_THRESHOLD); - } - - int is_battery_ok_to_continue() - { - // Bug 16868177 exists to purge this code completely - return true; //is_battery_ok(CONTINUE_THRESHOLD); - } -} diff --git a/CheckBattery.h b/CheckBattery.h deleted file mode 100644 index dd11ba9..0000000 --- a/CheckBattery.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2014 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 _CHECKBATTERY_H__ -#define _CHECKBATTERY_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -int is_battery_ok_to_start(); -int is_battery_ok_to_continue(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/EncryptInplace.cpp b/EncryptInplace.cpp index 4ffb8cd..16a108c 100644 --- a/EncryptInplace.cpp +++ b/EncryptInplace.cpp @@ -32,7 +32,6 @@ #include "cutils/properties.h" #define LOG_TAG "EncryptInplace" #include "cutils/log.h" -#include "CheckBattery.h" // HORRIBLE HACK, FIXME #include "cryptfs.h" @@ -244,13 +243,6 @@ static int encrypt_groups(struct encryptGroupsData* data) goto errout; } } - - if (!is_battery_ok_to_continue()) { - SLOGE("Stopping encryption due to low battery"); - rc = 0; - goto errout; - } - } if (flush_outstanding_data(data)) { goto errout; @@ -573,13 +565,6 @@ static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev, CRYPT_SECTORS_PER_BUFSIZE, i * CRYPT_SECTORS_PER_BUFSIZE); } - - if (!is_battery_ok_to_continue()) { - SLOGE("Stopping encryption due to low battery"); - *size_already_done += (i + 1) * CRYPT_SECTORS_PER_BUFSIZE - 1; - rc = 0; - goto errout; - } } /* Do any remaining sectors */ diff --git a/cryptfs.cpp b/cryptfs.cpp index 40b1e07..d42e00b 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -57,7 +57,6 @@ #include "VoldUtil.h" #include "Ext4Crypt.h" #include "f2fs_sparseblock.h" -#include "CheckBattery.h" #include "EncryptInplace.h" #include "Process.h" #include "Keymaster.h" @@ -2010,11 +2009,6 @@ static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how, off64_t cur_encryption_done=0, tot_encryption_size=0; int rc = -1; - if (!is_battery_ok_to_start()) { - SLOGW("Not starting encryption due to low battery"); - return 0; - } - /* The size of the userdata partition, and add in the vold volumes below */ tot_encryption_size = crypt_ftr->fs_size; From 6b756ce5e9546ddbd6eb575e1d88af2faf160ab1 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Thu, 5 Oct 2017 14:07:09 -0700 Subject: [PATCH 023/106] Don't re-prepare main storage when preparing SD card storage Test: Boots correctly, logs show main storage no longer prepared when SD card is. Change-Id: I9a123436e7083d8331c7543fe77aa6587b28db9f --- Ext4Crypt.cpp | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 3ac6428..a6c589c 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -601,22 +601,26 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int auto misc_de_path = android::vold::BuildDataMiscDePath(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 == nullptr) { + 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(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 (volume_uuid == nullptr) { + 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; } } @@ -628,24 +632,28 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int 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 == nullptr) { + 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(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 (volume_uuid == nullptr) { + if (!ensure_policy(ce_raw_ref, system_ce_path)) return false; + if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false; + + // Now that credentials have been installed, we can run restorecon + // over these paths + // NOTE: these paths need to be kept in sync with libselinux + android::vold::RestoreconRecursive(system_ce_path); + android::vold::RestoreconRecursive(misc_ce_path); + } if (!ensure_policy(ce_raw_ref, media_ce_path)) return false; if (!ensure_policy(ce_raw_ref, user_ce_path)) return false; - - // Now that credentials have been installed, we can run restorecon - // over these paths - // NOTE: these paths need to be kept in sync with libselinux - android::vold::RestoreconRecursive(system_ce_path); - android::vold::RestoreconRecursive(misc_ce_path); } } From a7ca40bd70408d96e13abb71f9236000b4650454 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Fri, 6 Oct 2017 14:29:33 -0700 Subject: [PATCH 024/106] Remove dead code; move code out of cryptfs that doesn't belong. Test: Marlin boots Change-Id: I5c3fc21fef336b301981d6eff6f6ea242f30f66c --- Ext4Crypt.cpp | 13 +++++++-- cryptfs.cpp | 73 --------------------------------------------------- cryptfs.h | 9 ------- 3 files changed, 11 insertions(+), 84 deletions(-) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index a6c589c..1daf4ba 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -19,6 +19,8 @@ #include "KeyStorage.h" #include "KeyUtil.h" #include "Utils.h" +#include "VoldUtil.h" + #include #include @@ -261,11 +263,18 @@ static bool lookup_key_ref(const std::map& key_map, useri return true; } +static void get_file_encryption_modes(const char **contents_mode_ret, + const char **filenames_mode_ret) +{ + struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT); + fs_mgr_get_file_encryption_modes(rec, contents_mode_ret, filenames_mode_ret); +} + static bool ensure_policy(const std::string& raw_ref, const std::string& path) { const char *contents_mode; const char *filenames_mode; - cryptfs_get_file_encryption_modes(&contents_mode, &filenames_mode); + get_file_encryption_modes(&contents_mode, &filenames_mode); if (e4crypt_policy_ensure(path.c_str(), raw_ref.data(), raw_ref.size(), @@ -330,7 +339,7 @@ bool e4crypt_initialize_global_de() { const char *contents_mode; const char *filenames_mode; - cryptfs_get_file_encryption_modes(&contents_mode, &filenames_mode); + get_file_encryption_modes(&contents_mode, &filenames_mode); std::string modestring = std::string(contents_mode) + ":" + filenames_mode; std::string mode_filename = std::string("/data") + e4crypt_key_mode; diff --git a/cryptfs.cpp b/cryptfs.cpp index d42e00b..2574e39 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -2865,76 +2865,3 @@ int cryptfs_isConvertibleToFBE() struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT); return fs_mgr_is_convertible_to_fbe(rec) ? 1 : 0; } - -int cryptfs_create_default_ftr(struct crypt_mnt_ftr* crypt_ftr, __attribute__((unused))int key_length) -{ - if (cryptfs_init_crypt_mnt_ftr(crypt_ftr)) { - SLOGE("Failed to initialize crypt_ftr"); - return -1; - } - - if (create_encrypted_random_key(DEFAULT_PASSWORD, crypt_ftr->master_key, - crypt_ftr->salt, crypt_ftr)) { - SLOGE("Cannot create encrypted master key\n"); - return -1; - } - - //crypt_ftr->keysize = key_length / 8; - return 0; -} - -int cryptfs_get_master_key(struct crypt_mnt_ftr* ftr, const char* password, - unsigned char* master_key) -{ - int rc; - - unsigned char* intermediate_key = 0; - size_t intermediate_key_size = 0; - - if (password == 0 || *password == 0) { - password = DEFAULT_PASSWORD; - } - - rc = decrypt_master_key(password, master_key, ftr, &intermediate_key, - &intermediate_key_size); - - if (rc) { - SLOGE("Can't calculate intermediate key"); - return rc; - } - - int N = 1 << ftr->N_factor; - int r = 1 << ftr->r_factor; - int p = 1 << ftr->p_factor; - - unsigned char scrypted_intermediate_key[sizeof(ftr->scrypted_intermediate_key)]; - - rc = crypto_scrypt(intermediate_key, intermediate_key_size, - ftr->salt, sizeof(ftr->salt), N, r, p, - scrypted_intermediate_key, - sizeof(scrypted_intermediate_key)); - - free(intermediate_key); - - if (rc) { - SLOGE("Can't scrypt intermediate key"); - return rc; - } - - return memcmp(scrypted_intermediate_key, ftr->scrypted_intermediate_key, - intermediate_key_size); -} - -int cryptfs_set_password(struct crypt_mnt_ftr* ftr, const char* password, - const unsigned char* master_key) -{ - return encrypt_master_key(password, ftr->salt, master_key, ftr->master_key, - ftr); -} - -void cryptfs_get_file_encryption_modes(const char **contents_mode_ret, - const char **filenames_mode_ret) -{ - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT); - fs_mgr_get_file_encryption_modes(rec, contents_mode_ret, filenames_mode_ret); -} diff --git a/cryptfs.h b/cryptfs.h index 2169f54..5642e29 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -246,15 +246,6 @@ extern "C" { void cryptfs_clear_password(void); int cryptfs_isConvertibleToFBE(void); - // 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 From 3b71fc51005ac566fd8120f01b784d5f251ad886 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 9 Oct 2017 10:55:21 -0700 Subject: [PATCH 025/106] Be more C++. volume UUID should always be std::string. Test: boots Bug: 67041047 Change-Id: I36d3944ae8de192703b9ee359900841b833fe3a1 --- Ext4Crypt.cpp | 56 +++++++++++++++++++++---------------------- Ext4Crypt.h | 20 ++++++++-------- Keymaster.h | 7 +----- ScryptParameters.h | 4 ---- Utils.cpp | 28 +++++++++++----------- Utils.h | 8 +++---- VoldNativeService.cpp | 13 ++++++---- cryptfs.cpp | 1 + fs/Ext4.cpp | 1 + model/Disk.cpp | 3 ++- secontext.h | 2 -- 11 files changed, 69 insertions(+), 74 deletions(-) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 1daf4ba..48957c8 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -91,8 +91,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) { @@ -379,7 +379,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, FLAG_STORAGE_DE)) { LOG(ERROR) << "Failed to prepare user 0 storage"; return false; } @@ -491,8 +491,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; } @@ -503,10 +503,10 @@ 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) { +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; @@ -543,10 +543,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; @@ -566,8 +566,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; } @@ -584,8 +584,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; } @@ -594,9 +594,9 @@ 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) +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) { @@ -610,7 +610,7 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int auto misc_de_path = android::vold::BuildDataMiscDePath(user_id); auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id); - if (volume_uuid == nullptr) { + 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), @@ -626,7 +626,7 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int 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 (volume_uuid == nullptr) { + if (volume_uuid.empty()) { if (!ensure_policy(de_raw_ref, system_de_path)) return false; if (!ensure_policy(de_raw_ref, misc_de_path)) return false; } @@ -641,7 +641,7 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int 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) { + 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; } @@ -651,7 +651,7 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int 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 (volume_uuid == nullptr) { + if (volume_uuid.empty()) { if (!ensure_policy(ce_raw_ref, system_ce_path)) return false; if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false; @@ -669,8 +669,8 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int 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; @@ -685,7 +685,7 @@ bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int auto misc_de_path = android::vold::BuildDataMiscDePath(user_id); auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id); - if (volume_uuid == nullptr) { + if (volume_uuid.empty()) { res &= destroy_dir(system_legacy_path); #if MANAGE_MISC_DIRS res &= destroy_dir(misc_legacy_path); @@ -704,7 +704,7 @@ bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int 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) { + if (volume_uuid.empty()) { res &= destroy_dir(system_ce_path); res &= destroy_dir(misc_ce_path); } @@ -715,6 +715,6 @@ bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int return res; } -bool e4crypt_secdiscard(const char* path) { - return android::vold::runSecdiscardSingle(std::string(path)); +bool e4crypt_secdiscard(const std::string& path) { + return android::vold::runSecdiscardSingle(path); } diff --git a/Ext4Crypt.h b/Ext4Crypt.h index e90167b..d0afd85 100644 --- a/Ext4Crypt.h +++ b/Ext4Crypt.h @@ -14,29 +14,29 @@ * limitations under the License. */ +#include + #include #include #include -__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_secdiscard(const std::string& path); diff --git a/Keymaster.h b/Keymaster.h index dc6f1bc..f24a0c0 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -17,8 +17,6 @@ #ifndef ANDROID_VOLD_KEYMASTER_H #define ANDROID_VOLD_KEYMASTER_H -#ifdef __cplusplus - #include "KeyBuffer.h" #include @@ -127,8 +125,7 @@ class Keymaster { } // 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 +135,6 @@ class Keymaster { * The sign_object function signes an object with the given keymaster * key. */ -__BEGIN_DECLS int keymaster_compatibility_cryptfs_scrypt(); int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, @@ -156,6 +152,5 @@ int keymaster_sign_object_for_cryptfs_scrypt(const uint8_t* key_blob, uint8_t** signature_buffer, size_t* signature_buffer_size); -__END_DECLS #endif diff --git a/ScryptParameters.h b/ScryptParameters.h index 1b43ea5..190842b 100644 --- a/ScryptParameters.h +++ b/ScryptParameters.h @@ -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 diff --git a/Utils.cpp b/Utils.cpp index b6c7bf8..a9350e8 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -585,54 +585,54 @@ 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 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)) { @@ -643,7 +643,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); diff --git a/Utils.h b/Utils.h index 4e2be96..8d09ddf 100644 --- a/Utils.h +++ b/Utils.h @@ -103,10 +103,10 @@ std::string BuildDataMiscCePath(userid_t userid); std::string BuildDataMiscDePath(userid_t userid); std::string BuildDataProfilesDePath(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); diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 049f5ba..6fb1731 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -666,7 +667,7 @@ binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSer ENFORCE_UID(AID_SYSTEM); ACQUIRE_CRYPT_LOCK; - return translateBool(e4crypt_add_user_key_auth(userId, userSerial, token.c_str(), secret.c_str())); + return translateBool(e4crypt_add_user_key_auth(userId, userSerial, token, secret)); } binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) { @@ -681,7 +682,7 @@ binder::Status VoldNativeService::unlockUserKey(int32_t userId, int32_t userSeri ENFORCE_UID(AID_SYSTEM); ACQUIRE_CRYPT_LOCK; - return translateBool(e4crypt_unlock_user_key(userId, userSerial, token.c_str(), secret.c_str())); + return translateBool(e4crypt_unlock_user_key(userId, userSerial, token, secret)); } binder::Status VoldNativeService::lockUserKey(int32_t userId) { @@ -696,7 +697,8 @@ binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptrc_str() : nullptr; + std::string empty_string = ""; + auto uuid_ = uuid ? *uuid : empty_string; return translateBool(e4crypt_prepare_user_storage(uuid_, userId, userSerial, flags)); } @@ -705,7 +707,8 @@ binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptrc_str() : nullptr; + std::string empty_string = ""; + auto uuid_ = uuid ? *uuid : empty_string; return translateBool(e4crypt_destroy_user_storage(uuid_, userId, flags)); } @@ -713,7 +716,7 @@ binder::Status VoldNativeService::secdiscard(const std::string& path) { ENFORCE_UID(AID_SYSTEM); ACQUIRE_CRYPT_LOCK; - return translateBool(e4crypt_secdiscard(path.c_str())); + return translateBool(e4crypt_secdiscard(path)); } } // namespace vold diff --git a/cryptfs.cpp b/cryptfs.cpp index 2574e39..08a3d16 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp index 0cf4f9e..1898155 100644 --- a/fs/Ext4.cpp +++ b/fs/Ext4.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include diff --git a/model/Disk.cpp b/model/Disk.cpp index c889a35..5b0c981 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -23,10 +23,11 @@ #include "Ext4Crypt.h" #include +#include #include #include -#include #include +#include #include #include diff --git a/secontext.h b/secontext.h index 08ad48e..f5339c8 100644 --- a/secontext.h +++ b/secontext.h @@ -18,8 +18,6 @@ #include -__BEGIN_DECLS security_context_t secontextFsck(); -__END_DECLS #endif From 1a9652613aadfa23eb6af4cc0703843f1936d104 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Fri, 13 Oct 2017 13:49:50 -0700 Subject: [PATCH 026/106] Create subdirectories of misc_ce/misc_de when needed Bug: 25861755 Test: Boot device, check directory exists as it should. Change-Id: I413631452e8e0bdd869887091f8b077bd5f9297e --- Android.mk | 28 ++++++++++++++- Ext4Crypt.cpp | 18 ++++++++++ prepare_dir.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++ vold_prepare_subdirs | 44 ++++++++++++++++++++++++ 4 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 prepare_dir.cpp create mode 100644 vold_prepare_subdirs diff --git a/Android.mk b/Android.mk index e22bf0f..f1804b6 100644 --- a/Android.mk +++ b/Android.mk @@ -88,7 +88,7 @@ common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err58-cpp vold_conlyflags := -std=c11 vold_cflags := -Werror -Wall -Wno-missing-field-initializers -Wno-unused-variable -Wno-unused-parameter -required_modules := +required_modules := vold_prepare_subdirs ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) required_modules += mke2fs endif @@ -181,4 +181,30 @@ LOCAL_CONLYFLAGS := $(vold_conlyflags) include $(BUILD_EXECUTABLE) +include $(CLEAR_VARS) + +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_CLANG := true +LOCAL_TIDY := $(common_local_tidy_enabled) +LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) +LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) +LOCAL_SRC_FILES:= \ + prepare_dir.cpp \ + +LOCAL_MODULE:= prepare_dir +LOCAL_SHARED_LIBRARIES := libbase libcutils libselinux +LOCAL_CFLAGS := $(vold_cflags) +LOCAL_CONLYFLAGS := $(vold_conlyflags) + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) + +LOCAL_MODULE:= vold_prepare_subdirs +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_SRC_FILES := vold_prepare_subdirs +LOCAL_REQUIRED_MODULES := prepare_dir + +include $(BUILD_PREBUILT) + include $(LOCAL_PATH)/tests/Android.mk diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 48957c8..1a84e30 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -632,6 +632,15 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ } if (!ensure_policy(de_raw_ref, user_de_path)) return false; } + + if (volume_uuid.empty()) { + if (0 != android::vold::ForkExecvp( + std::vector{"/system/bin/vold_prepare_subdirs", "misc_de", + misc_de_path, std::to_string(user_id), ""})) { + LOG(ERROR) << "vold_prepare_subdirs failed on: " << misc_de_path; + return false; + } + } } if (flags & FLAG_STORAGE_CE) { @@ -664,6 +673,15 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ if (!ensure_policy(ce_raw_ref, media_ce_path)) return false; if (!ensure_policy(ce_raw_ref, user_ce_path)) return false; } + + if (volume_uuid.empty()) { + if (0 != android::vold::ForkExecvp( + std::vector{"/system/bin/vold_prepare_subdirs", "misc_ce", + misc_ce_path, std::to_string(user_id), ""})) { + LOG(ERROR) << "vold_prepare_subdirs failed on: " << misc_ce_path; + return false; + } + } } return true; diff --git a/prepare_dir.cpp b/prepare_dir.cpp new file mode 100644 index 0000000..1d91458 --- /dev/null +++ b/prepare_dir.cpp @@ -0,0 +1,82 @@ +/* + * 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 +#include + +#include +#include +#include + +#include + +#include +#include + +void usage(const char* progname) { + fprintf(stderr, "Usage: %s --mode MODE --uid UID --gid GID -- \n", progname); +} + +bool small_int(const std::string& s) { + return !s.empty() && s.size() < 7 && s.find_first_not_of("0123456789") == std::string::npos; +} + +int main(int argc, const char* const argv[]) { + setenv("ANDROID_LOG_TAGS", "*:v", 1); + android::base::InitLogging(const_cast(argv)); + std::vector args(argv + 1, argv + argc); + // Enforce exact format of arguments. You can always loosen but you can never tighten :) + if (args.size() != 8 || args[0] != "--mode" || !small_int(args[1]) || args[2] != "--uid" || + !small_int(args[3]) || args[4] != "--gid" || !small_int(args[5]) || args[6] != "--") { + usage(argv[0]); + return -1; + } + mode_t mode = (mode_t)stoi(args[1], nullptr, 8); + uid_t uid = (uid_t)stoi(args[3]); + gid_t gid = (gid_t)stoi(args[5]); + const char* path = args[7].c_str(); + + struct selabel_handle* sehandle = selinux_android_file_context_handle(); + char* secontext = nullptr; + if (sehandle) { + if (selabel_lookup(sehandle, &secontext, path, S_IFDIR) == 0) { + setfscreatecon(secontext); + } + } + + if (fs_prepare_dir(path, mode, uid, gid) != 0) { + return -1; + } + if (secontext) { + char* oldsecontext = nullptr; + if (lgetfilecon(path, &oldsecontext) < 0) { + PLOG(ERROR) << "Unable to read secontext for: " << path; + return -1; + } + if (strcmp(secontext, oldsecontext) != 0) { + LOG(INFO) << "Relabelling from " << oldsecontext << " to " << secontext << ": " << path; + if (lsetfilecon(path, secontext) != 0) { + PLOG(ERROR) << "Relabelling failed for: " << path; + } + } + } + return 0; +} diff --git a/vold_prepare_subdirs b/vold_prepare_subdirs new file mode 100644 index 0000000..f436ca2 --- /dev/null +++ b/vold_prepare_subdirs @@ -0,0 +1,44 @@ +#!/system/bin/sh +# +# 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. + +set -e + +case "$3" in + *[!0-9]* | '') + echo "Invalid user id" + exit -1 + ;; +esac + +if [ x"$4" != x ] ; then + echo "Volume must be root volume" + exit -1; +fi + +case "$1" in + misc_de|misc_ce) + computed_path="/data/$1/$3" + if [ x"$computed_path" != x"$2" ] ; then + echo "Parameter path didn't match computed path: " $computed_path + exit -1; + fi + /system/bin/prepare_dir --mode 700 --uid 0 --gid 0 -- "$computed_path"/vold + ;; + *) + echo "Unknown type: $1" + exit -1; + ;; +esac From 8e5506684590f4656073224546543366bf382241 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 16 Oct 2017 17:01:44 -0700 Subject: [PATCH 027/106] Recursively delete subdirs when deleting Use vold_prepare_subdirs since only it has the privilege needed. Bug: 25861755 Test: Boot device, create user, create files, remove user, observe logs Change-Id: I90fb2517ccd177c9b009001e7a2b00f537152f8c --- Ext4Crypt.cpp | 68 ++++++++++++++++++++++++-------------------- vold_prepare_subdirs | 49 ++++++++++++++++++++++--------- 2 files changed, 73 insertions(+), 44 deletions(-) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 1a84e30..646a032 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -594,6 +594,18 @@ bool e4crypt_lock_user_key(userid_t user_id) { return true; } +static bool prepare_subdirs(const std::string& action, const std::string& dirtype, + const std::string& volume_uuid, userid_t user_id, + const std::string& path) { + if (0 != android::vold::ForkExecvp(std::vector{"/system/bin/vold_prepare_subdirs", + action, dirtype, volume_uuid, + std::to_string(user_id), path})) { + LOG(ERROR) << "vold_prepare_subdirs failed on: " << path; + 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) @@ -634,12 +646,8 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ } if (volume_uuid.empty()) { - if (0 != android::vold::ForkExecvp( - std::vector{"/system/bin/vold_prepare_subdirs", "misc_de", - misc_de_path, std::to_string(user_id), ""})) { - LOG(ERROR) << "vold_prepare_subdirs failed on: " << misc_de_path; + if (!prepare_subdirs("prepare", "misc_de", volume_uuid, user_id, misc_de_path)) return false; - } } } @@ -664,23 +672,19 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ if (!ensure_policy(ce_raw_ref, system_ce_path)) return false; if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false; - // Now that credentials have been installed, we can run restorecon - // over these paths - // NOTE: these paths need to be kept in sync with libselinux - android::vold::RestoreconRecursive(system_ce_path); - android::vold::RestoreconRecursive(misc_ce_path); } if (!ensure_policy(ce_raw_ref, media_ce_path)) return false; if (!ensure_policy(ce_raw_ref, user_ce_path)) return false; } if (volume_uuid.empty()) { - if (0 != android::vold::ForkExecvp( - std::vector{"/system/bin/vold_prepare_subdirs", "misc_ce", - misc_ce_path, std::to_string(user_id), ""})) { - LOG(ERROR) << "vold_prepare_subdirs failed on: " << misc_ce_path; + if (!prepare_subdirs("prepare", "misc_ce", volume_uuid, user_id, misc_ce_path)) return false; - } + // Now that credentials have been installed, we can run restorecon + // over these paths + // NOTE: these paths need to be kept in sync with libselinux + android::vold::RestoreconRecursive(system_ce_path); + android::vold::RestoreconRecursive(misc_ce_path); } } @@ -692,6 +696,22 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ << ", user " << user_id << ", flags " << flags; bool res = true; + 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); + + res &= destroy_dir(media_ce_path); + res &= destroy_dir(user_ce_path); + if (volume_uuid.empty()) { + res &= prepare_subdirs("destroy", "misc_ce", volume_uuid, user_id, misc_ce_path); + res &= destroy_dir(system_ce_path); + res &= destroy_dir(misc_ce_path); + } + } + if (flags & FLAG_STORAGE_DE) { // DE_sys key auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id); @@ -703,7 +723,9 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ auto misc_de_path = android::vold::BuildDataMiscDePath(user_id); auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id); + res &= destroy_dir(user_de_path); if (volume_uuid.empty()) { + res &= prepare_subdirs("destroy", "misc_de", volume_uuid, user_id, misc_de_path); res &= destroy_dir(system_legacy_path); #if MANAGE_MISC_DIRS res &= destroy_dir(misc_legacy_path); @@ -712,22 +734,6 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ res &= destroy_dir(system_de_path); res &= destroy_dir(misc_de_path); } - 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.empty()) { - 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; diff --git a/vold_prepare_subdirs b/vold_prepare_subdirs index f436ca2..cdea243 100644 --- a/vold_prepare_subdirs +++ b/vold_prepare_subdirs @@ -14,31 +14,54 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -e +# Set up or tear down subdirectories of vold-created directories. +# +# This is kept separate from vold because under the SELinux rules, it has privileges vold doesn't +# have. In particular, prepare_dir sets SELinux labels on subdirectories based on file_contexts, +# so this script has some relabelling privileges. -case "$3" in - *[!0-9]* | '') - echo "Invalid user id" - exit -1 - ;; + +set -e +action="$1" +dirtype="$2" +volume_uuid="$3" +user_id="$4" +path="$5" + +case "$user_id" in + *[!0-9]* | '') + echo "Invalid user id" + exit -1 + ;; esac -if [ x"$4" != x ] ; then +if [ x"$volume_uuid" != x ] ; then echo "Volume must be root volume" exit -1; fi -case "$1" in +case "$dirtype" in misc_de|misc_ce) - computed_path="/data/$1/$3" - if [ x"$computed_path" != x"$2" ] ; then + computed_path="/data/$dirtype/$user_id" + if [ x"$computed_path" != x"$path" ] ; then echo "Parameter path didn't match computed path: " $computed_path exit -1; fi - /system/bin/prepare_dir --mode 700 --uid 0 --gid 0 -- "$computed_path"/vold + case "$action" in + prepare) + /system/bin/prepare_dir --mode 700 --uid 0 --gid 0 -- "$computed_path"/vold + ;; + destroy) + rm -rf "$computed_path"/* + ;; + *) + echo "Unknown action: $action" + exit -1 + ;; + esac ;; *) - echo "Unknown type: $1" - exit -1; + echo "Unknown type: $dirtype" + exit -1 ;; esac From 06f762d577d8b3e5424c002c7f6d838e9f0e5ded Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 16 Oct 2017 10:59:51 -0700 Subject: [PATCH 028/106] Validate filesystem UUIDs in Binder calls. Test: boots Bug: 67041047 Change-Id: I7bb21186db8cd709a9adfc5f9d0dedb069b2cff3 --- VoldNativeService.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 6fb1731..a900ba1 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -695,20 +695,22 @@ binder::Status VoldNativeService::lockUserKey(int32_t userId) { binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr& uuid, int32_t userId, int32_t userSerial, int32_t flags) { ENFORCE_UID(AID_SYSTEM); - ACQUIRE_CRYPT_LOCK; - 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& uuid, int32_t userId, int32_t flags) { ENFORCE_UID(AID_SYSTEM); - ACQUIRE_CRYPT_LOCK; - 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)); } From 3472e52fc259b6a549acece21d4901d99d6a421f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 6 Oct 2017 18:02:53 -0600 Subject: [PATCH 029/106] Move to modern utility methods from android::base. Moves away from crufty char* operations to std::string utility methods, including android::base methods for splitting/parsing. Rewrite of how Process handles scanning procfs for filesystem references; now uses fts(3) for more sane traversal. Replace sscanf() with new FindValue() method, also has unit tests. Remove some unused methods. Switch almost everyone over to using modern logging library. Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Bug: 67041047 Change-Id: I70dc512f21459d1e25b187f24289002b2c7bc7af --- Devmapper.cpp | 78 ++++---------- Devmapper.h | 1 - Loop.cpp | 181 +++---------------------------- Loop.h | 2 - NetlinkHandler.cpp | 8 +- NetlinkManager.cpp | 16 ++- Process.cpp | 229 ++++++++++++---------------------------- Process.h | 26 +---- TrimTask.cpp | 5 +- Utils.cpp | 100 ++++++++++-------- Utils.h | 13 ++- VoldNativeService.cpp | 8 +- VolumeManager.cpp | 78 ++++++-------- VolumeManager.h | 2 +- cryptfs.cpp | 6 +- fs/Ext4.cpp | 2 +- fs/Vfat.cpp | 49 ++++----- main.cpp | 10 +- model/Disk.cpp | 59 +++++++---- model/PrivateVolume.cpp | 2 +- model/PublicVolume.cpp | 2 +- tests/Android.mk | 1 + tests/Utils_test.cpp | 44 ++++++++ 23 files changed, 329 insertions(+), 593 deletions(-) create mode 100644 tests/Utils_test.cpp diff --git a/Devmapper.cpp b/Devmapper.cpp index 2cbed86..2510771 100644 --- a/Devmapper.cpp +++ b/Devmapper.cpp @@ -30,11 +30,8 @@ #include -#define LOG_TAG "Vold" - -#include - #include +#include #include #include @@ -62,42 +59,6 @@ void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize, } } -int Devmapper::lookupActive(const char *name_raw, char *ubuffer, size_t len) { - auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw); - const char* name = name_string.c_str(); - - char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE); - if (!buffer) { - SLOGE("Error allocating memory (%s)", strerror(errno)); - 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_raw, const char *loopFile, const char *key, unsigned long numSectors, char *ubuffer, size_t len) { auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw); @@ -105,13 +66,13 @@ int Devmapper::create(const char *name_raw, const char *loopFile, const char *ke 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; } @@ -122,7 +83,7 @@ int Devmapper::create(const char *name_raw, const char *loopFile, const char *ke 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; @@ -137,7 +98,7 @@ int Devmapper::create(const char *name_raw, const char *loopFile, const char *ke 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; @@ -146,7 +107,7 @@ int Devmapper::create(const char *name_raw, const char *loopFile, const char *ke // 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; @@ -177,7 +138,7 @@ int Devmapper::create(const char *name_raw, const char *loopFile, const char *ke 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; @@ -187,7 +148,7 @@ int Devmapper::create(const char *name_raw, const char *loopFile, const char *ke 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; @@ -205,13 +166,13 @@ int Devmapper::destroy(const char *name_raw) { 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; } @@ -223,7 +184,7 @@ int Devmapper::destroy(const char *name_raw) { 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); @@ -239,21 +200,21 @@ int Devmapper::destroyAll() { ATRACE_NAME("Devmapper::destroyAll"); char *buffer = (char *) malloc(1024 * 64); if (!buffer) { - SLOGE("Error allocating memory (%s)", strerror(errno)); + PLOG(ERROR) << "Failed malloc"; return -1; } memset(buffer, 0, (1024 * 64)); char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE); if (!buffer2) { - SLOGE("Error allocating memory (%s)", strerror(errno)); + PLOG(ERROR) << "Failed malloc"; free(buffer); 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); free(buffer2); return -1; @@ -263,7 +224,7 @@ int Devmapper::destroyAll() { ioctlInit(io, (1024 * 64), NULL, 0); if (ioctl(fd, DM_LIST_DEVICES, io)) { - SLOGE("DM_LIST_DEVICES ioctl failed (%s)", strerror(errno)); + PLOG(ERROR) << "Failed DM_LIST_DEVICES"; free(buffer); free(buffer2); close(fd); @@ -281,19 +242,20 @@ int Devmapper::destroyAll() { unsigned nxt = 0; do { n = (struct dm_name_list *) (((char *) n) + nxt); - if (strncmp(n->name, kVoldPrefix, strlen(kVoldPrefix)) == 0) { - LOG(DEBUG) << "Tearing down stale dm device named " << n->name; + 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 " << n->name; + PLOG(WARNING) << "Failed to destroy dm device named " << name; } } } else { - LOG(VERBOSE) << "Found unmanaged dm device named " << n->name; + LOG(VERBOSE) << "Found unmanaged dm device named " << name; } nxt = n->next; } while (nxt); diff --git a/Devmapper.h b/Devmapper.h index 086ad78..7bb9786 100644 --- a/Devmapper.h +++ b/Devmapper.h @@ -26,7 +26,6 @@ public: unsigned long numSectors, char *buffer, size_t len); static int destroy(const char *name); static int destroyAll(); - static int lookupActive(const char *name, char *buffer, size_t len); private: static void *_align(void *ptr, unsigned int a); diff --git a/Loop.cpp b/Loop.cpp index 1eb9865..3736d6a 100644 --- a/Loop.cpp +++ b/Loop.cpp @@ -31,11 +31,8 @@ #include -#define LOG_TAG "Vold" - -#include - #include +#include #include #include #include @@ -49,161 +46,6 @@ using android::base::unique_fd; static const char* kVoldPrefix = "vold:"; -int Loop::lookupActive(const char *id_raw, char *buffer, size_t len) { - auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw); - const char* id = id_string.c_str(); - - int i; - int fd; - char filename[256]; - - 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_raw, const char *loopFile, char *loopDeviceBuffer, size_t len) { - auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw); - const char* id = id_string.c_str(); - - int i; - int fd; - char filename[256]; - - 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; -} - int Loop::create(const std::string& target, std::string& out_device) { unique_fd ctl_fd(open("/dev/loop-control", O_RDWR | O_CLOEXEC)); if (ctl_fd.get() == -1) { @@ -251,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; } @@ -279,7 +121,8 @@ int Loop::destroyAll() { // Poke through all devices looking for loops while ((de = readdir(dir))) { - if (strncmp(de->d_name, "loop", 4) != 0) continue; + 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)); @@ -296,8 +139,8 @@ int Loop::destroyAll() { continue; } - char* id = (char*) li.lo_crypt_name; - if (strncmp(id, kVoldPrefix, strlen(kVoldPrefix)) == 0) { + 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) { @@ -332,22 +175,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; } diff --git a/Loop.h b/Loop.h index 654b8ad..130c5b6 100644 --- a/Loop.h +++ b/Loop.h @@ -25,8 +25,6 @@ class Loop { public: static const int LOOP_MAX = 4096; public: - static int lookupActive(const char *id, char *buffer, size_t len); - 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 destroyAll(); diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp index ecda2a0..92131e9 100644 --- a/NetlinkHandler.cpp +++ b/NetlinkHandler.cpp @@ -19,9 +19,7 @@ #include #include -#define LOG_TAG "Vold" - -#include +#include #include #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); } } diff --git a/NetlinkManager.cpp b/NetlinkManager.cpp index 90e3c6c..409cdc8 100644 --- a/NetlinkManager.cpp +++ b/NetlinkManager.cpp @@ -26,9 +26,7 @@ #include -#define LOG_TAG "Vold" - -#include +#include #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; diff --git a/Process.cpp b/Process.cpp index 1c0f504..042ba2d 100644 --- a/Process.cpp +++ b/Process.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,196 +28,98 @@ #include #include -#define LOG_TAG "ProcessKiller" +#include +#include #include +#include +#include #include #include -#include #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.c_str())) { + 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.c_str())) { + 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 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(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(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 diff --git a/Process.h b/Process.h index 4ddbdb9..1406782 100644 --- a/Process.h +++ b/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 diff --git a/TrimTask.cpp b/TrimTask.cpp index fafb345..2718095 100644 --- a/TrimTask.cpp +++ b/TrimTask.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -67,9 +66,9 @@ void TrimTask::addFromFstab() { 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 (!strcmp(fstab->recs[i].fs_type, "emmc") || - !strcmp(fstab->recs[i].fs_type, "mtd")) { + if (fs_type == "emmc" || fs_type == "mtd") { continue; } /* Skip read-only filesystems */ diff --git a/Utils.cpp b/Utils.cpp index a9350e8..484de90 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -129,19 +130,19 @@ status_t ForceUnmount(const std::string& path) { // we start sending signals if (!VolumeManager::shutting_down) sleep(5); - Process::killProcessesWithOpenFiles(cpath, SIGINT); + KillProcessesWithOpenFiles(path, SIGINT); if (!VolumeManager::shutting_down) sleep(5); if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } - Process::killProcessesWithOpenFiles(cpath, SIGTERM); + KillProcessesWithOpenFiles(path, SIGTERM); if (!VolumeManager::shutting_down) sleep(5); if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } - Process::killProcessesWithOpenFiles(cpath, SIGKILL); + KillProcessesWithOpenFiles(path, SIGKILL); if (!VolumeManager::shutting_down) sleep(5); if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; @@ -151,25 +152,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 (Process::killProcessesWithOpenFiles(cpath, SIGTERM) == 0) { + if (KillProcessesWithOpenFiles(path, SIGTERM) == 0) { return OK; } if (!VolumeManager::shutting_down) sleep(5); - if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) { + if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) { return OK; } if (!VolumeManager::shutting_down) 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 +184,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 cmd; cmd.push_back(kBlkidPath); @@ -209,36 +226,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); } @@ -673,15 +677,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 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) < buf.size()) { + result->assign(&buf[0], size); + return true; + } + // Double our buffer and try again. + buf.resize(buf.size() * 2); } } diff --git a/Utils.h b/Utils.h index 8d09ddf..9163006 100644 --- a/Utils.h +++ b/Utils.h @@ -53,13 +53,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& args); @@ -112,7 +114,8 @@ 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(); diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 6fb1731..d1986ef 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -37,10 +37,6 @@ #include #include -#ifndef LOG_TAG -#define LOG_TAG "vold" -#endif - using android::base::StringPrintf; using std::endl; @@ -423,7 +419,7 @@ binder::Status VoldNativeService::mkdirs(const std::string& path) { CHECK_ARGUMENT_PATH(path); ACQUIRE_LOCK; - return translate(VolumeManager::Instance()->mkdirs(path.c_str())); + return translate(VolumeManager::Instance()->mkdirs(path)); } binder::Status VoldNativeService::createObb(const std::string& sourcePath, @@ -519,7 +515,7 @@ static int fdeEnableInternal(int32_t passwordType, const std::string& password, if (rc == 0) { return 0; } else if (tries == 0) { - Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL); + KillProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL); } } diff --git a/VolumeManager.cpp b/VolumeManager.cpp index d441297..c1d51d9 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -34,14 +33,11 @@ #include -#define LOG_TAG "Vold" - -#include - #include +#include +#include #include #include -#include #include #include @@ -98,7 +94,7 @@ VolumeManager::~VolumeManager() { int VolumeManager::updateVirtualDisk() { ATRACE_NAME("VolumeManager::updateVirtualDisk"); - if (property_get_bool(kPropVirtualDisk, false)) { + if (android::base::GetBoolProperty(kPropVirtualDisk, false)) { if (access(kPathVirtualDisk, F_OK) != 0) { Loop::createImageFile(kPathVirtualDisk, kSizeVirtualDisk / 512); } @@ -323,13 +319,12 @@ int VolumeManager::linkPrimary(userid_t userId) { std::string target(StringPrintf("/mnt/user/%d/primary", userId)); if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) { if (errno != ENOENT) { - SLOGW("Failed to unlink %s: %s", target.c_str(), strerror(errno)); + PLOG(WARNING) << "Failed to unlink " << target; } } LOG(DEBUG) << "Linking " << source << " to " << target; if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) { - SLOGW("Failed to link %s to %s: %s", source.c_str(), target.c_str(), - strerror(errno)); + PLOG(WARNING) << "Failed to link"; return -errno; } return 0; @@ -372,12 +367,10 @@ int VolumeManager::setPrimary(const std::shared_ptr& return 0; } -static int unmount_tree(const char* path) { - size_t path_len = strlen(path); - +static int unmount_tree(const std::string& prefix) { FILE* fp = setmntent("/proc/mounts", "r"); if (fp == NULL) { - ALOGE("Error opening /proc/mounts: %s", strerror(errno)); + PLOG(ERROR) << "Failed to open /proc/mounts"; return -errno; } @@ -386,15 +379,16 @@ static int unmount_tree(const char* path) { std::list toUnmount; mntent* mentry; while ((mentry = getmntent(fp)) != NULL) { - if (strncmp(mentry->mnt_dir, path, path_len) == 0) { - toUnmount.push_front(std::string(mentry->mnt_dir)); + auto test = std::string(mentry->mnt_dir) + "/"; + if (android::base::StartsWith(test, prefix.c_str())) { + toUnmount.push_front(test); } } endmntent(fp); for (const auto& path : toUnmount) { if (umount2(path.c_str(), MNT_DETACH)) { - ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno)); + PLOG(ERROR) << "Failed to unmount " << path; } } return 0; @@ -405,8 +399,8 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) { DIR* dir; struct dirent* de; - char rootName[PATH_MAX]; - char pidName[PATH_MAX]; + std::string rootName; + std::string pidName; int pidFd; int nsFd; struct stat sb; @@ -418,8 +412,8 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) { } // Figure out root namespace to compare against below - if (android::vold::SaneReadLinkAt(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) { - PLOG(ERROR) << "Failed to readlink"; + if (!android::vold::Readlinkat(dirfd(dir), "1/ns/mnt", &rootName)) { + PLOG(ERROR) << "Failed to read root namespace"; closedir(dir); return -1; } @@ -443,11 +437,11 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) { // Matches so far, but refuse to touch if in root namespace LOG(DEBUG) << "Found matching PID " << de->d_name; - if (android::vold::SaneReadLinkAt(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) { + if (!android::vold::Readlinkat(pidFd, "ns/mnt", &pidName)) { PLOG(WARNING) << "Failed to read namespace for " << de->d_name; goto next; } - if (!strcmp(rootName, pidName)) { + if (rootName == pidName) { LOG(WARNING) << "Skipping due to root namespace"; goto next; } @@ -465,7 +459,7 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) { _exit(1); } - unmount_tree("/storage"); + unmount_tree("/storage/"); std::string storageSource; if (mode == "default") { @@ -568,7 +562,7 @@ int VolumeManager::unmountAll() { // force unmount those just to be safe. FILE* fp = setmntent("/proc/mounts", "r"); if (fp == NULL) { - SLOGE("Error opening /proc/mounts: %s", strerror(errno)); + PLOG(ERROR) << "Failed to open /proc/mounts"; return -errno; } @@ -577,9 +571,10 @@ int VolumeManager::unmountAll() { std::list toUnmount; mntent* mentry; while ((mentry = getmntent(fp)) != NULL) { - if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0 - || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) { - toUnmount.push_front(std::string(mentry->mnt_dir)); + auto test = std::string(mentry->mnt_dir); + if (android::base::StartsWith(test, "/mnt/") + || android::base::StartsWith(test, "/storage/")) { + toUnmount.push_front(test); } } endmntent(fp); @@ -597,13 +592,13 @@ extern "C" int vold_unmountAll(void) { return vm->unmountAll(); } -int VolumeManager::mkdirs(const char* path) { +int VolumeManager::mkdirs(const std::string& path) { // Only offer to create directories for paths managed by vold - if (strncmp(path, "/storage/", 9) == 0) { + if (android::base::StartsWith(path, "/storage/")) { // fs_mkdirs() does symlink checking and relative path enforcement - return fs_mkdirs(path, 0700); + return fs_mkdirs(path.c_str(), 0700); } else { - SLOGE("Failed to find mounted volume for %s", path); + LOG(ERROR) << "Failed to find mounted volume for " << path; return -EINVAL; } } @@ -694,21 +689,14 @@ static android::status_t runCommandInNamespace(const std::string& command, // 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"; + std::string rootName; + std::string pidName; + if (!android::vold::Readlinkat(dir.get(), "1/ns/mnt", &rootName) + || !android::vold::Readlinkat(pid_fd.get(), "ns/mnt", &pidName)) { + PLOG(ERROR) << "Failed to read namespaces"; return -EPERM; } - if (pid_result == -1) { - LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt"; - return -EPERM; - } - if (!strcmp(rootName, pidName)) { + if (rootName == pidName) { LOG(ERROR) << "Don't mount appfuse in root namespace"; return -EPERM; } diff --git a/VolumeManager.h b/VolumeManager.h index dcfbdad..4f62de9 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -123,7 +123,7 @@ 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(const char* path); + int mkdirs(const std::string& path); int createObb(const std::string& path, const std::string& key, int32_t ownerGid, std::string* outVolId); diff --git a/cryptfs.cpp b/cryptfs.cpp index 08a3d16..ae9b0af 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1277,10 +1277,10 @@ int wait_and_unmount(const char *mountpoint, bool kill) if (kill) { if (i == (WAIT_UNMOUNT_COUNT - 3)) { SLOGW("sending SIGHUP to processes with open files\n"); - vold_killProcessesWithOpenFiles(mountpoint, SIGTERM); + android::vold::KillProcessesWithOpenFiles(mountpoint, SIGTERM); } else if (i == (WAIT_UNMOUNT_COUNT - 2)) { SLOGW("sending SIGKILL to processes with open files\n"); - vold_killProcessesWithOpenFiles(mountpoint, SIGKILL); + android::vold::KillProcessesWithOpenFiles(mountpoint, SIGKILL); } } @@ -1291,7 +1291,7 @@ int wait_and_unmount(const char *mountpoint, bool kill) SLOGD("unmounting %s succeeded\n", mountpoint); rc = 0; } else { - vold_killProcessesWithOpenFiles(mountpoint, 0); + android::vold::KillProcessesWithOpenFiles(mountpoint, 0); SLOGE("unmounting %s failed: %s\n", mountpoint, strerror(err)); rc = -1; } diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp index 1898155..89b8414 100644 --- a/fs/Ext4.cpp +++ b/fs/Ext4.cpp @@ -146,7 +146,7 @@ status_t Mount(const std::string& source, const std::string& target, bool ro, rc = mount(c_source, c_target, "ext4", flags, NULL); if (rc && errno == EROFS) { - SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source); + LOG(ERROR) << source << " appears to be a read only filesystem - retrying mount RO"; flags |= MS_RDONLY; rc = mount(c_source, c_target, "ext4", flags, NULL); } diff --git a/fs/Vfat.cpp b/fs/Vfat.cpp index dc1fe33..538178e 100644 --- a/fs/Vfat.cpp +++ b/fs/Vfat.cpp @@ -35,12 +35,8 @@ #include -#define LOG_TAG "Vold" - #include #include -#include -#include #include #include @@ -65,11 +61,6 @@ bool IsSupported() { } status_t Check(const std::string& source) { - if (access(kFsckPath, X_OK)) { - SLOGW("Skipping fs checks\n"); - return 0; - } - int pass = 1; int rc = 0; do { @@ -83,38 +74,37 @@ status_t Check(const std::string& source) { rc = ForkExecvp(cmd, sFsckUntrustedContext); if (rc < 0) { - SLOGE("Filesystem check failed due to logwrap error"); + LOG(ERROR) << "Filesystem check failed due to logwrap error"; errno = EIO; return -1; } switch(rc) { case 0: - SLOGI("Filesystem check completed OK"); + LOG(INFO) << "Filesystem check completed OK"; return 0; case 2: - SLOGE("Filesystem check failed (not a FAT filesystem)"); + LOG(ERROR) << "Filesystem check failed (not a FAT filesystem)"; errno = ENODATA; return -1; case 4: if (pass++ <= 3) { - SLOGW("Filesystem modified - rechecking (pass %d)", - pass); + LOG(WARNING) << "Filesystem modified - rechecking (pass " << pass << ")"; continue; } - SLOGE("Failing check after too many rechecks"); + LOG(ERROR) << "Failing check after too many rechecks"; errno = EIO; return -1; case 8: - SLOGE("Filesystem check failed (no filesystem)"); + LOG(ERROR) << "Filesystem check failed (no filesystem)"; errno = ENODATA; return -1; default: - SLOGE("Filesystem check failed (unknown exit code %d)", rc); + LOG(ERROR) << "Filesystem check failed (unknown exit code " << rc << ")"; errno = EIO; return -1; } @@ -128,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(); @@ -139,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) { - SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source); + 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)) { - SLOGE("Unable to create LOST.DIR (%s)", strerror(errno)); + if (mkdir(lost_path.c_str(), 0755)) { + PLOG(ERROR) << "Unable to create LOST.DIR"; } } - free(lost_path); } return rc; @@ -189,16 +176,16 @@ status_t Format(const std::string& source, unsigned long numSectors) { int rc = ForkExecvp(cmd); if (rc < 0) { - SLOGE("Filesystem format failed due to logwrap error"); + LOG(ERROR) << "Filesystem format failed due to logwrap error"; errno = EIO; return -1; } if (rc == 0) { - SLOGI("Filesystem formatted OK"); + LOG(INFO) << "Filesystem formatted OK"; return 0; } else { - SLOGE("Format failed (unknown exit code %d)", rc); + LOG(ERROR) << "Format failed (unknown exit code " << rc << ")"; errno = EIO; return -1; } diff --git a/main.cpp b/main.cpp index 30f60a1..cca738e 100644 --- a/main.cpp +++ b/main.cpp @@ -25,9 +25,9 @@ #include "sehandle.h" #include +#include #include #include -#include #include #include @@ -88,7 +88,7 @@ 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); } @@ -120,8 +120,8 @@ int main(int argc, char** argv) { // 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"); // Do coldboot here so it won't block booting, // also the cold boot is needed in case we have flash drive @@ -240,7 +240,7 @@ static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quot *has_adoptable = true; } if (fs_mgr_is_noemulatedsd(rec) - || property_get_bool("vold.debug.default_primary", false)) { + || android::base::GetBoolProperty("vold.debug.default_primary", false)) { flags |= android::vold::Disk::Flags::kDefaultPrimary; } diff --git a/model/Disk.cpp b/model/Disk.cpp index 5b0c981..291c2e1 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -263,7 +265,11 @@ status_t Disk::readMetadata() { PLOG(WARNING) << "Failed to read manufacturer from " << path; return -errno; } - uint64_t manfid = strtoll(tmp.c_str(), nullptr, 16); + 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. @@ -295,7 +301,7 @@ status_t Disk::readMetadata() { } status_t Disk::readPartitions() { - int8_t maxMinors = getMaxMinors(); + int maxMinors = getMaxMinors(); if (maxMinors < 0) { return -ENOTSUP; } @@ -324,31 +330,40 @@ status_t Disk::readPartitions() { Table table = Table::kUnknown; bool foundParts = false; for (const auto& line : output) { - char* cline = (char*) line.c_str(); - char* token = strtok(cline, kSgdiskToken); - if (token == nullptr) continue; + auto split = android::base::Split(line, kSgdiskToken); + auto it = split.begin(); + if (it == split.end()) continue; - if (!strcmp(token, "DISK")) { - const char* type = strtok(nullptr, kSgdiskToken); - if (!strcmp(type, "mbr")) { + if (*it == "DISK") { + if (++it == split.end()) continue; + if (*it == "mbr") { table = Table::kMbr; - } else if (!strcmp(type, "gpt")) { + } else if (*it == "gpt") { table = Table::kGpt; + } else { + LOG(WARNING) << "Invalid partition table " << *it; + continue; } - } else if (!strcmp(token, "PART")) { + } else if (*it == "PART") { foundParts = true; - int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10); - if (i <= 0 || i > maxMinors) { - LOG(WARNING) << mId << " is ignoring partition " << i - << " beyond max supported devices"; + + if (++it == split.end()) continue; + int i = 0; + if (!android::base::ParseInt(*it, &i, 1, maxMinors)) { + LOG(WARNING) << "Invalid partition number " << *it; continue; } dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i); if (table == Table::kMbr) { - const char* type = strtok(nullptr, kSgdiskToken); + if (++it == split.end()) continue; + int type = 0; + if (!android::base::ParseInt("0x" + *it, &type)) { + LOG(WARNING) << "Invalid partition type " << *it; + continue; + } - switch (strtol(type, nullptr, 16)) { + switch (type) { case 0x06: // FAT16 case 0x0b: // W95 FAT32 (LBA) case 0x0c: // W95 FAT32 (LBA) @@ -357,12 +372,14 @@ status_t Disk::readPartitions() { break; } } else if (table == Table::kGpt) { - const char* typeGuid = strtok(nullptr, kSgdiskToken); - const char* partGuid = strtok(nullptr, kSgdiskToken); + if (++it == split.end()) continue; + auto typeGuid = *it; + if (++it == split.end()) continue; + auto partGuid = *it; - if (!strcasecmp(typeGuid, kGptBasicData)) { + if (android::base::EqualsIgnoreCase(typeGuid, kGptBasicData)) { createPublicVolume(partDevice); - } else if (!strcasecmp(typeGuid, kGptAndroidExpand)) { + } else if (android::base::EqualsIgnoreCase(typeGuid, kGptAndroidExpand)) { createPrivateVolume(partDevice, partGuid); } } @@ -375,7 +392,7 @@ 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"; diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index 3152313..48d041b 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -53,7 +53,7 @@ PrivateVolume::~PrivateVolume() { } status_t PrivateVolume::readMetadata() { - status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel); + status_t res = ReadMetadata(mDmDevPath, &mFsType, &mFsUuid, &mFsLabel); auto listener = getListener(); if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel); diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index f80f59e..98c897f 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -52,7 +52,7 @@ PublicVolume::~PublicVolume() { } status_t PublicVolume::readMetadata() { - status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel); + status_t res = ReadMetadataUntrusted(mDevPath, &mFsType, &mFsUuid, &mFsLabel); auto listener = getListener(); if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel); diff --git a/tests/Android.mk b/tests/Android.mk index 3127352..8f2cda7 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -12,6 +12,7 @@ LOCAL_STATIC_LIBRARIES := libbase libselinux libvold liblog libcrypto LOCAL_SRC_FILES := \ cryptfs_test.cpp \ + Utils_test.cpp \ VolumeManager_test.cpp \ LOCAL_MODULE := vold_tests diff --git a/tests/Utils_test.cpp b/tests/Utils_test.cpp new file mode 100644 index 0000000..ab9809e --- /dev/null +++ b/tests/Utils_test.cpp @@ -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 + +#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); +} + +} +} From 01a0e7fa189b37b82be971bc50ecce5883523293 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 17 Oct 2017 16:06:32 -0600 Subject: [PATCH 030/106] Fix task memory leaks; better path validation. We've been allocating task objects without freeing them, oops. We don't really need full classes for these tasks, so move them to blocking methods, and invoke them from a detached thread. Remove FIDTRIM support, which isn't meaningful on UFS-based flash devices. Modern devices require FBE/FDE which gives us better protection against trimmed data lingering around. Rename "Trim" to more generic "IdleMaint", since it'll soon extend to include custom F2FS optimization logic. Check for shady ".." when validating paths. Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Bug: 67041047 Change-Id: I4fb194c5d5ef13f413c02acedfbaaf79c567582b --- Android.mk | 6 +- BenchmarkTask.cpp => Benchmark.cpp | 42 ++++++------- BenchmarkTask.h => Benchmark.h | 25 ++------ TrimTask.cpp => IdleMaint.cpp | 53 +++++++---------- TrimTask.h => IdleMaint.h | 31 +--------- MoveTask.cpp => MoveStorage.cpp | 95 +++++++++++++++--------------- MoveStorage.h | 32 ++++++++++ MoveTask.h | 57 ------------------ VoldNativeService.cpp | 25 ++++++-- 9 files changed, 149 insertions(+), 217 deletions(-) rename BenchmarkTask.cpp => Benchmark.cpp (82%) rename BenchmarkTask.h => Benchmark.h (61%) rename TrimTask.cpp => IdleMaint.cpp (78%) rename TrimTask.h => IdleMaint.h (57%) rename MoveTask.cpp => MoveStorage.cpp (76%) create mode 100644 MoveStorage.h delete mode 100644 MoveTask.h diff --git a/Android.mk b/Android.mk index f1804b6..8cbc1d4 100644 --- a/Android.mk +++ b/Android.mk @@ -20,9 +20,9 @@ common_src_files := \ model/EmulatedVolume.cpp \ model/ObbVolume.cpp \ Utils.cpp \ - MoveTask.cpp \ - BenchmarkTask.cpp \ - TrimTask.cpp \ + MoveStorage.cpp \ + Benchmark.cpp \ + IdleMaint.cpp \ KeyBuffer.cpp \ Keymaster.cpp \ KeyStorage.cpp \ diff --git a/BenchmarkTask.cpp b/Benchmark.cpp similarity index 82% rename from BenchmarkTask.cpp rename to Benchmark.cpp index d10d792..63b4dd3 100644 --- a/BenchmarkTask.cpp +++ b/Benchmark.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "BenchmarkTask.h" +#include "Benchmark.h" #include "BenchmarkGen.h" #include "VolumeManager.h" @@ -24,6 +24,8 @@ #include #include +#include + #include #include #include @@ -36,21 +38,10 @@ using android::base::WriteStringToFile; namespace android { namespace vold { -static const char* kWakeLock = "BenchmarkTask"; +static const char* kWakeLock = "Benchmark"; -BenchmarkTask::BenchmarkTask(const std::string& path, - const android::sp& listener) : - mPath(path), mListener(listener) { -} - -BenchmarkTask::~BenchmarkTask() { -} - -void BenchmarkTask::start() { - mThread = std::thread(&BenchmarkTask::run, this); -} - -static status_t runInternal(const std::string& rootPath, android::os::PersistableBundle& extras) { +static status_t benchmarkInternal(const std::string& rootPath, + android::os::PersistableBundle* extras) { auto path = rootPath; path += "/misc"; if (android::vold::PrepareDir(path, 01771, AID_SYSTEM, AID_MISC)) { @@ -143,23 +134,24 @@ static status_t runInternal(const std::string& rootPath, android::os::Persistabl LOG(INFO) << "run took " << nanoseconds_to_milliseconds(run_d) << "ms"; LOG(INFO) << "destroy took " << nanoseconds_to_milliseconds(destroy_d) << "ms"; - extras.putString(String16("path"), String16(path.c_str())); - extras.putString(String16("ident"), String16(BenchmarkIdent().c_str())); - extras.putLong(String16("create"), create_d); - extras.putLong(String16("drop"), drop_d); - extras.putLong(String16("run"), run_d); - extras.putLong(String16("destroy"), destroy_d); + extras->putString(String16("path"), String16(path.c_str())); + extras->putString(String16("ident"), String16(BenchmarkIdent().c_str())); + extras->putLong(String16("create"), create_d); + extras->putLong(String16("drop"), drop_d); + extras->putLong(String16("run"), run_d); + extras->putLong(String16("destroy"), destroy_d); return 0; } -void BenchmarkTask::run() { +void Benchmark(const std::string& path, + const android::sp& listener) { acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); android::os::PersistableBundle extras; - status_t res = runInternal(mPath, extras); - if (mListener) { - mListener->onFinished(res, extras); + status_t res = benchmarkInternal(path, &extras); + if (listener) { + listener->onFinished(res, extras); } release_wake_lock(kWakeLock); diff --git a/BenchmarkTask.h b/Benchmark.h similarity index 61% rename from BenchmarkTask.h rename to Benchmark.h index dfa3922..4f19b01 100644 --- a/BenchmarkTask.h +++ b/Benchmark.h @@ -14,35 +14,18 @@ * limitations under the License. */ -#ifndef ANDROID_VOLD_BENCHMARK_TASK_H -#define ANDROID_VOLD_BENCHMARK_TASK_H +#ifndef ANDROID_VOLD_BENCHMARK_H +#define ANDROID_VOLD_BENCHMARK_H #include "android/os/IVoldTaskListener.h" -#include "Utils.h" #include -#include namespace android { namespace vold { -class BenchmarkTask { -public: - BenchmarkTask(const std::string& path, - const android::sp& listener); - virtual ~BenchmarkTask(); - - void start(); - -private: - std::string mPath; - android::sp mListener; - std::thread mThread; - - void run(); - - DISALLOW_COPY_AND_ASSIGN(BenchmarkTask); -}; +void Benchmark(const std::string& path, + const android::sp& listener); } // namespace vold } // namespace android diff --git a/TrimTask.cpp b/IdleMaint.cpp similarity index 78% rename from TrimTask.cpp rename to IdleMaint.cpp index 2718095..ed6374f 100644 --- a/TrimTask.cpp +++ b/IdleMaint.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "TrimTask.h" +#include "IdleMaint.h" #include "Utils.h" #include "VolumeManager.h" @@ -31,36 +31,26 @@ #include #include -/* From a would-be kernel header */ -#define FIDTRIM _IOWR('f', 128, struct fstrim_range) /* Deep discard trim */ - using android::base::StringPrintf; namespace android { namespace vold { -static const char* kWakeLock = "TrimTask"; - -TrimTask::TrimTask(int flags, const android::sp& listener) : - mFlags(flags), mListener(listener) { - // Collect both fstab and vold volumes - addFromFstab(); +static const char* kWakeLock = "IdleMaint"; +static void addFromVolumeManager(std::list* paths) { VolumeManager* vm = VolumeManager::Instance(); std::list 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()); + paths->push_back(vol->getPath()); } } } -TrimTask::~TrimTask() { -} - -void TrimTask::addFromFstab() { +static void addFromFstab(std::list* paths) { std::unique_ptr fstab(fs_mgr_read_fstab_default(), fs_mgr_free_fstab); struct fstab_rec *prev_rec = NULL; @@ -89,19 +79,20 @@ void TrimTask::addFromFstab() { continue; } - mPaths.push_back(fstab->recs[i].mount_point); + paths->push_back(fstab->recs[i].mount_point); prev_rec = &fstab->recs[i]; } } -void TrimTask::start() { - mThread = std::thread(&TrimTask::run, this); -} - -void TrimTask::run() { +void Trim(const android::sp& listener) { acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); - for (const auto& path : mPaths) { + // Collect both fstab and vold volumes + std::list paths; + addFromFstab(&paths); + addFromVolumeManager(&paths); + + for (const auto& path : paths) { LOG(DEBUG) << "Starting trim of " << path; android::os::PersistableBundle extras; @@ -110,8 +101,8 @@ void TrimTask::run() { int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); if (fd < 0) { PLOG(WARNING) << "Failed to open " << path; - if (mListener) { - mListener->onStatus(-1, extras); + if (listener) { + listener->onStatus(-1, extras); } continue; } @@ -121,10 +112,10 @@ void TrimTask::run() { range.len = ULLONG_MAX; nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); - if (ioctl(fd, (mFlags & Flags::kDeepTrim) ? FIDTRIM : FITRIM, &range)) { + if (ioctl(fd, FITRIM, &range)) { PLOG(WARNING) << "Trim failed on " << path; - if (mListener) { - mListener->onStatus(-1, extras); + if (listener) { + listener->onStatus(-1, extras); } } else { nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start; @@ -132,16 +123,16 @@ void TrimTask::run() { << " in " << nanoseconds_to_milliseconds(time) << "ms"; extras.putLong(String16("bytes"), range.len); extras.putLong(String16("time"), time); - if (mListener) { - mListener->onStatus(0, extras); + if (listener) { + listener->onStatus(0, extras); } } close(fd); } - if (mListener) { + if (listener) { android::os::PersistableBundle extras; - mListener->onFinished(0, extras); + listener->onFinished(0, extras); } release_wake_lock(kWakeLock); diff --git a/TrimTask.h b/IdleMaint.h similarity index 57% rename from TrimTask.h rename to IdleMaint.h index a87728b..38dadfb 100644 --- a/TrimTask.h +++ b/IdleMaint.h @@ -14,40 +14,15 @@ * limitations under the License. */ -#ifndef ANDROID_VOLD_TRIM_TASK_H -#define ANDROID_VOLD_TRIM_TASK_H +#ifndef ANDROID_VOLD_IDLE_MAINT_H +#define ANDROID_VOLD_IDLE_MAINT_H #include "android/os/IVoldTaskListener.h" -#include "Utils.h" - -#include -#include namespace android { namespace vold { -class TrimTask { -public: - explicit TrimTask(int flags, const android::sp& listener); - virtual ~TrimTask(); - - enum Flags { - kDeepTrim = 1 << 0, - }; - - void start(); - -private: - int mFlags; - android::sp mListener; - std::list mPaths; - std::thread mThread; - - void addFromFstab(); - void run(); - - DISALLOW_COPY_AND_ASSIGN(TrimTask); -}; +void Trim(const android::sp& listener); } // namespace vold } // namespace android diff --git a/MoveTask.cpp b/MoveStorage.cpp similarity index 76% rename from MoveTask.cpp rename to MoveStorage.cpp index 4268ed4..4f5ebe8 100644 --- a/MoveTask.cpp +++ b/MoveStorage.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "MoveTask.h" +#include "MoveStorage.h" #include "Utils.h" #include "VolumeManager.h" @@ -23,6 +23,8 @@ #include #include +#include + #include #include @@ -44,22 +46,11 @@ static const char* kRmPath = "/system/bin/rm"; static const char* kWakeLock = "MoveTask"; -MoveTask::MoveTask(const std::shared_ptr& from, const std::shared_ptr& to, - const android::sp& listener) : - mFrom(from), mTo(to), mListener(listener) { -} - -MoveTask::~MoveTask() { -} - -void MoveTask::start() { - mThread = std::thread(&MoveTask::run, this); -} - -void MoveTask::notifyProgress(int progress) { - if (mListener) { +static void notifyProgress(int progress, + const android::sp& listener) { + if (listener) { android::os::PersistableBundle extras; - mListener->onStatus(progress, extras); + listener->onStatus(progress, extras); } } @@ -86,8 +77,9 @@ static status_t pushBackContents(const std::string& path, std::vector& listener) { + notifyProgress(startProgress, listener); uint64_t expectedBytes = GetTreeBytes(path); uint64_t startFreeBytes = GetFreeBytes(path); @@ -121,15 +113,15 @@ status_t MoveTask::execRm(const std::string& path, int startProgress, int stepPr 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 } -status_t MoveTask::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& listener) { + notifyProgress(startProgress, listener); uint64_t expectedBytes = GetTreeBytes(fromPath); uint64_t startFreeBytes = GetFreeBytes(toPath); @@ -172,7 +164,7 @@ status_t MoveTask::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 @@ -192,69 +184,80 @@ static void bringOnline(const std::shared_ptr& vol) { vol->create(); } -void MoveTask::run() { - acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); - +static status_t moveStorageInternal(const std::shared_ptr& from, + const std::shared_ptr& to, + const android::sp& 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 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 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 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& from, const std::shared_ptr& to, + const android::sp& 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 diff --git a/MoveStorage.h b/MoveStorage.h new file mode 100644 index 0000000..d271704 --- /dev/null +++ b/MoveStorage.h @@ -0,0 +1,32 @@ +/* + * 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 ANDROID_VOLD_MOVE_STORAGE_H +#define ANDROID_VOLD_MOVE_STORAGE_H + +#include "android/os/IVoldTaskListener.h" +#include "model/VolumeBase.h" + +namespace android { +namespace vold { + +void MoveStorage(const std::shared_ptr& from, const std::shared_ptr& to, + const android::sp& listener); + +} // namespace vold +} // namespace android + +#endif diff --git a/MoveTask.h b/MoveTask.h deleted file mode 100644 index 246a24d..0000000 --- a/MoveTask.h +++ /dev/null @@ -1,57 +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 ANDROID_VOLD_MOVE_TASK_H -#define ANDROID_VOLD_MOVE_TASK_H - -#include "android/os/IVoldTaskListener.h" -#include "Utils.h" -#include "model/VolumeBase.h" - -#include - -namespace android { -namespace vold { - -class MoveTask { -public: - MoveTask(const std::shared_ptr& from, const std::shared_ptr& to, - const android::sp& listener); - virtual ~MoveTask(); - - void start(); - -private: - std::shared_ptr mFrom; - std::shared_ptr mTo; - android::sp mListener; - std::thread mThread; - - void run(); - - void notifyProgress(int progress); - - status_t execRm(const std::string& path, int startProgress, int stepProgress); - status_t execCp(const std::string& fromPath, const std::string& toPath, - int startProgress, int stepProgress); - - DISALLOW_COPY_AND_ASSIGN(MoveTask); -}; - -} // namespace vold -} // namespace android - -#endif diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index c82eb92..d8832d3 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -18,16 +18,17 @@ #include "VoldNativeService.h" #include "VolumeManager.h" -#include "BenchmarkTask.h" -#include "MoveTask.h" +#include "Benchmark.h" +#include "MoveStorage.h" #include "Process.h" -#include "TrimTask.h" +#include "IdleMaint.h" #include "cryptfs.h" #include "Ext4Crypt.h" #include "MetadataCrypt.h" #include +#include #include #include @@ -120,6 +121,10 @@ binder::Status checkArgumentPath(const std::string& path) { 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, @@ -377,7 +382,9 @@ binder::Status VoldNativeService::benchmark(const std::string& volId, return error("Volume " + volId + " missing path"); } - (new android::vold::BenchmarkTask(path, listener))->start(); + std::thread([=]() { + android::vold::Benchmark(path, listener); + }).detach(); return ok(); } @@ -395,7 +402,10 @@ binder::Status VoldNativeService::moveStorage(const std::string& fromVolId, } else if (toVol == nullptr) { return error("Failed to find volume " + toVolId); } - (new android::vold::MoveTask(fromVol, toVol, listener))->start(); + + std::thread([=]() { + android::vold::MoveStorage(fromVol, toVol, listener); + }).detach(); return ok(); } @@ -446,7 +456,9 @@ binder::Status VoldNativeService::fstrim(int32_t fstrimFlags, ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; - (new android::vold::TrimTask(fstrimFlags, listener))->start(); + std::thread([=]() { + android::vold::Trim(listener); + }).detach(); return ok(); } @@ -712,6 +724,7 @@ binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr Date: Wed, 18 Oct 2017 12:17:35 -0600 Subject: [PATCH 031/106] Get ourselves some clang-format. These are the same rules used by system/core/. We'll apply it to existing code in a future CL. Test: none Bug: 67041047 Change-Id: I407581a9ba155aea87ac87f231f5269f7c444a2e --- .clang-format | 11 +++++++++++ PREUPLOAD.cfg | 5 +++++ 2 files changed, 16 insertions(+) create mode 100644 .clang-format create mode 100644 PREUPLOAD.cfg diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ae4a451 --- /dev/null +++ b/.clang-format @@ -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 diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg new file mode 100644 index 0000000..c8dbf77 --- /dev/null +++ b/PREUPLOAD.cfg @@ -0,0 +1,5 @@ +[Builtin Hooks] +clang_format = true + +[Builtin Hooks Options] +clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp From 68f1b8bdfb657dcf2201b20e73f4557d38b44885 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 18 Oct 2017 14:09:52 -0600 Subject: [PATCH 032/106] Use sgdisk to create better-aligned MBR tables. We heavily leverage sgdisk, which already has a bunch of logic to optimally align partitions. We've been using it for the adoptable storage GPT tables, and now we also use it for MBR tables. Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Bug: 63735902 Change-Id: I846a8c96930ec2c6ab12e54dc2d464b17f7c54a9 --- model/Disk.cpp | 46 ++++++++++++---------------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/model/Disk.cpp b/model/Disk.cpp index 291c2e1..14de74f 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -416,7 +415,6 @@ status_t Disk::unmountAll() { status_t Disk::partitionPublic() { int res; - // TODO: improve this code destroyAllVolumes(); mJustPartitioned = true; @@ -432,41 +430,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() { From 93396c14a8267d52ea45997479abc4b38ea428db Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 18 Oct 2017 16:52:48 -0600 Subject: [PATCH 033/106] Use main thread for Binder transactions. Make the main thread do something useful instead of sitting around twiddling its thumbs. Test: builds, boots Bug: 67041047 Change-Id: I88f7f4fe151ae2b81f80aa575530c12b56ba4d75 --- main.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/main.cpp b/main.cpp index cca738e..01a2168 100644 --- a/main.cpp +++ b/main.cpp @@ -130,12 +130,9 @@ int main(int argc, char** argv) { ATRACE_END(); - // Eventually we'll become the monitoring thread - while(1) { - pause(); - } + android::IPCThreadState::self()->joinThreadPool(); + LOG(INFO) << "vold shutting down"; - LOG(ERROR) << "Vold exiting"; exit(0); } From ae4f85d2ff11079bd79650a61745a89fa695ed4a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 18 Oct 2017 17:02:21 -0600 Subject: [PATCH 034/106] Introduce lock for SELinux process-level changes. Used to protect process-level SELinux changes from racing with each other between multiple threads. Test: builds, boots Bug: 67041047 Change-Id: I242afed3c3eb7fba282f1f6b3bdb2d957417c7e8 --- Utils.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Utils.cpp b/Utils.cpp index 484de90..9c19190 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -60,7 +60,12 @@ 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 lock(kSecurityLock); const char* cpath = path.c_str(); status_t res = 0; @@ -98,6 +103,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 lock(kSecurityLock); const char* cpath = path.c_str(); char* secontext = nullptr; @@ -251,6 +257,7 @@ status_t ForkExecvp(const std::vector& args) { } status_t ForkExecvp(const std::vector& args, security_context_t context) { + std::lock_guard lock(kSecurityLock); size_t argc = args.size(); char** argv = (char**) calloc(argc, sizeof(char*)); for (size_t i = 0; i < argc; i++) { @@ -283,6 +290,7 @@ status_t ForkExecvp(const std::vector& args, status_t ForkExecvp(const std::vector& args, std::vector& output, security_context_t context) { + std::lock_guard lock(kSecurityLock); std::string cmd; for (size_t i = 0; i < args.size(); i++) { cmd += args[i] + " "; From 8646da062aef442945d2130b87819ecd36bc63c0 Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Thu, 19 Oct 2017 11:51:20 -0700 Subject: [PATCH 035/106] Use -Werror in system/vold/tests * Comment out unused function. Bug: 66996870 Test: build with WITH_TIDY=1 Change-Id: I7a23573af0d664a5f39f1cde3a22ac0001dac1ac --- tests/Android.mk | 2 ++ tests/CryptfsScryptHidlizationEquivalence_test.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/Android.mk b/tests/Android.mk index 8f2cda7..49da010 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -18,6 +18,7 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := vold_tests LOCAL_MODULE_TAGS := eng tests +LOCAL_CFLAGS := -Wall -Werror include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) @@ -41,4 +42,5 @@ LOCAL_SRC_FILES := CryptfsScryptHidlizationEquivalence_test.cpp LOCAL_MODULE := vold_cryptfs_scrypt_hidlization_equivalence_test LOCAL_MODULE_TAGS := eng tests +LOCAL_CFLAGS := -Wall -Werror include $(BUILD_NATIVE_TEST) diff --git a/tests/CryptfsScryptHidlizationEquivalence_test.cpp b/tests/CryptfsScryptHidlizationEquivalence_test.cpp index 91ddb2b..3a6c029 100644 --- a/tests/CryptfsScryptHidlizationEquivalence_test.cpp +++ b/tests/CryptfsScryptHidlizationEquivalence_test.cpp @@ -369,6 +369,7 @@ static int keymaster_check_compatibility_new() return keymaster_compatibility_cryptfs_scrypt(); } +#if 0 /* Create a new keymaster key and store it in this footer */ static int keymaster_create_key_new(struct crypt_mnt_ftr *ftr) { @@ -390,6 +391,7 @@ static int keymaster_create_key_new(struct crypt_mnt_ftr *ftr) } return 0; } +#endif /* This signs the given object using the keymaster key. */ static int keymaster_sign_object_new(struct crypt_mnt_ftr *ftr, From 56292ef1198fbeb6a12c27c7b4f42e89c933e049 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Fri, 20 Oct 2017 08:07:53 -0700 Subject: [PATCH 036/106] Undo Utils dependency on VolumeManager I want to use Utils in another executable, so breaking this link. Bug: 25861755 Test: compiles (and boots, though that doesn't exercise changed code) Change-Id: I6bb447453bb370fefb7f2f3aceb459428bdee6a7 --- Utils.cpp | 20 +++++++++++--------- Utils.h | 3 +++ VolumeManager.cpp | 6 ++---- VolumeManager.h | 4 ---- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 9c19190..1f6ff21 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include "sehandle.h" #include "Utils.h" + #include "Process.h" -#include "VolumeManager.h" +#include "sehandle.h" #include #include @@ -55,6 +55,8 @@ 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"; @@ -134,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); KillProcessesWithOpenFiles(path, SIGINT); - if (!VolumeManager::shutting_down) sleep(5); + if (sSleepOnUnmount) sleep(5); if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } KillProcessesWithOpenFiles(path, SIGTERM); - if (!VolumeManager::shutting_down) sleep(5); + if (sSleepOnUnmount) sleep(5); if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } KillProcessesWithOpenFiles(path, SIGKILL); - if (!VolumeManager::shutting_down) sleep(5); + if (sSleepOnUnmount) sleep(5); if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } @@ -161,17 +163,17 @@ status_t KillProcessesUsingPath(const std::string& path) { if (KillProcessesWithOpenFiles(path, SIGINT) == 0) { return OK; } - if (!VolumeManager::shutting_down) sleep(5); + if (sSleepOnUnmount) sleep(5); if (KillProcessesWithOpenFiles(path, SIGTERM) == 0) { return OK; } - if (!VolumeManager::shutting_down) sleep(5); + if (sSleepOnUnmount) sleep(5); 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 diff --git a/Utils.h b/Utils.h index 9163006..c5955cc 100644 --- a/Utils.h +++ b/Utils.h @@ -38,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); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index c1d51d9..1847ab1 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -62,8 +62,6 @@ using android::base::StringPrintf; using android::base::unique_fd; -bool VolumeManager::shutting_down = false; - static const char* kPathUserMount = "/mnt/user"; static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk"; @@ -535,14 +533,14 @@ int VolumeManager::shutdown() { if (mInternalEmulated == nullptr) { return 0; // already shutdown } - shutting_down = true; + android::vold::sSleepOnUnmount = false; mInternalEmulated->destroy(); mInternalEmulated = nullptr; for (const auto& disk : mDisks) { disk->destroy(); } mDisks.clear(); - shutting_down = false; + android::vold::sSleepOnUnmount = true; return 0; } diff --git a/VolumeManager.h b/VolumeManager.h index 4f62de9..b66aa2f 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -43,10 +43,6 @@ #define DEBUG_APPFUSE 0 class VolumeManager { -public: - //TODO remove this with better solution, b/64143519 - static bool shutting_down; - private: static VolumeManager *sInstance; From d16dc5089b5fdea77577090b6615541f3ff4915b Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 23 Oct 2017 14:38:55 -0600 Subject: [PATCH 037/106] Move vold to Android.bp. Test: builds, boots Bug: 67041047 Change-Id: Ife9118d274fc92d30b38d216f815741a060a04b7 --- Android.bp | 193 ++++++++++++++++++++++++++++++++ Android.mk | 210 ----------------------------------- tests/Android.bp | 14 +++ tests/Android.mk | 46 -------- tests/VolumeManager_test.cpp | 37 ------ 5 files changed, 207 insertions(+), 293 deletions(-) create mode 100644 Android.bp delete mode 100644 Android.mk create mode 100644 tests/Android.bp delete mode 100644 tests/Android.mk delete mode 100644 tests/VolumeManager_test.cpp diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..f7ec836 --- /dev/null +++ b/Android.bp @@ -0,0 +1,193 @@ +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*", + "-cert-err58-cpp", + ], + 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", + "libbase", + "libbinder", + "libcrypto", + "libcrypto_utils", + "libcutils", + "libdiskconfig", + "libext4_utils", + "libf2fs_sparseblock", + "libhardware", + "libhardware_legacy", + "libhidlbase", + "libhwbinder", + "libkeystore_binder", + "libkeyutils", + "liblog", + "liblogwrap", + "libselinux", + "libsysutils", + "libutils", + ], +} + +cc_library_static { + name: "libvold_binder", + defaults: ["vold_default_flags"], + + srcs: [ + "binder/android/os/IVold.aidl", + "binder/android/os/IVoldListener.aidl", + "binder/android/os/IVoldTaskListener.aidl", + ], + shared_libs: [ + "libbinder", + "libutils", + ], + aidl: { + local_include_dirs: ["binder"], + include_dirs: ["frameworks/native/aidl/binder"], + export_aidl_headers: true, + }, +} + +// Static library factored out to support testing +cc_library_static { + name: "libvold", + defaults: [ + "vold_default_flags", + "vold_default_libs", + ], + + srcs: [ + "Benchmark.cpp", + "Devmapper.cpp", + "EncryptInplace.cpp", + "Ext4Crypt.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/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", + ], +} + +cc_binary { + name: "vold", + defaults: [ + "vold_default_flags", + "vold_default_libs", + ], + + srcs: ["main.cpp"], + static_libs: ["libvold"], + init_rc: ["vold.rc"], + + required: [ + "mke2fs", + "vold_prepare_subdirs", + ], +} + +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: "secdiscard", + defaults: ["vold_default_flags"], + + srcs: [ + "FileDeviceUtils.cpp", + "secdiscard.cpp", + ], + shared_libs: ["libbase"], +} + +cc_binary { + name: "prepare_dir", + defaults: ["vold_default_flags"], + + srcs: ["prepare_dir.cpp"], + shared_libs: [ + "libbase", + "libcutils", + "libselinux", + ], +} + +cc_prebuilt_binary { + name: "vold_prepare_subdirs", + defaults: ["vold_default_flags"], + + srcs: ["vold_prepare_subdirs"], + + required: ["prepare_dir"], +} + +subdirs = ["tests"] diff --git a/Android.mk b/Android.mk deleted file mode 100644 index 8cbc1d4..0000000 --- a/Android.mk +++ /dev/null @@ -1,210 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -common_src_files := \ - VolumeManager.cpp \ - NetlinkManager.cpp \ - NetlinkHandler.cpp \ - Process.cpp \ - fs/Ext4.cpp \ - fs/F2fs.cpp \ - fs/Vfat.cpp \ - Loop.cpp \ - Devmapper.cpp \ - Ext4Crypt.cpp \ - VoldUtil.cpp \ - cryptfs.cpp \ - model/Disk.cpp \ - model/VolumeBase.cpp \ - model/PublicVolume.cpp \ - model/PrivateVolume.cpp \ - model/EmulatedVolume.cpp \ - model/ObbVolume.cpp \ - Utils.cpp \ - MoveStorage.cpp \ - Benchmark.cpp \ - IdleMaint.cpp \ - KeyBuffer.cpp \ - Keymaster.cpp \ - KeyStorage.cpp \ - KeyUtil.cpp \ - ScryptParameters.cpp \ - secontext.cpp \ - EncryptInplace.cpp \ - MetadataCrypt.cpp \ - VoldNativeService.cpp \ - -common_aidl_files := \ - binder/android/os/IVold.aidl \ - binder/android/os/IVoldListener.aidl \ - binder/android/os/IVoldTaskListener.aidl \ - -common_aidl_includes := \ - $(LOCAL_PATH)/binder \ - frameworks/native/aidl/binder \ - -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-err58-cpp" once 36656327 is fixed -common_local_tidy_enabled := true -common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-* -common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err58-cpp - -vold_conlyflags := -std=c11 -vold_cflags := -Werror -Wall -Wno-missing-field-initializers -Wno-unused-variable -Wno-unused-parameter - -required_modules := vold_prepare_subdirs -ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) - required_modules += mke2fs -endif - -include $(CLEAR_VARS) - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_MODULE := libvold -LOCAL_CLANG := true -LOCAL_TIDY := $(common_local_tidy_enabled) -LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) -LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) -LOCAL_SRC_FILES := $(common_src_files) $(common_aidl_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) - -LOCAL_AIDL_INCLUDES := $(common_aidl_includes) - -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_MODULE := vold -LOCAL_CLANG := true -LOCAL_TIDY := $(common_local_tidy_enabled) -LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) -LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) -LOCAL_SRC_FILES := \ - main.cpp \ - $(common_src_files) \ - $(common_aidl_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) - -LOCAL_AIDL_INCLUDES := $(common_aidl_includes) - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_CLANG := true -LOCAL_TIDY := $(common_local_tidy_enabled) -LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) -LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) - -LOCAL_SRC_FILES := \ - vdc.cpp \ - $(common_aidl_files) \ - -LOCAL_MODULE := vdc -LOCAL_SHARED_LIBRARIES := libbase libbinder libcutils libutils -LOCAL_CFLAGS := $(vold_cflags) -LOCAL_CONLYFLAGS := $(vold_conlyflags) -LOCAL_INIT_RC := vdc.rc - -LOCAL_AIDL_INCLUDES := $(common_aidl_includes) - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_CLANG := true -LOCAL_TIDY := $(common_local_tidy_enabled) -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 $(CLEAR_VARS) - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_CLANG := true -LOCAL_TIDY := $(common_local_tidy_enabled) -LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) -LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) -LOCAL_SRC_FILES:= \ - prepare_dir.cpp \ - -LOCAL_MODULE:= prepare_dir -LOCAL_SHARED_LIBRARIES := libbase libcutils libselinux -LOCAL_CFLAGS := $(vold_cflags) -LOCAL_CONLYFLAGS := $(vold_conlyflags) - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) - -LOCAL_MODULE:= vold_prepare_subdirs -LOCAL_MODULE_CLASS := EXECUTABLES -LOCAL_SRC_FILES := vold_prepare_subdirs -LOCAL_REQUIRED_MODULES := prepare_dir - -include $(BUILD_PREBUILT) - -include $(LOCAL_PATH)/tests/Android.mk diff --git a/tests/Android.bp b/tests/Android.bp new file mode 100644 index 0000000..a070178 --- /dev/null +++ b/tests/Android.bp @@ -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"], +} diff --git a/tests/Android.mk b/tests/Android.mk deleted file mode 100644 index 49da010..0000000 --- a/tests/Android.mk +++ /dev/null @@ -1,46 +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 \ - system/vold/ - -LOCAL_STATIC_LIBRARIES := libbase libselinux libvold liblog libcrypto - -LOCAL_SRC_FILES := \ - cryptfs_test.cpp \ - Utils_test.cpp \ - 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 - -LOCAL_CFLAGS := -Wall -Werror -include $(BUILD_NATIVE_TEST) diff --git a/tests/VolumeManager_test.cpp b/tests/VolumeManager_test.cpp deleted file mode 100644 index f661d49..0000000 --- a/tests/VolumeManager_test.cpp +++ /dev/null @@ -1,37 +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 - -#define LOG_TAG "VolumeManager_test" -#include -#include -#include "../VolumeManager.h" - -#include - -namespace android { - -class VolumeManagerTest : public testing::Test { -protected: - virtual void SetUp() { - } - - virtual void TearDown() { - } -}; - -} From 5889083d719432f466ebf0f271b21d8141b67a14 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Mon, 23 Oct 2017 17:12:31 -0700 Subject: [PATCH 038/106] Check that dir name is a pid before attempting to read Prevents selinux denials for folders in /proc that do not have the default /proc label. Bug: 68146208 Test: no selinux denials for vold attempting to read proc_asound dir. Change-Id: I7cdd3bbe8e687e078372012773e9a34a5c76e0f8 --- VolumeManager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index c1d51d9..f367c2a 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -34,9 +34,11 @@ #include #include +#include #include -#include #include +#include + #include #include @@ -420,6 +422,10 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) { // Poke through all running PIDs look for apps running as UID while ((de = readdir(dir))) { + pid_t pid; + if (de->d_type != DT_DIR) continue; + if (!android::base::ParseInt(de->d_name, &pid)) continue; + pidFd = -1; nsFd = -1; From 3ce18256a1e2edf830830f066e5ddb4c8203111b Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 24 Oct 2017 11:08:45 -0600 Subject: [PATCH 039/106] Pass both partition GUID and filesystem UUID. FDE keys are indexed using the partition GUID, while FBE keys will be indexed using the filesystem UUID, so pass both of those identifiers along when forgetting a volume. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Bug: 25861755 Change-Id: I6e239d5ba67a01c9a848d705f6167da00f975924 --- VoldNativeService.cpp | 6 ++++-- VoldNativeService.h | 2 +- VolumeManager.cpp | 2 +- VolumeManager.h | 2 +- binder/android/os/IVold.aidl | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index d8832d3..0053478 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -302,12 +302,14 @@ binder::Status VoldNativeService::partition(const std::string& diskId, int32_t p } } -binder::Status VoldNativeService::forgetPartition(const std::string& partGuid) { +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)); + return translate(VolumeManager::Instance()->forgetPartition(partGuid, fsUuid)); } binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, diff --git a/VoldNativeService.h b/VoldNativeService.h index dd2b854..8368bdc 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -44,7 +44,7 @@ public: binder::Status onUserStopped(int32_t userId); binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio); - binder::Status forgetPartition(const std::string& partGuid); + binder::Status 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); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index befb54d..3194e59 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -293,7 +293,7 @@ void VolumeManager::listVolumes(android::vold::VolumeBase::Type type, } } -int VolumeManager::forgetPartition(const std::string& partGuid) { +int VolumeManager::forgetPartition(const std::string& partGuid, const std::string& fsUuid) { std::string normalizedGuid; if (android::vold::NormalizeHex(partGuid, normalizedGuid)) { LOG(WARNING) << "Invalid GUID " << partGuid; diff --git a/VolumeManager.h b/VolumeManager.h index b66aa2f..8a780c4 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -89,7 +89,7 @@ public: void listVolumes(android::vold::VolumeBase::Type type, std::list& list); - 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); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index d47f113..32d9b16 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -34,7 +34,7 @@ interface IVold { void onUserStopped(int userId); void partition(@utf8InCpp String diskId, int partitionType, int ratio); - void forgetPartition(@utf8InCpp String partGuid); + void forgetPartition(@utf8InCpp String partGuid, @utf8InCpp String fsUuid); void mount(@utf8InCpp String volId, int mountFlags, int mountUserId); void unmount(@utf8InCpp String volId); From 82b41ff837a6279c958f6d48aced63f0805b443a Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Fri, 20 Oct 2017 08:17:54 -0700 Subject: [PATCH 040/106] Convert vold_prepare_subdirs to C++ Minimize overhead in boot by replacing shell script invoked multiple times with a C++ program invoked once. Bug: 67901036 Test: create user, run adb shell ls -laZ /data/misc_ce/10; delete user and check logs. Change-Id: I886cfd6505cca1f5b5902f2071e13f48e612214d --- Android.bp | 26 +++--- Ext4Crypt.cpp | 42 ++++------ Utils.cpp | 32 +++++--- prepare_dir.cpp | 82 ------------------- vold_prepare_subdirs | 67 --------------- vold_prepare_subdirs.cpp | 172 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 220 insertions(+), 201 deletions(-) delete mode 100644 prepare_dir.cpp delete mode 100644 vold_prepare_subdirs create mode 100644 vold_prepare_subdirs.cpp diff --git a/Android.bp b/Android.bp index f7ec836..8827d25 100644 --- a/Android.bp +++ b/Android.bp @@ -170,24 +170,20 @@ cc_binary { } cc_binary { - name: "prepare_dir", - defaults: ["vold_default_flags"], - - srcs: ["prepare_dir.cpp"], - shared_libs: [ - "libbase", - "libcutils", - "libselinux", - ], -} - -cc_prebuilt_binary { name: "vold_prepare_subdirs", defaults: ["vold_default_flags"], - srcs: ["vold_prepare_subdirs"], - - required: ["prepare_dir"], + srcs: ["vold_prepare_subdirs.cpp", "Utils.cpp"], + shared_libs: [ + "libbase", + "libcutils", + "liblogwrap", + "libselinux", + "libutils", + ], + static_libs: [ + "libvold_binder", + ], } subdirs = ["tests"] diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 646a032..5f59d35 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -41,6 +41,8 @@ #include +#include "android/os/IVold.h" + #include "cryptfs.h" #define EMULATED_USES_SELINUX 0 @@ -61,10 +63,6 @@ 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 { const std::string device_key_dir = std::string() + DATA_MNT_POINT + e4crypt_unencrypted_folder; @@ -73,6 +71,7 @@ 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"; bool s_global_de_initialized = false; @@ -379,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("", 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; } @@ -594,13 +593,12 @@ bool e4crypt_lock_user_key(userid_t user_id) { return true; } -static bool prepare_subdirs(const std::string& action, const std::string& dirtype, - const std::string& volume_uuid, userid_t user_id, - const std::string& path) { - if (0 != android::vold::ForkExecvp(std::vector{"/system/bin/vold_prepare_subdirs", - action, dirtype, volume_uuid, - std::to_string(user_id), path})) { - LOG(ERROR) << "vold_prepare_subdirs failed on: " << path; +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{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; @@ -611,7 +609,7 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ 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); @@ -644,14 +642,9 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ } if (!ensure_policy(de_raw_ref, user_de_path)) return false; } - - if (volume_uuid.empty()) { - if (!prepare_subdirs("prepare", "misc_de", volume_uuid, user_id, misc_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); @@ -678,8 +671,6 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ } if (volume_uuid.empty()) { - if (!prepare_subdirs("prepare", "misc_ce", volume_uuid, user_id, misc_ce_path)) - return false; // Now that credentials have been installed, we can run restorecon // over these paths // NOTE: these paths need to be kept in sync with libselinux @@ -687,6 +678,7 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ android::vold::RestoreconRecursive(misc_ce_path); } } + if (!prepare_subdirs("prepare", volume_uuid, user_id, flags)) return false; return true; } @@ -696,7 +688,9 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ << ", user " << user_id << ", flags " << flags; bool res = true; - if (flags & FLAG_STORAGE_CE) { + 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); @@ -706,13 +700,12 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ res &= destroy_dir(media_ce_path); res &= destroy_dir(user_ce_path); if (volume_uuid.empty()) { - res &= prepare_subdirs("destroy", "misc_ce", volume_uuid, user_id, misc_ce_path); res &= destroy_dir(system_ce_path); res &= destroy_dir(misc_ce_path); } } - 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); @@ -725,7 +718,6 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ res &= destroy_dir(user_de_path); if (volume_uuid.empty()) { - res &= prepare_subdirs("destroy", "misc_de", volume_uuid, user_id, misc_de_path); res &= destroy_dir(system_legacy_path); #if MANAGE_MISC_DIRS res &= destroy_dir(misc_legacy_path); diff --git a/Utils.cpp b/Utils.cpp index 1f6ff21..38edcb3 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -271,14 +271,18 @@ status_t ForkExecvp(const std::vector& 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); @@ -304,14 +308,18 @@ status_t ForkExecvp(const std::vector& 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) { diff --git a/prepare_dir.cpp b/prepare_dir.cpp deleted file mode 100644 index 1d91458..0000000 --- a/prepare_dir.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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 -#include - -#include -#include -#include - -#include - -#include -#include - -void usage(const char* progname) { - fprintf(stderr, "Usage: %s --mode MODE --uid UID --gid GID -- \n", progname); -} - -bool small_int(const std::string& s) { - return !s.empty() && s.size() < 7 && s.find_first_not_of("0123456789") == std::string::npos; -} - -int main(int argc, const char* const argv[]) { - setenv("ANDROID_LOG_TAGS", "*:v", 1); - android::base::InitLogging(const_cast(argv)); - std::vector args(argv + 1, argv + argc); - // Enforce exact format of arguments. You can always loosen but you can never tighten :) - if (args.size() != 8 || args[0] != "--mode" || !small_int(args[1]) || args[2] != "--uid" || - !small_int(args[3]) || args[4] != "--gid" || !small_int(args[5]) || args[6] != "--") { - usage(argv[0]); - return -1; - } - mode_t mode = (mode_t)stoi(args[1], nullptr, 8); - uid_t uid = (uid_t)stoi(args[3]); - gid_t gid = (gid_t)stoi(args[5]); - const char* path = args[7].c_str(); - - struct selabel_handle* sehandle = selinux_android_file_context_handle(); - char* secontext = nullptr; - if (sehandle) { - if (selabel_lookup(sehandle, &secontext, path, S_IFDIR) == 0) { - setfscreatecon(secontext); - } - } - - if (fs_prepare_dir(path, mode, uid, gid) != 0) { - return -1; - } - if (secontext) { - char* oldsecontext = nullptr; - if (lgetfilecon(path, &oldsecontext) < 0) { - PLOG(ERROR) << "Unable to read secontext for: " << path; - return -1; - } - if (strcmp(secontext, oldsecontext) != 0) { - LOG(INFO) << "Relabelling from " << oldsecontext << " to " << secontext << ": " << path; - if (lsetfilecon(path, secontext) != 0) { - PLOG(ERROR) << "Relabelling failed for: " << path; - } - } - } - return 0; -} diff --git a/vold_prepare_subdirs b/vold_prepare_subdirs deleted file mode 100644 index cdea243..0000000 --- a/vold_prepare_subdirs +++ /dev/null @@ -1,67 +0,0 @@ -#!/system/bin/sh -# -# 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. - -# Set up or tear down subdirectories of vold-created directories. -# -# This is kept separate from vold because under the SELinux rules, it has privileges vold doesn't -# have. In particular, prepare_dir sets SELinux labels on subdirectories based on file_contexts, -# so this script has some relabelling privileges. - - -set -e -action="$1" -dirtype="$2" -volume_uuid="$3" -user_id="$4" -path="$5" - -case "$user_id" in - *[!0-9]* | '') - echo "Invalid user id" - exit -1 - ;; -esac - -if [ x"$volume_uuid" != x ] ; then - echo "Volume must be root volume" - exit -1; -fi - -case "$dirtype" in - misc_de|misc_ce) - computed_path="/data/$dirtype/$user_id" - if [ x"$computed_path" != x"$path" ] ; then - echo "Parameter path didn't match computed path: " $computed_path - exit -1; - fi - case "$action" in - prepare) - /system/bin/prepare_dir --mode 700 --uid 0 --gid 0 -- "$computed_path"/vold - ;; - destroy) - rm -rf "$computed_path"/* - ;; - *) - echo "Unknown action: $action" - exit -1 - ;; - esac - ;; - *) - echo "Unknown type: $dirtype" - exit -1 - ;; -esac diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp new file mode 100644 index 0000000..6dba5b3 --- /dev/null +++ b/vold_prepare_subdirs.cpp @@ -0,0 +1,172 @@ +/* + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "Utils.h" +#include "android/os/IVold.h" + +static void usage(const char* progname) { + std::cerr << "Usage: " << progname << " [ prepare | destroy ] " + << 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(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(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(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{"/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 (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; + } + } + 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); + } + if (flags & android::os::IVold::STORAGE_FLAG_DE) { + auto misc_de_path = android::vold::BuildDataMiscDePath(user_id); + res &= rmrf_contents(misc_de_path); + } + } + return res; +} + +int main(int argc, const char* const argv[]) { + android::base::InitLogging(const_cast(argv)); + std::vector 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; +} From 3aa914d4a9f08f60999c7188427c2f02cc807962 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 9 Oct 2017 16:35:51 -0700 Subject: [PATCH 041/106] Give SD cards their own keys and modes. When we set up encryption on real volumes - not just /data - we should give them their own keys, so that these keys can be deleted when the volume is forgotten. Also, we must choose the encryption modes differently, since ICE encryption which works on /data may not work on such volumes. Bug: 25861755 Test: boot device, add SD card, check modes. Change-Id: I354cd651757c3566dba046ae99d324833ad9b0e5 --- Ext4Crypt.cpp | 112 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 5f59d35..dc0f191 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -21,7 +21,6 @@ #include "Utils.h" #include "VoldUtil.h" - #include #include #include @@ -56,6 +55,7 @@ #include #include +#include #include using android::base::StringPrintf; @@ -65,6 +65,12 @@ using android::vold::KeyBuffer; 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"; @@ -262,26 +268,19 @@ static bool lookup_key_ref(const std::map& key_map, useri return true; } -static void get_file_encryption_modes(const char **contents_mode_ret, - const char **filenames_mode_ret) -{ +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); - fs_mgr_get_file_encryption_modes(rec, contents_mode_ret, filenames_mode_ret); + 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; } -static bool ensure_policy(const std::string& raw_ref, const std::string& path) { - const char *contents_mode; - const char *filenames_mode; - - 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) { @@ -336,23 +335,21 @@ bool e4crypt_initialize_global_de() { return true; } - const char *contents_mode; - const char *filenames_mode; - 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, 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; } @@ -502,6 +499,31 @@ static bool parse_hex(const std::string& hex, std::string* result) { return true; } +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 bool read_or_create_volkey(const std::string& misc_path, const std::string& volume_uuid, + PolicyKeyRef* key_ref) { + 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; + } + if (!android::vold::retrieveAndInstallKey(true, 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) { + return android::vold::destroyKey(volkey_path(misc_path, volume_uuid)); +} + 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 @@ -634,13 +656,16 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ 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; + PolicyKeyRef de_ref; if (volume_uuid.empty()) { - if (!ensure_policy(de_raw_ref, system_de_path)) return false; - if (!ensure_policy(de_raw_ref, misc_de_path)) return false; + 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; + } else { + if (!read_or_create_volkey(misc_de_path, volume_uuid, &de_ref)) return false; } - if (!ensure_policy(de_raw_ref, user_de_path)) return false; + if (!ensure_policy(de_ref, user_de_path)) return false; } } @@ -659,15 +684,18 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ 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; + PolicyKeyRef ce_ref; if (volume_uuid.empty()) { - if (!ensure_policy(ce_raw_ref, system_ce_path)) return false; - if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false; + 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; + } else { + if (!read_or_create_volkey(misc_ce_path, volume_uuid, &ce_ref)) return false; } - if (!ensure_policy(ce_raw_ref, media_ce_path)) return false; - if (!ensure_policy(ce_raw_ref, user_ce_path)) 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()) { @@ -702,6 +730,10 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ if (volume_uuid.empty()) { res &= destroy_dir(system_ce_path); res &= destroy_dir(misc_ce_path); + } else { + if (e4crypt_is_native()) { + res &= destroy_volkey(misc_ce_path, volume_uuid); + } } } @@ -725,6 +757,10 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ res &= destroy_dir(profiles_de_path); res &= destroy_dir(system_de_path); res &= destroy_dir(misc_de_path); + } else { + if (e4crypt_is_native()) { + res &= destroy_volkey(misc_de_path, volume_uuid); + } } } From f39614449d6431ab5d6892d96342600f8faca8f6 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Thu, 19 Oct 2017 14:44:37 -0700 Subject: [PATCH 042/106] Create subdirectories in misc_ce/misc_de for storaged Test: Boot device, check directories created Bug: 63740245 Change-Id: Ie3f593e2cceb99ea7e86614d6b0d7b34f8c7034c --- vold_prepare_subdirs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp index 6dba5b3..02bedde 100644 --- a/vold_prepare_subdirs.cpp +++ b/vold_prepare_subdirs.cpp @@ -124,10 +124,12 @@ static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int fla 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; } 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; From ff19b05e8ecf5349aa2fb0939446c1de760d8c87 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Thu, 26 Oct 2017 11:28:55 -0700 Subject: [PATCH 043/106] Fix errors on non-keymaster keys If it's not a keymaster key, don't try to invalidate or delete the key blob. Bug: 25861755 Test: Create and forget a volume, check logs and files. Change-Id: If8bfb1a9ab41e6c7e46bc311eb296242e56d264f --- KeyStorage.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/KeyStorage.cpp b/KeyStorage.cpp index 9d61555..143272d 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -499,19 +499,6 @@ static bool deleteKey(const std::string& dir) { return true; } -static bool runSecdiscard(const std::string& dir) { - if (ForkExecvp( - std::vector{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{kSecdiscardPath, "--", @@ -533,8 +520,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{ + 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; } From c6433a299df633c45d714a20fe3672b9b86d9312 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Tue, 24 Oct 2017 14:54:43 -0700 Subject: [PATCH 044/106] Forget keys when we forget the volume. Bug: 25861755 Test: create a volume, forget it, check logs and filesystem. Change-Id: I0ab662969c51703cb046d57b72330e0f14447ef3 --- Ext4Crypt.cpp | 38 +++++++++++++++++++++++++++++++++++++- Ext4Crypt.h | 6 ++---- VolumeManager.cpp | 32 ++++++++++++++++++++------------ 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index dc0f191..495a0fa 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -521,7 +521,9 @@ static bool read_or_create_volkey(const std::string& misc_path, const std::strin } static bool destroy_volkey(const std::string& misc_path, const std::string& volume_uuid) { - return android::vold::destroyKey(volkey_path(misc_path, 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, @@ -767,6 +769,40 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ return res; } +static bool destroy_volume_keys(const std::string& directory_path, const std::string& volume_uuid) { + auto dirp = std::unique_ptr(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); + res &= destroy_volume_keys("/data/misc_ce", volume_uuid); + res &= destroy_volume_keys("/data/misc_de", volume_uuid); + return res; +} + bool e4crypt_secdiscard(const std::string& path) { return android::vold::runSecdiscardSingle(path); } diff --git a/Ext4Crypt.h b/Ext4Crypt.h index d0afd85..4226f15 100644 --- a/Ext4Crypt.h +++ b/Ext4Crypt.h @@ -16,12 +16,8 @@ #include -#include -#include - #include -// General functions bool e4crypt_initialize_global_de(); bool e4crypt_init_user0(); @@ -39,4 +35,6 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ int flags); bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags); +bool e4crypt_destroy_volume_keys(const std::string& volume_uuid); + bool e4crypt_secdiscard(const std::string& path); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 3194e59..f54fb00 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -48,18 +48,21 @@ #include -#include "model/EmulatedVolume.h" -#include "model/ObbVolume.h" -#include "VolumeManager.h" -#include "NetlinkManager.h" +#include + +#include "Devmapper.h" +#include "Ext4Crypt.h" #include "Loop.h" +#include "NetlinkManager.h" +#include "Process.h" +#include "Utils.h" +#include "VoldUtil.h" +#include "VolumeManager.h" +#include "cryptfs.h" #include "fs/Ext4.h" #include "fs/Vfat.h" -#include "Utils.h" -#include "Devmapper.h" -#include "Process.h" -#include "VoldUtil.h" -#include "cryptfs.h" +#include "model/EmulatedVolume.h" +#include "model/ObbVolume.h" using android::base::StringPrintf; using android::base::unique_fd; @@ -300,13 +303,18 @@ int VolumeManager::forgetPartition(const std::string& partGuid, const std::strin return -1; } + bool success = true; std::string keyPath = android::vold::BuildKeyPath(normalizedGuid); if (unlink(keyPath.c_str()) != 0) { LOG(ERROR) << "Failed to unlink " << keyPath; - return -1; + success = false; } - - return 0; + if (e4crypt_is_native()) { + if (!e4crypt_destroy_volume_keys(fsUuid)) { + success = false; + } + } + return success ? 0 : -1; } int VolumeManager::linkPrimary(userid_t userId) { From 26a53888a4efa4a966db189dd0b614f7573b2760 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Thu, 26 Oct 2017 11:16:39 -0700 Subject: [PATCH 045/106] When we forget a volume, forget per-volume key Protect all per-volume-per-user keys with a per-volume key, which is forgotten when the volume is forgotten. This means that the user's key is securely lost even when their storage is encrypted at forgetting time. Bug: 25861755 Test: create a volume, forget it, check logs and filesystem. Change-Id: I8df77bc91bbfa2258e082ddd54d6160dbf39b378 --- Ext4Crypt.cpp | 29 ++++++++++++++++++++--- KeyStorage.cpp | 63 +++++++++++++++++++++++++++++++------------------- KeyStorage.h | 3 +++ KeyUtil.cpp | 10 ++++---- KeyUtil.h | 6 +++-- 5 files changed, 77 insertions(+), 34 deletions(-) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 495a0fa..85ace4a 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -79,6 +79,9 @@ const std::string user_key_dir = std::string() + DATA_MNT_POINT + "/misc/vold/us 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; // Some users are ephemeral, don't try to wipe their keys from disk @@ -336,8 +339,8 @@ bool e4crypt_initialize_global_de() { } PolicyKeyRef device_ref; - if (!android::vold::retrieveAndInstallKey(true, device_key_path, device_key_temp, - &device_ref.key_raw_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); @@ -503,14 +506,32 @@ static std::string volkey_path(const std::string& misc_path, const std::string& 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; } - if (!android::vold::retrieveAndInstallKey(true, key_path, key_path + "_tmp", + 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 = @@ -798,6 +819,8 @@ static bool destroy_volume_keys(const std::string& directory_path, const std::st 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; diff --git a/KeyStorage.cpp b/KeyStorage.cpp index 143272d..8878a3c 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -88,7 +88,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,9 +99,8 @@ 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(&res[0]), &c); - return res; + res->assign(SHA512_DIGEST_LENGTH, '\0'); + SHA512_Final(reinterpret_cast(&(*res)[0]), &c); } static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth, @@ -160,6 +159,30 @@ static bool writeStringToFile(const std::string& payload, const std::string& fil 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, @@ -283,20 +306,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; } @@ -306,7 +320,8 @@ static void logOpensslError() { static bool encryptWithoutKeymaster(const std::string& preKey, const KeyBuffer& plaintext, std::string* ciphertext) { - auto key = hashWithPrefix(kHashPrefix_keygen, preKey); + 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( @@ -356,7 +371,8 @@ static bool decryptWithoutKeymaster(const std::string& preKey, 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_new(), EVP_CIPHER_CTX_free); @@ -410,9 +426,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 +439,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; @@ -467,8 +482,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,7 +491,7 @@ 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()) { diff --git a/KeyStorage.h b/KeyStorage.h index 655cd17..786e5b4 100644 --- a/KeyStorage.h +++ b/KeyStorage.h @@ -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. diff --git a/KeyUtil.cpp b/KeyUtil.cpp index dbc73c1..9885440 100644 --- a/KeyUtil.cpp +++ b/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)) { diff --git a/KeyUtil.h b/KeyUtil.h index 412b0ae..a85eca1 100644 --- a/KeyUtil.h +++ b/KeyUtil.h @@ -18,6 +18,7 @@ #define ANDROID_VOLD_KEYUTIL_H #include "KeyBuffer.h" +#include "KeyStorage.h" #include #include @@ -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); From 2d64b91823ee820204330d7f9daa4d79c41c436c Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Fri, 27 Oct 2017 13:37:24 -0700 Subject: [PATCH 046/106] Improve VDC's logging on failure. Also refactor. Bug: 36029169 Test: ensure that a command fails, check logs for failure. Change-Id: I1dece2982f762f4522e17d45b5f04af104b95861 --- vdc.cpp | 52 +++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/vdc.cpp b/vdc.cpp index 4e0c3a9..761d035 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -54,13 +55,13 @@ static android::sp getServiceAggressive() { return res; } -int main(int argc, char **argv) { - int sock; - int wait; - 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 @@ -68,21 +69,17 @@ int main(int argc, char **argv) { } else { android::base::InitLogging(argv, &android::base::StderrLogger); } + std::vector args(argv + 1, argv + argc); - wait = argc > 1 && strcmp(argv[1], "--wait") == 0; - if (wait) { - argv++; - argc--; + if (args.size() > 0 && args[0] == "--wait") { + // Just ignore the --wait flag + args.erase(args.begin()); } - if (argc < 3) { - usage(progname); + if (args.size() < 2) { + usage(argv[0]); exit(5); } - - std::string arg1 = argv[1]; - std::string arg2 = argv[2]; - android::sp binder = getServiceAggressive(); if (!binder) { LOG(ERROR) << "Failed to obtain vold Binder"; @@ -90,25 +87,26 @@ int main(int argc, char **argv) { } auto vold = android::interface_cast(binder); - if (arg1 == "cryptfs" && arg2 == "enablefilecrypto") { - exit(vold->fbeEnable().isOk() ? 0 : ENOTTY); - } else if (arg1 == "cryptfs" && arg2 == "init_user0") { - exit(vold->initUser0().isOk() ? 0 : ENOTTY); - } else if (arg1 == "cryptfs" && arg2 == "enablecrypto") { + 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_IN_PLACE | android::os::IVold::ENCRYPTION_FLAG_NO_UI; - exit(vold->fdeEnable(passwordType, "", encryptionFlags).isOk() ? 0 : ENOTTY); - } else if (arg1 == "cryptfs" && arg2 == "mountdefaultencrypted") { - exit(vold->mountDefaultEncrypted().isOk() ? 0 : ENOTTY); - } else if (arg1 == "volume" && arg2 == "shutdown") { - exit(vold->shutdown().isOk() ? 0 : ENOTTY); + 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 { LOG(ERROR) << "Raw commands are no longer supported"; exit(EINVAL); } + return 0; } static void usage(char *progname) { - LOG(INFO) << "Usage: " << progname << " [--wait] | [arg1] [arg2...]"; + LOG(INFO) << "Usage: " << progname << " [--wait] [args...]"; } From 2048a2865cfa1f8c794b94eb044854f130943f9c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 15 Jun 2017 09:59:43 -0600 Subject: [PATCH 047/106] Test that plaintext can't be read from disk for encrypted files. Bug: 36029169 Test: tested by hand on Taimen Change-Id: I5717a8630bb2c8d8fe5c343d519c4e59862ecbdf --- Android.bp | 2 + CheckEncryption.cpp | 149 +++++++++++++++++++++++++++++++++++ CheckEncryption.h | 31 ++++++++ VoldNativeService.cpp | 45 +++++++---- VoldNativeService.h | 1 + binder/android/os/IVold.aidl | 1 + vdc.cpp | 2 + 7 files changed, 217 insertions(+), 14 deletions(-) create mode 100644 CheckEncryption.cpp create mode 100644 CheckEncryption.h diff --git a/Android.bp b/Android.bp index 8827d25..4432153 100644 --- a/Android.bp +++ b/Android.bp @@ -91,9 +91,11 @@ cc_library_static { srcs: [ "Benchmark.cpp", + "CheckEncryption.cpp", "Devmapper.cpp", "EncryptInplace.cpp", "Ext4Crypt.cpp", + "FileDeviceUtils.cpp", "IdleMaint.cpp", "KeyBuffer.cpp", "KeyStorage.cpp", diff --git a/CheckEncryption.cpp b/CheckEncryption.cpp new file mode 100644 index 0000000..ffa3698 --- /dev/null +++ b/CheckEncryption.cpp @@ -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 +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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(std::min(static_cast(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 diff --git a/CheckEncryption.h b/CheckEncryption.h new file mode 100644 index 0000000..158d886 --- /dev/null +++ b/CheckEncryption.h @@ -0,0 +1,31 @@ +/* + * 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_CHECK_ENCRYPTION_H +#define ANDROID_VOLD_CHECK_ENCRYPTION_H + +#include + +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 diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 0053478..d7a6576 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -17,11 +17,12 @@ #define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER #include "VoldNativeService.h" -#include "VolumeManager.h" #include "Benchmark.h" +#include "CheckEncryption.h" +#include "IdleMaint.h" #include "MoveStorage.h" #include "Process.h" -#include "IdleMaint.h" +#include "VolumeManager.h" #include "cryptfs.h" #include "Ext4Crypt.h" @@ -357,15 +358,9 @@ binder::Status VoldNativeService::format(const std::string& volId, const std::st return translate(vol->format(fsType)); } -binder::Status VoldNativeService::benchmark(const std::string& volId, - const android::sp& listener) { - ENFORCE_UID(AID_SYSTEM); - CHECK_ARGUMENT_ID(volId); - ACQUIRE_LOCK; - - std::string path; +static binder::Status pathForVolId(const std::string& volId, std::string* path) { if (volId == "private" || volId == "null") { - path = "/data"; + *path = "/data"; } else { auto vol = VolumeManager::Instance()->findVolume(volId); if (vol == nullptr) { @@ -377,12 +372,23 @@ binder::Status VoldNativeService::benchmark(const std::string& volId, if (vol->getState() != VolumeBase::State::kMounted) { return error("Volume " + volId + " not mounted"); } - path = vol->getPath(); + *path = vol->getPath(); + if (path->empty()) { + return error("Volume " + volId + " missing path"); + } } + return ok(); +} - if (path.empty()) { - return error("Volume " + volId + " missing path"); - } +binder::Status VoldNativeService::benchmark( + const std::string& volId, const android::sp& 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); @@ -390,6 +396,17 @@ binder::Status VoldNativeService::benchmark(const std::string& volId, 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& listener) { ENFORCE_UID(AID_SYSTEM); diff --git a/VoldNativeService.h b/VoldNativeService.h index 8368bdc..7ca72e5 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -51,6 +51,7 @@ public: binder::Status format(const std::string& volId, const std::string& fsType); binder::Status benchmark(const std::string& volId, const android::sp& listener); + binder::Status checkEncryption(const std::string& volId); binder::Status moveStorage(const std::string& fromVolId, const std::string& toVolId, const android::sp& listener); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 32d9b16..5d182c9 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -40,6 +40,7 @@ interface IVold { 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); diff --git a/vdc.cpp b/vdc.cpp index 761d035..19eb379 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -100,6 +100,8 @@ int main(int argc, char** argv) { 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 { LOG(ERROR) << "Raw commands are no longer supported"; exit(EINVAL); From b64933a5021ee9666388b781b542f11ef7665673 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Tue, 31 Oct 2017 08:25:55 -0700 Subject: [PATCH 048/106] Be even more C++. Switch on a warning. Remove lots of "extern C" and "ifdef __cplusplus" which are no longer needed now all of vold is C++. Also turn on the cert-err58-cpp warning we once had to disable. Bug: 67041047 Test: compiles, boots Change-Id: I8c6f9dd486f2409e0deed7bb648d959677465b21 --- Android.bp | 1 - VolumeManager.cpp | 5 ----- VolumeManager.h | 10 --------- cryptfs.cpp | 5 +++++ cryptfs.h | 53 ++++++++++++++++++++++------------------------- 5 files changed, 30 insertions(+), 44 deletions(-) diff --git a/Android.bp b/Android.bp index 4432153..5941cd9 100644 --- a/Android.bp +++ b/Android.bp @@ -17,7 +17,6 @@ cc_defaults { "-*", "cert-*", "clang-analyzer-security*", - "-cert-err58-cpp", ], tidy_flags: [ "-warnings-as-errors=clang-analyzer-security*,cert-*", diff --git a/VolumeManager.cpp b/VolumeManager.cpp index f54fb00..e078c0d 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -599,11 +599,6 @@ int VolumeManager::unmountAll() { return 0; } -extern "C" int vold_unmountAll(void) { - VolumeManager *vm = VolumeManager::Instance(); - return vm->unmountAll(); -} - int VolumeManager::mkdirs(const std::string& path) { // Only offer to create directories for paths managed by vold if (android::base::StartsWith(path, "/storage/")) { diff --git a/VolumeManager.h b/VolumeManager.h index 8a780c4..5baa7ce 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -21,8 +21,6 @@ #include #include -#ifdef __cplusplus - #include #include #include @@ -154,12 +152,4 @@ private: int mNextObbId; }; -extern "C" { -#endif /* __cplusplus */ -#define UNMOUNT_NOT_MOUNTED_ERR (-2) - int vold_unmountAll(void); -#ifdef __cplusplus -} -#endif - #endif diff --git a/cryptfs.cpp b/cryptfs.cpp index ae9b0af..7302c44 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -2051,6 +2051,11 @@ static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how, return rc; } +static int vold_unmountAll(void) { + VolumeManager* vm = VolumeManager::Instance(); + return vm->unmountAll(); +} + int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *passwd, int no_ui) { diff --git a/cryptfs.h b/cryptfs.h index 5642e29..767270f 100644 --- a/cryptfs.h +++ b/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..rc. @@ -218,34 +221,28 @@ 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 match_multi_entry(const char *key, const char *field, unsigned index); - 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(const char* flag, int type, const char* passwd, int no_ui); +int cryptfs_changepw(int type, const char* newpw); +int cryptfs_enable_default(const char* flag, int no_ui); +int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const unsigned char* key, + int keysize, char* out_crypto_blkdev); +int cryptfs_revert_ext_volume(const char* label); +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(const char *pw); - int cryptfs_restart(void); - int cryptfs_enable(const char *flag, int type, const char *passwd, int no_ui); - int cryptfs_changepw(int type, const char *newpw); - int cryptfs_enable_default(const char *flag, int no_ui); - int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, - const unsigned char* key, int keysize, char* out_crypto_blkdev); - int cryptfs_revert_ext_volume(const char* label); - 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); - -#ifdef __cplusplus -} -#endif +#endif /* ANDROID_VOLD_CRYPTFS_H */ From cbcb2926b29e61c9a20dcb6593897a8f78a07ba4 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 6 Nov 2017 13:53:59 -0700 Subject: [PATCH 049/106] Abort long-running benchmarks, report progress. A typical storage device finishes the benchmark in under 10 seconds, but some extremely slow devices can take minutes, resulting in a confusing UX that looks like we've frozen. Even worse, we keep churning through all that I/O even though we know the device will blow past our user-warning threshold. So periodically check if we've timed out, and also use that to report progress up into the Settings UI. Test: manual Bug: 62201209, 65639764, 67055204 Change-Id: I321397bcff230976f034cede0947d4a5a1f3e8a7 --- Benchmark.cpp | 173 ++++++++++++-------- BenchmarkGen.h | 398 +++++++++++++++++++++++++--------------------- bench/benchgen.py | 20 ++- 3 files changed, 338 insertions(+), 253 deletions(-) diff --git a/Benchmark.cpp b/Benchmark.cpp index 63b4dd3..dfe3366 100644 --- a/Benchmark.cpp +++ b/Benchmark.cpp @@ -18,8 +18,10 @@ #include "BenchmarkGen.h" #include "VolumeManager.h" +#include #include #include + #include #include #include @@ -30,18 +32,65 @@ #include #include -#define ENABLE_DROP_CACHES 1 - using android::base::ReadFileToString; using android::base::WriteStringToFile; namespace android { namespace vold { +// Benchmark currently uses chdir(), which means we can only +// safely run one at a time. +static std::mutex kBenchmarkLock; + 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"; + } + } + + ~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& listener, android::os::PersistableBundle* extras) { + status_t res = 0; + auto path = rootPath; path += "/misc"; if (android::vold::PrepareDir(path, 01771, AID_SYSTEM, AID_MISC)) { @@ -56,28 +105,6 @@ static status_t benchmarkInternal(const std::string& rootPath, return -1; } - 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; - } - - IoSchedClass orig_clazz = IoSchedClass_NONE; - int orig_ioprio = 0; - if (android_get_ioprio(0, &orig_clazz, &orig_ioprio)) { - PLOG(ERROR) << "Failed to android_get_ioprio"; - return -1; - } - if (android_set_ioprio(0, IoSchedClass_RT, 0)) { - PLOG(ERROR) << "Failed to android_set_ioprio"; - return -1; - } - char orig_cwd[PATH_MAX]; if (getcwd(orig_cwd, PATH_MAX) == NULL) { PLOG(ERROR) << "Failed getcwd"; @@ -90,66 +117,76 @@ static status_t benchmarkInternal(const std::string& rootPath, 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"; - - extras->putString(String16("path"), String16(path.c_str())); - extras->putString(String16("ident"), String16(BenchmarkIdent().c_str())); - extras->putLong(String16("create"), create_d); - extras->putLong(String16("drop"), drop_d); - extras->putLong(String16("run"), run_d); - extras->putLong(String16("destroy"), destroy_d); - - return 0; + return res; } void Benchmark(const std::string& path, const android::sp& listener) { + std::lock_guard lock(kBenchmarkLock); acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); + PerformanceBoost boost; android::os::PersistableBundle extras; - status_t res = benchmarkInternal(path, &extras); + + status_t res = benchmarkInternal(path, listener, &extras); if (listener) { listener->onFinished(res, extras); } diff --git a/BenchmarkGen.h b/BenchmarkGen.h index cd95aae..a1bf718 100644 --- a/BenchmarkGen.h +++ b/BenchmarkGen.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -36,10 +37,11 @@ namespace android { namespace vold { -static status_t BenchmarkRun() { +static status_t BenchmarkRun(std::function checkpoint) { + char* buf = (char*) malloc(1048576); -int t3433f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE)); +int t3433f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(lseek(t3433f17, 0, SEEK_END)); TEMP_FAILURE_RETRY(lseek(t3433f17, 38891199, SEEK_SET)); TEMP_FAILURE_RETRY(read(t3433f17, buf, 65557)); @@ -50,7 +52,7 @@ TEMP_FAILURE_RETRY(pread(t3433f17, buf, 25119, 278528)); // mmap2 TEMP_FAILURE_RETRY(pread(t3433f17, buf, 30, 37276895)); TEMP_FAILURE_RETRY(pread(t3433f17, buf, 14, 37276925)); TEMP_FAILURE_RETRY(pread(t3433f17, buf, 914520, 37273600)); // mmap2 -int t3433f18 = TEMP_FAILURE_RETRY(open("file1", O_RDONLY|O_LARGEFILE)); +int t3433f18 = TEMP_FAILURE_RETRY(open("file1", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(pread(t3433f18, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3433f18, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3433f18, buf, 4096, 0)); // mmap2 @@ -211,8 +213,8 @@ TEMP_FAILURE_RETRY(pread(t3433f17, buf, 3143, 34410496)); // mmap2 TEMP_FAILURE_RETRY(pread(t3433f17, buf, 30, 32521955)); TEMP_FAILURE_RETRY(pread(t3433f17, buf, 45, 32521985)); TEMP_FAILURE_RETRY(pread(t3433f17, buf, 6350, 32518144)); // mmap2 -int t3450f18 = TEMP_FAILURE_RETRY(open("file11", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); -int t3450f22 = TEMP_FAILURE_RETRY(open("file12", O_RDONLY|O_LARGEFILE)); +int t3450f18 = TEMP_FAILURE_RETRY(open("file11", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); +int t3450f22 = TEMP_FAILURE_RETRY(open("file12", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3450f22, buf, 1)); close(t3450f22); t3450f22 = TEMP_FAILURE_RETRY(open("file13", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); @@ -224,7 +226,7 @@ TEMP_FAILURE_RETRY(write(t3450f22, buf, 1)); TEMP_FAILURE_RETRY(fsync(t3450f22)); close(t3450f22); close(t3450f18); -int t3454f26 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3454f26 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(lseek(t3454f26, 0, SEEK_END)); TEMP_FAILURE_RETRY(lseek(t3454f26, 38891199, SEEK_SET)); TEMP_FAILURE_RETRY(read(t3454f26, buf, 65557)); @@ -236,7 +238,7 @@ TEMP_FAILURE_RETRY(lseek(t3454f26, 38891199, SEEK_SET)); TEMP_FAILURE_RETRY(read(t3454f26, buf, 65557)); TEMP_FAILURE_RETRY(pread(t3454f26, buf, 769726, 38187008)); // mmap2 close(t3454f26); -int t3455f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE)); +int t3455f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(lseek(t3455f17, 0, SEEK_END)); TEMP_FAILURE_RETRY(lseek(t3455f17, 38891199, SEEK_SET)); TEMP_FAILURE_RETRY(read(t3455f17, buf, 65557)); @@ -247,10 +249,10 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 25119, 278528)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 37276895)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 14, 37276925)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 914520, 37273600)); // mmap2 -int t3454f29 = TEMP_FAILURE_RETRY(open("file16", O_RDONLY|O_LARGEFILE)); +int t3454f29 = TEMP_FAILURE_RETRY(open("file16", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(pread(t3454f29, buf, 14048, 0)); // mmap2 close(t3454f29); -int t3455f18 = TEMP_FAILURE_RETRY(open("file1", O_RDONLY|O_LARGEFILE)); +int t3455f18 = TEMP_FAILURE_RETRY(open("file1", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 0)); // mmap2 @@ -277,6 +279,7 @@ TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 57012224)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f18, buf, 1048576, 0)); // mmap2 close(t3455f18); t3455f18 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE)); +if (!checkpoint(52)) return -1; TEMP_FAILURE_RETRY(read(t3455f18, buf, 4)); TEMP_FAILURE_RETRY(lseek(t3455f18, 0, SEEK_SET)); TEMP_FAILURE_RETRY(lseek(t3455f18, 0, SEEK_END)); @@ -397,7 +400,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3262, 3510272)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 3513185)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 46, 3513215)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3262, 3510272)); // mmap2 -int t3455f19 = TEMP_FAILURE_RETRY(open("file12", O_RDONLY|O_LARGEFILE)); +int t3455f19 = TEMP_FAILURE_RETRY(open("file12", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3455f19, buf, 1)); close(t3455f19); t3455f19 = TEMP_FAILURE_RETRY(open("file13", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); @@ -415,9 +418,9 @@ TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f18, buf, 13748, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4196, 12288)); // mmap2 close(t3455f18); -int t3483f20 = TEMP_FAILURE_RETRY(open("file17", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3483f20 = TEMP_FAILURE_RETRY(open("file17", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 100, 0)); -int t3483f21 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3483f21 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3483f21, buf, 1, 0)); close(t3483f21); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 0)); @@ -440,7 +443,7 @@ close(t3483f21); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 16, 24)); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 16384)); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 12288)); -int t3483f22 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3483f22 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3483f22, buf, 1, 0)); close(t3483f22); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 16, 24)); @@ -467,9 +470,9 @@ TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 110592)); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 49152)); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 139264)); TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 172032)); -int t3483f25 = TEMP_FAILURE_RETRY(open("file19", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3483f25 = TEMP_FAILURE_RETRY(open("file19", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 100, 0)); -int t3483f26 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3483f26 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3483f26, buf, 1, 0)); close(t3483f26); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 0)); @@ -492,7 +495,7 @@ close(t3483f26); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 16, 24)); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 16384)); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 12288)); -int t3483f27 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3483f27 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3483f27, buf, 1, 0)); close(t3483f27); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 16, 24)); @@ -533,6 +536,7 @@ TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 184320)); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 69632)); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 81920)); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 90112)); +if (!checkpoint(55)) return -1; TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 102400)); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 114688)); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 131072)); @@ -541,16 +545,16 @@ t3483f27 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3483f27, buf, 1, 0)); close(t3483f27); TEMP_FAILURE_RETRY(pread(t3483f25, buf, 16, 24)); -int t3498f30 = TEMP_FAILURE_RETRY(open("file21", O_RDONLY|O_LARGEFILE)); +int t3498f30 = TEMP_FAILURE_RETRY(open("file21", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3498f30, buf, 16384)); close(t3498f30); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 278721)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 19, 278751)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 25119, 278528)); // mmap2 -int t3499f30 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f30 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f30, buf, 1, 0)); close(t3499f30); -int t3499f31 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); +int t3499f31 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 512, 0)); TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 4, 512)); TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 4096, 516)); @@ -595,7 +599,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f30)); TEMP_FAILURE_RETRY(pwrite(t3499f30, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f30)); close(t3499f30); -int t3500f30 = TEMP_FAILURE_RETRY(open("file23", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3500f30 = TEMP_FAILURE_RETRY(open("file23", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3500f30, buf, 52, 0)); TEMP_FAILURE_RETRY(pread(t3500f30, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3500f30, buf, 27898, 0)); // mmap2 @@ -631,7 +635,7 @@ TEMP_FAILURE_RETRY(pread(t3500f30, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3500f30, buf, 1048576, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3500f30, buf, 122564, 3059712)); // mmap2 close(t3500f30); -int t3502f30 = TEMP_FAILURE_RETRY(open("file29", O_RDONLY|O_LARGEFILE)); +int t3502f30 = TEMP_FAILURE_RETRY(open("file29", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3502f30, buf, 1)); TEMP_FAILURE_RETRY(read(t3502f30, buf, 4)); TEMP_FAILURE_RETRY(read(t3502f30, buf, 1)); @@ -776,6 +780,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 31, 32760741)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2073, 32759808)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32273035)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 37, 32273065)); +if (!checkpoint(58)) return -1; TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1692, 32272384)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34612102)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 38, 34612132)); @@ -802,7 +807,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f31, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f31)); -int t3499f32 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f32 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f32)); close(t3499f32); TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 12, 0)); @@ -837,9 +842,9 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f31)); TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f31)); close(t3499f31); -int t3492f31 = TEMP_FAILURE_RETRY(open("file30", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3492f31 = TEMP_FAILURE_RETRY(open("file30", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 100, 0)); -int t3492f32 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3492f32 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f32, buf, 1, 0)); close(t3492f32); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 4096, 0)); @@ -865,7 +870,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 49, 35635415)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1005, 35635200)); // mmap2 TEMP_FAILURE_RETRY(pread(t3492f31, buf, 4096, 16384)); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 4096, 12288)); -int t3492f33 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3492f33 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f33, buf, 1, 0)); close(t3492f33); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24)); @@ -899,7 +904,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f30, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3499f30, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f30, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f30)); -int t3499f34 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f34 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f34)); close(t3499f34); TEMP_FAILURE_RETRY(pwrite(t3499f30, buf, 12, 0)); @@ -1001,6 +1006,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35474138)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 43, 35474168)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3682, 35471360)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34394223)); +if (!checkpoint(61)) return -1; TEMP_FAILURE_RETRY(pread(t3455f17, buf, 41, 34394253)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 481, 34394112)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32648704)); @@ -1034,19 +1040,19 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3608, 36093952)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 36096678)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 29, 36096708)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3292, 36093952)); // mmap2 -int t3509f41 = TEMP_FAILURE_RETRY(open("file33", O_RDONLY|O_LARGEFILE)); -int t3492f42 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3509f41 = TEMP_FAILURE_RETRY(open("file33", O_RDONLY|O_LARGEFILE)); +int t3492f42 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f42, buf, 1, 0)); close(t3492f42); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24)); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 4096, 53248)); -int t3499f42 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f42 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f42, buf, 1, 0)); close(t3499f42); TEMP_FAILURE_RETRY(read(t3509f41, buf, 8192)); TEMP_FAILURE_RETRY(read(t3509f41, buf, 8091)); close(t3509f41); -int t3499f41 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f41 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f41, buf, 1, 0)); close(t3499f41); t3499f41 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -1103,10 +1109,10 @@ close(t3499f41); t3499f41 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f41, buf, 1, 0)); close(t3499f41); -int t3499f40 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f40 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f40, buf, 1, 0)); close(t3499f40); -int t3492f40 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3492f40 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f40, buf, 1, 0)); close(t3492f40); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24)); @@ -1192,7 +1198,7 @@ close(t3499f40); t3499f40 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f40, buf, 1, 0)); close(t3499f40); -int t3492f41 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3492f41 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f41, buf, 1, 0)); close(t3492f41); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24)); @@ -1223,6 +1229,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 12820)); TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 12824)); TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4096, 12828)); +if (!checkpoint(64)) return -1; TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f40, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f40)); @@ -1253,7 +1260,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f40, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f40)); -int t3508f42 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3508f42 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(lseek(t3508f42, 0, SEEK_END)); TEMP_FAILURE_RETRY(lseek(t3508f42, 38891199, SEEK_SET)); TEMP_FAILURE_RETRY(read(t3508f42, buf, 65557)); @@ -1265,7 +1272,7 @@ TEMP_FAILURE_RETRY(lseek(t3508f42, 38891199, SEEK_SET)); TEMP_FAILURE_RETRY(read(t3508f42, buf, 65557)); TEMP_FAILURE_RETRY(pread(t3508f42, buf, 769726, 38187008)); // mmap2 close(t3508f42); -int t3499f43 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f43 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f43)); close(t3499f43); TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 12, 0)); @@ -1273,10 +1280,10 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f40)); TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f40)); close(t3499f40); -int t3508f40 = TEMP_FAILURE_RETRY(open("file16", O_RDONLY|O_LARGEFILE)); +int t3508f40 = TEMP_FAILURE_RETRY(open("file16", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(pread(t3508f40, buf, 14048, 0)); // mmap2 close(t3508f40); -int t3499f33 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f33 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f33, buf, 1, 0)); close(t3499f33); t3499f33 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -1295,7 +1302,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f33, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3499f33, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f33, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f33)); -int t3499f39 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f39 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f39)); close(t3499f39); TEMP_FAILURE_RETRY(pwrite(t3499f33, buf, 12, 0)); @@ -1336,7 +1343,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 4281, 35631104)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35448800)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 31, 35448830)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2408, 35446784)); // mmap2 -int t3519f33 = TEMP_FAILURE_RETRY(open("file34", O_RDONLY|O_LARGEFILE)); +int t3519f33 = TEMP_FAILURE_RETRY(open("file34", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3519f33, buf, 1422)); TEMP_FAILURE_RETRY(read(t3519f33, buf, 1)); close(t3519f33); @@ -1436,11 +1443,11 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2365, 35274752)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 29897692)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 34, 29897722)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1809, 29896704)); // mmap2 -int t3523f49 = TEMP_FAILURE_RETRY(open("file33", O_RDONLY|O_LARGEFILE)); +int t3523f49 = TEMP_FAILURE_RETRY(open("file33", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3523f49, buf, 8192)); TEMP_FAILURE_RETRY(read(t3523f49, buf, 8091)); close(t3523f49); -int t3455f50 = TEMP_FAILURE_RETRY(open("file7", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3455f50 = TEMP_FAILURE_RETRY(open("file7", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); close(t3455f50); t3455f50 = TEMP_FAILURE_RETRY(open("file35", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3455f50, buf, 52, 0)); @@ -1452,6 +1459,7 @@ t3455f50 = TEMP_FAILURE_RETRY(open("file36", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3455f50, buf, 52, 0)); TEMP_FAILURE_RETRY(pread(t3455f50, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f50, buf, 187587, 0)); // mmap2 +if (!checkpoint(67)) return -1; TEMP_FAILURE_RETRY(pread(t3455f50, buf, 4128, 188416)); // mmap2 close(t3455f50); t3455f50 = TEMP_FAILURE_RETRY(open("file24", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); @@ -1471,7 +1479,7 @@ close(t3455f50); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 29922405)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 45, 29922435)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1962, 29921280)); // mmap2 -int t3499f50 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f50 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f50, buf, 1, 0)); close(t3499f50); t3499f50 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -1490,7 +1498,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f50, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3499f50, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f50, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f50)); -int t3499f52 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f52 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f52)); close(t3499f52); TEMP_FAILURE_RETRY(pwrite(t3499f50, buf, 12, 0)); @@ -1534,7 +1542,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3729, 31436800)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 33255456)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 43, 33255486)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 795, 33255424)); // mmap2 -int t3492f52 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3492f52 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f52, buf, 1, 0)); close(t3492f52); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24)); @@ -1594,8 +1602,8 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3721, 34443264)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35513539)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 37, 35513569)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1673, 35512320)); // mmap2 -int t3526f50 = TEMP_FAILURE_RETRY(open("file39", O_RDONLY|O_LARGEFILE)); -int t3526f52 = TEMP_FAILURE_RETRY(open("file40", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3526f50 = TEMP_FAILURE_RETRY(open("file39", O_RDONLY|O_LARGEFILE)); +int t3526f52 = TEMP_FAILURE_RETRY(open("file40", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3526f52, buf, 52, 0)); TEMP_FAILURE_RETRY(pread(t3526f52, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3526f52, buf, 1584, 0)); // mmap2 @@ -1619,7 +1627,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3113, 34430976)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32575657)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 49, 32575687)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 451, 32575488)); // mmap2 -int t3519f50 = TEMP_FAILURE_RETRY(open("file41", O_RDONLY|O_LARGEFILE)); +int t3519f50 = TEMP_FAILURE_RETRY(open("file41", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384)); TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384)); close(t3519f50); @@ -1632,7 +1640,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2245, 31522816)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 29920348)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 42, 29920378)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 5221, 29917184)); // mmap2 -int t3527f50 = TEMP_FAILURE_RETRY(open("file42", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3527f50 = TEMP_FAILURE_RETRY(open("file42", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3527f50, buf, 52, 0)); TEMP_FAILURE_RETRY(pread(t3527f50, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32567874)); @@ -1652,7 +1660,7 @@ TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384)); TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384)); TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384)); close(t3519f50); -int t3492f50 = TEMP_FAILURE_RETRY(open("file44", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3492f50 = TEMP_FAILURE_RETRY(open("file44", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f50, buf, 52, 0)); TEMP_FAILURE_RETRY(pread(t3492f50, buf, 4096, 0)); // mmap2 TEMP_FAILURE_RETRY(pread(t3492f50, buf, 10313, 0)); // mmap2 @@ -1666,23 +1674,23 @@ close(t3519f50); TEMP_FAILURE_RETRY(read(t3526f52, buf, 16384)); TEMP_FAILURE_RETRY(read(t3526f52, buf, 16384)); close(t3526f52); -int t3532f53 = TEMP_FAILURE_RETRY(open("file47", O_RDONLY|O_LARGEFILE)); +int t3532f53 = TEMP_FAILURE_RETRY(open("file47", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3532f53, buf, 16384)); -int t3533f47 = TEMP_FAILURE_RETRY(open("file48", O_RDONLY|O_LARGEFILE)); +int t3533f47 = TEMP_FAILURE_RETRY(open("file48", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3532f53, buf, 16384)); close(t3532f53); TEMP_FAILURE_RETRY(read(t3533f47, buf, 16384)); TEMP_FAILURE_RETRY(read(t3533f47, buf, 16384)); close(t3533f47); -int t3519f43 = TEMP_FAILURE_RETRY(open("file49", O_RDONLY|O_LARGEFILE)); +int t3519f43 = TEMP_FAILURE_RETRY(open("file49", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3519f43, buf, 16384)); TEMP_FAILURE_RETRY(read(t3519f43, buf, 16384)); close(t3519f43); -int t3532f43 = TEMP_FAILURE_RETRY(open("file50", O_RDONLY|O_LARGEFILE)); +int t3532f43 = TEMP_FAILURE_RETRY(open("file50", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3532f43, buf, 16384)); TEMP_FAILURE_RETRY(read(t3532f43, buf, 16384)); close(t3532f43); -int t3533f43 = TEMP_FAILURE_RETRY(open("file51", O_RDONLY|O_LARGEFILE)); +int t3533f43 = TEMP_FAILURE_RETRY(open("file51", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3533f43, buf, 16384)); TEMP_FAILURE_RETRY(read(t3533f43, buf, 16384)); close(t3533f43); @@ -1695,10 +1703,11 @@ TEMP_FAILURE_RETRY(read(t3532f53, buf, 16384)); TEMP_FAILURE_RETRY(read(t3532f53, buf, 16384)); close(t3519f43); close(t3532f53); -int t3492f57 = TEMP_FAILURE_RETRY(open("file54", O_RDONLY|O_LARGEFILE)); +int t3492f57 = TEMP_FAILURE_RETRY(open("file54", O_RDONLY|O_LARGEFILE)); +if (!checkpoint(70)) return -1; TEMP_FAILURE_RETRY(read(t3492f57, buf, 39938)); close(t3492f57); -int t3492f61 = TEMP_FAILURE_RETRY(open("file55", O_RDONLY|O_LARGEFILE)); +int t3492f61 = TEMP_FAILURE_RETRY(open("file55", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3492f61, buf, 8192)); TEMP_FAILURE_RETRY(read(t3492f61, buf, 8192)); close(t3492f61); @@ -1793,7 +1802,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1673, 35512320)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 28977951)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 48, 28977981)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3292, 28975104)); // mmap2 -int t3499f55 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f55 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f55, buf, 1, 0)); close(t3499f55); t3499f55 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -1812,7 +1821,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f55, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f55)); -int t3499f56 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f56 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f56)); close(t3499f56); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 12, 0)); @@ -1820,14 +1829,14 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f55)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f55)); close(t3499f55); -int t3505f55 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3505f55 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3505f55, buf, 1, 0)); close(t3505f55); -int t3519f55 = TEMP_FAILURE_RETRY(open("file57", O_RDONLY|O_LARGEFILE)); +int t3519f55 = TEMP_FAILURE_RETRY(open("file57", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3519f55, buf, 16384)); TEMP_FAILURE_RETRY(read(t3519f55, buf, 16384)); close(t3519f55); -int t3532f55 = TEMP_FAILURE_RETRY(open("file58", O_RDONLY|O_LARGEFILE)); +int t3532f55 = TEMP_FAILURE_RETRY(open("file58", O_RDONLY|O_LARGEFILE)); t3499f56 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f56, buf, 1, 0)); close(t3499f56); @@ -1835,7 +1844,7 @@ TEMP_FAILURE_RETRY(read(t3532f55, buf, 16384)); TEMP_FAILURE_RETRY(read(t3532f55, buf, 16384)); close(t3532f55); t3499f55 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); -int t3505f56 = TEMP_FAILURE_RETRY(open("file59", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); +int t3505f56 = TEMP_FAILURE_RETRY(open("file59", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 512, 0)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 512)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 516)); @@ -1848,7 +1857,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f55, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f55)); -int t3499f59 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f59 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f59)); close(t3499f59); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 12, 0)); @@ -1856,11 +1865,11 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f55)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f55)); close(t3499f55); -int t3533f55 = TEMP_FAILURE_RETRY(open("file60", O_RDONLY|O_LARGEFILE)); +int t3533f55 = TEMP_FAILURE_RETRY(open("file60", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3533f55, buf, 16384)); TEMP_FAILURE_RETRY(read(t3533f55, buf, 16384)); close(t3533f55); -int t3499f58 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f58 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f58, buf, 1, 0)); close(t3499f58); t3499f58 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -1928,6 +1937,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 512, 0)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 512)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 516)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 4612)); +if (!checkpoint(73)) return -1; TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 4616)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 4620)); TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 8716)); @@ -2026,7 +2036,7 @@ TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4, 12820)); TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4, 12824)); TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4, 16924)); -int t3499f62 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f62 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f62, buf, 1, 0)); close(t3499f62); TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4, 16928)); @@ -2048,7 +2058,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f62, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f62)); -int t3499f68 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f68 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f68)); close(t3499f68); TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 12, 0)); @@ -2058,7 +2068,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3505f56)); TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f62)); close(t3499f62); -int t3505f62 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3505f62 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3505f62)); close(t3505f62); TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 12, 0)); @@ -2069,11 +2079,11 @@ close(t3505f56); t3505f56 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3505f56, buf, 1, 0)); close(t3505f56); -int t3533f56 = TEMP_FAILURE_RETRY(open("file61", O_RDONLY|O_LARGEFILE)); +int t3533f56 = TEMP_FAILURE_RETRY(open("file61", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3533f56, buf, 16384)); TEMP_FAILURE_RETRY(read(t3533f56, buf, 16384)); close(t3533f56); -int t3532f56 = TEMP_FAILURE_RETRY(open("file62", O_RDONLY|O_LARGEFILE)); +int t3532f56 = TEMP_FAILURE_RETRY(open("file62", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3532f56, buf, 16384)); TEMP_FAILURE_RETRY(read(t3532f56, buf, 16384)); close(t3532f56); @@ -2130,7 +2140,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 4322, 28352512)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 29935078)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 50, 29935108)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1983, 29933568)); // mmap2 -int t3499f66 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f66 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f66, buf, 1, 0)); close(t3499f66); t3499f66 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -2142,7 +2152,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4, 4616)); TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4096, 4620)); TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4, 8716)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 36467015)); -int t3532f68 = TEMP_FAILURE_RETRY(open("file64", O_RDONLY|O_LARGEFILE)); +int t3532f68 = TEMP_FAILURE_RETRY(open("file64", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 41, 36467045)); TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4, 8720)); TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4096, 8724)); @@ -2152,13 +2162,14 @@ TEMP_FAILURE_RETRY(pread(t3499f66, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f66)); TEMP_FAILURE_RETRY(read(t3532f68, buf, 16384)); TEMP_FAILURE_RETRY(read(t3532f68, buf, 16384)); -int t3499f73 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f73 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(read(t3532f68, buf, 16384)); TEMP_FAILURE_RETRY(fdatasync(t3499f73)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34267550)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 49, 34267580)); close(t3499f73); TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 12, 0)); +if (!checkpoint(76)) return -1; close(t3532f68); TEMP_FAILURE_RETRY(fdatasync(t3499f66)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 722, 34267136)); // mmap2 @@ -2180,11 +2191,11 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2120, 35512320)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35513539)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 37, 35513569)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1673, 35512320)); // mmap2 -int t3532f61 = TEMP_FAILURE_RETRY(open("file65", O_RDONLY|O_LARGEFILE)); +int t3532f61 = TEMP_FAILURE_RETRY(open("file65", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3532f61, buf, 16384)); TEMP_FAILURE_RETRY(read(t3532f61, buf, 16384)); close(t3532f61); -int t3533f61 = TEMP_FAILURE_RETRY(open("file66", O_RDONLY|O_LARGEFILE)); +int t3533f61 = TEMP_FAILURE_RETRY(open("file66", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3533f61, buf, 16384)); TEMP_FAILURE_RETRY(read(t3533f61, buf, 16384)); close(t3533f61); @@ -2212,7 +2223,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f62, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f62)); -int t3499f61 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f61 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f61)); close(t3499f61); TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 12, 0)); @@ -2228,11 +2239,11 @@ t3533f61 = TEMP_FAILURE_RETRY(open("file70", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3533f61, buf, 16384)); TEMP_FAILURE_RETRY(read(t3533f61, buf, 16384)); close(t3533f61); -int t3519f61 = TEMP_FAILURE_RETRY(open("file71", O_RDONLY|O_LARGEFILE)); +int t3519f61 = TEMP_FAILURE_RETRY(open("file71", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3519f61, buf, 16384)); TEMP_FAILURE_RETRY(read(t3519f61, buf, 16384)); close(t3519f61); -int t3499f80 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f80 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f80, buf, 1, 0)); close(t3499f80); t3499f80 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -2248,7 +2259,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f80, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f80, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f80, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f80)); -int t3499f81 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f81 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f81)); close(t3499f81); TEMP_FAILURE_RETRY(pwrite(t3499f80, buf, 12, 0)); @@ -2283,7 +2294,7 @@ close(t3499f66); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34957756)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 29, 34957786)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3273, 34955264)); // mmap2 -int t3519f68 = TEMP_FAILURE_RETRY(open("file72", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3519f68 = TEMP_FAILURE_RETRY(open("file72", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f68); t3519f68 = TEMP_FAILURE_RETRY(open("file73", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f68); @@ -2305,7 +2316,7 @@ t3519f68 = TEMP_FAILURE_RETRY(open("file81", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_ close(t3519f68); t3519f68 = TEMP_FAILURE_RETRY(open("file82", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f68); -int t3519f70 = TEMP_FAILURE_RETRY(open("file83", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3519f70 = TEMP_FAILURE_RETRY(open("file83", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f70); t3519f68 = TEMP_FAILURE_RETRY(open("file84", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f68); @@ -2330,12 +2341,12 @@ close(t3519f70); t3519f70 = TEMP_FAILURE_RETRY(open("file94", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f70); t3519f70 = TEMP_FAILURE_RETRY(open("file95", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); -int t3492f72 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3492f72 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f72, buf, 1, 0)); close(t3492f72); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24)); close(t3519f70); -int t3492f70 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3492f70 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3492f70, buf, 1, 0)); close(t3492f70); TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24)); @@ -2367,15 +2378,15 @@ t3519f68 = TEMP_FAILURE_RETRY(open("file108", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O close(t3519f68); t3519f68 = TEMP_FAILURE_RETRY(open("file109", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f68); -int t3519f72 = TEMP_FAILURE_RETRY(open("file110", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3519f72 = TEMP_FAILURE_RETRY(open("file110", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f72); -int t3519f80 = TEMP_FAILURE_RETRY(open("file111", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3519f80 = TEMP_FAILURE_RETRY(open("file111", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f80); -int t3519f81 = TEMP_FAILURE_RETRY(open("file112", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3519f81 = TEMP_FAILURE_RETRY(open("file112", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f81); t3519f81 = TEMP_FAILURE_RETRY(open("file113", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f81); -int t3519f76 = TEMP_FAILURE_RETRY(open("file114", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3519f76 = TEMP_FAILURE_RETRY(open("file114", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f76); t3519f70 = TEMP_FAILURE_RETRY(open("file115", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f70); @@ -2383,7 +2394,7 @@ t3519f70 = TEMP_FAILURE_RETRY(open("file116", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O close(t3519f70); t3519f70 = TEMP_FAILURE_RETRY(open("file117", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f70); -int t3519f67 = TEMP_FAILURE_RETRY(open("file118", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3519f67 = TEMP_FAILURE_RETRY(open("file118", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f67); t3519f67 = TEMP_FAILURE_RETRY(open("file119", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f67); @@ -2396,6 +2407,7 @@ close(t3519f67); t3519f67 = TEMP_FAILURE_RETRY(open("file123", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f67); t3519f67 = TEMP_FAILURE_RETRY(open("file124", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +if (!checkpoint(79)) return -1; close(t3519f67); t3519f67 = TEMP_FAILURE_RETRY(open("file125", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3519f67); @@ -2405,8 +2417,8 @@ t3519f67 = TEMP_FAILURE_RETRY(open("file127", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O close(t3519f67); t3519f70 = TEMP_FAILURE_RETRY(open("file128", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3519f70); -int t3526f70 = TEMP_FAILURE_RETRY(open("file129", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); -int t3519f75 = TEMP_FAILURE_RETRY(open("file128", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); +int t3526f70 = TEMP_FAILURE_RETRY(open("file129", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3519f75 = TEMP_FAILURE_RETRY(open("file128", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); close(t3526f70); t3526f70 = TEMP_FAILURE_RETRY(open("file129", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3519f75, buf, 2991)); @@ -2415,7 +2427,7 @@ TEMP_FAILURE_RETRY(write(t3526f70, buf, 3974)); close(t3526f70); t3519f67 = TEMP_FAILURE_RETRY(open("file130", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3519f67, buf, 16384)); -int t3499f72 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f72 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f72, buf, 1, 0)); close(t3499f72); TEMP_FAILURE_RETRY(read(t3519f67, buf, 16384)); @@ -2433,7 +2445,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f72, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f72)); -int t3499f67 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f67 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f67)); close(t3499f67); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 12, 0)); @@ -2446,7 +2458,7 @@ close(t3526f70); t3526f70 = TEMP_FAILURE_RETRY(open("file131", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f70, buf, 4622)); close(t3526f70); -int t3526f72 = TEMP_FAILURE_RETRY(open("file132", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3526f72 = TEMP_FAILURE_RETRY(open("file132", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3526f72); t3526f72 = TEMP_FAILURE_RETRY(open("file132", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f72, buf, 16384)); @@ -2454,10 +2466,10 @@ TEMP_FAILURE_RETRY(write(t3526f72, buf, 6849)); close(t3526f72); t3526f70 = TEMP_FAILURE_RETRY(open("file133", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3526f70); -int t3526f75 = TEMP_FAILURE_RETRY(open("file133", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); +int t3526f75 = TEMP_FAILURE_RETRY(open("file133", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f75, buf, 13332)); close(t3526f75); -int t3495f70 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3495f70 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3495f70, buf, 1, 0)); close(t3495f70); t3495f70 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -2473,7 +2485,7 @@ TEMP_FAILURE_RETRY(pwrite(t3495f70, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3495f70, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3495f70, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3495f70)); -int t3495f75 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3495f75 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3495f75)); close(t3495f75); TEMP_FAILURE_RETRY(pwrite(t3495f70, buf, 12, 0)); @@ -2481,9 +2493,9 @@ TEMP_FAILURE_RETRY(fdatasync(t3495f70)); TEMP_FAILURE_RETRY(pwrite(t3495f70, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3495f70)); close(t3495f70); -int t3526f93 = TEMP_FAILURE_RETRY(open("file134", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3526f93 = TEMP_FAILURE_RETRY(open("file134", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3526f93); -int t3526f88 = TEMP_FAILURE_RETRY(open("file134", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); +int t3526f88 = TEMP_FAILURE_RETRY(open("file134", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f88, buf, 15056)); close(t3526f88); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34433108)); @@ -2511,7 +2523,7 @@ TEMP_FAILURE_RETRY(pwrite(t3495f75, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3495f75, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3495f75, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3495f75)); -int t3495f86 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3495f86 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3495f86)); close(t3495f86); TEMP_FAILURE_RETRY(pwrite(t3495f75, buf, 12, 0)); @@ -2519,7 +2531,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3495f75)); TEMP_FAILURE_RETRY(pwrite(t3495f75, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3495f75)); close(t3495f75); -int t3499f74 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f74 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f74, buf, 1, 0)); close(t3499f74); t3499f74 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -2535,7 +2547,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f74, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f74, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f74, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f74)); -int t3499f75 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f75 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f75)); close(t3499f75); TEMP_FAILURE_RETRY(pwrite(t3499f74, buf, 12, 0)); @@ -2543,18 +2555,18 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f74)); TEMP_FAILURE_RETRY(pwrite(t3499f74, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f74)); close(t3499f74); -int t3526f64 = TEMP_FAILURE_RETRY(open("file135", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3526f64 = TEMP_FAILURE_RETRY(open("file135", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3526f64); t3526f64 = TEMP_FAILURE_RETRY(open("file135", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f64, buf, 16384)); TEMP_FAILURE_RETRY(write(t3526f64, buf, 4873)); close(t3526f64); -int t3526f90 = TEMP_FAILURE_RETRY(open("file136", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3526f90 = TEMP_FAILURE_RETRY(open("file136", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3526f90); t3526f90 = TEMP_FAILURE_RETRY(open("file136", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f90, buf, 4199)); close(t3526f90); -int t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f90, buf, 1, 0)); close(t3499f90); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35511105)); @@ -2579,7 +2591,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f90, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f90)); -int t3499f92 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f92 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f92)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35513993)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 34, 35514023)); @@ -2620,6 +2632,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f90)); TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f90)); close(t3499f90); +if (!checkpoint(82)) return -1; t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f90, buf, 1, 0)); close(t3499f90); @@ -2644,17 +2657,17 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f90)); TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f90)); close(t3499f90); -int t3495f72 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3495f72 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3495f72, buf, 1, 0)); close(t3495f72); -int t3499f84 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f84 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f84, buf, 1, 0)); close(t3499f84); t3499f72 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 512, 0)); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4, 512)); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4096, 516)); -int t3495f84 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); +int t3495f84 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4, 4612)); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4, 4616)); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4096, 4620)); @@ -2667,7 +2680,7 @@ TEMP_FAILURE_RETRY(pwrite(t3495f84, buf, 4, 512)); TEMP_FAILURE_RETRY(pread(t3499f72, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f72)); TEMP_FAILURE_RETRY(pwrite(t3495f84, buf, 4096, 516)); -int t3499f88 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f88 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f88)); TEMP_FAILURE_RETRY(pwrite(t3495f84, buf, 4, 4612)); TEMP_FAILURE_RETRY(pwrite(t3495f84, buf, 4, 4616)); @@ -2683,7 +2696,7 @@ TEMP_FAILURE_RETRY(pread(t3495f84, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3495f84)); TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f72)); -int t3495f88 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3495f88 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 31156572)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 58, 31156602)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3099, 31154176)); // mmap2 @@ -2698,7 +2711,7 @@ close(t3495f84); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34907552)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 39, 34907582)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2551, 34906112)); // mmap2 -int t3495f66 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3495f66 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3495f66, buf, 1, 0)); close(t3495f66); t3495f66 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -2738,7 +2751,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f66, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f66)); -int t3499f70 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f70 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f70)); close(t3499f70); TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 12, 0)); @@ -2746,11 +2759,11 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f66)); TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f66)); close(t3499f66); -int t3526f66 = TEMP_FAILURE_RETRY(open("file137", O_RDONLY|O_LARGEFILE)); +int t3526f66 = TEMP_FAILURE_RETRY(open("file137", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3526f66, buf, 16384)); TEMP_FAILURE_RETRY(read(t3526f66, buf, 16384)); close(t3526f66); -int t3505f66 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3505f66 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3505f66, buf, 1, 0)); close(t3505f66); t3505f66 = TEMP_FAILURE_RETRY(open("file138", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); @@ -2786,7 +2799,7 @@ TEMP_FAILURE_RETRY(pwrite(t3495f70, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3495f70)); close(t3495f70); TEMP_FAILURE_RETRY(write(t3505f66, buf, 10592)); -int t3533f70 = TEMP_FAILURE_RETRY(open("file140", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3533f70 = TEMP_FAILURE_RETRY(open("file140", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3533f70); t3533f70 = TEMP_FAILURE_RETRY(open("file140", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3533f70, buf, 4042)); @@ -2796,7 +2809,7 @@ TEMP_FAILURE_RETRY(write(t3505f66, buf, 23656)); t3533f70 = TEMP_FAILURE_RETRY(open("file141", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3533f70); t3526f70 = TEMP_FAILURE_RETRY(open("file142", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); -int t3533f72 = TEMP_FAILURE_RETRY(open("file141", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); +int t3533f72 = TEMP_FAILURE_RETRY(open("file141", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); close(t3526f70); t3526f70 = TEMP_FAILURE_RETRY(open("file142", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f70, buf, 5057)); @@ -2838,6 +2851,7 @@ TEMP_FAILURE_RETRY(pread(t3505f66, buf, 1, 0)); close(t3505f66); t3505f66 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 512, 0)); +if (!checkpoint(85)) return -1; TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4, 512)); TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4096, 516)); TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4, 4612)); @@ -2858,7 +2872,7 @@ TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4096, 21036)); TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4, 25132)); TEMP_FAILURE_RETRY(pread(t3505f66, buf, 8, 25600)); TEMP_FAILURE_RETRY(fdatasync(t3505f66)); -int t3505f70 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3505f70 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3505f70)); close(t3505f70); TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 12, 0)); @@ -2923,7 +2937,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1737, 31305728)); // mmap2 TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34261624)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 49, 34261654)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2993, 34258944)); // mmap2 -int t3533f91 = TEMP_FAILURE_RETRY(open("file143", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3533f91 = TEMP_FAILURE_RETRY(open("file143", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3533f91); t3533f91 = TEMP_FAILURE_RETRY(open("file143", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 31210525)); @@ -2932,7 +2946,7 @@ TEMP_FAILURE_RETRY(write(t3533f91, buf, 16384)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3673, 31207424)); // mmap2 TEMP_FAILURE_RETRY(write(t3533f91, buf, 2024)); close(t3533f91); -int t3499f91 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f91 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f91, buf, 1, 0)); close(t3499f91); t3499f91 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -2948,7 +2962,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f91, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f91, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f91, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f91)); -int t3499f93 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f93 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f93)); close(t3499f93); TEMP_FAILURE_RETRY(pwrite(t3499f91, buf, 12, 0)); @@ -2956,7 +2970,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f91)); TEMP_FAILURE_RETRY(pwrite(t3499f91, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f91)); close(t3499f91); -int t3505f84 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3505f84 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3505f84, buf, 1, 0)); close(t3505f84); t3505f84 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -2972,7 +2986,7 @@ TEMP_FAILURE_RETRY(pwrite(t3505f84, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3505f84, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3505f84, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3505f84)); -int t3505f90 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3505f90 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3505f90)); close(t3505f90); TEMP_FAILURE_RETRY(pwrite(t3505f84, buf, 12, 0)); @@ -2980,41 +2994,41 @@ TEMP_FAILURE_RETRY(fdatasync(t3505f84)); TEMP_FAILURE_RETRY(pwrite(t3505f84, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3505f84)); close(t3505f84); -int t3533f102 = TEMP_FAILURE_RETRY(open("file144", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3533f102 = TEMP_FAILURE_RETRY(open("file144", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3533f102); t3533f72 = TEMP_FAILURE_RETRY(open("file144", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3533f72, buf, 5550)); close(t3533f72); -int t3526f84 = TEMP_FAILURE_RETRY(open("file145", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3526f84 = TEMP_FAILURE_RETRY(open("file145", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3526f84); -int t3526f101 = TEMP_FAILURE_RETRY(open("file145", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); +int t3526f101 = TEMP_FAILURE_RETRY(open("file145", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f101, buf, 3612)); close(t3526f101); t3526f90 = TEMP_FAILURE_RETRY(open("file146", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3526f90); t3526f90 = TEMP_FAILURE_RETRY(open("file146", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f90, buf, 5414)); -int t3533f96 = TEMP_FAILURE_RETRY(open("file147", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3533f96 = TEMP_FAILURE_RETRY(open("file147", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3533f96); t3533f96 = TEMP_FAILURE_RETRY(open("file147", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); close(t3526f90); TEMP_FAILURE_RETRY(write(t3533f96, buf, 3834)); close(t3533f96); -int t3519f90 = TEMP_FAILURE_RETRY(open("file148", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3519f90 = TEMP_FAILURE_RETRY(open("file148", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3519f90); t3519f90 = TEMP_FAILURE_RETRY(open("file148", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3519f90, buf, 3461)); -int t3526f96 = TEMP_FAILURE_RETRY(open("file149", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3526f96 = TEMP_FAILURE_RETRY(open("file149", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3526f96); close(t3519f90); t3526f90 = TEMP_FAILURE_RETRY(open("file149", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); TEMP_FAILURE_RETRY(write(t3526f90, buf, 16384)); TEMP_FAILURE_RETRY(write(t3526f90, buf, 12766)); close(t3526f90); -int t3533f90 = TEMP_FAILURE_RETRY(open("file150", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3533f90 = TEMP_FAILURE_RETRY(open("file150", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3533f90); t3533f90 = TEMP_FAILURE_RETRY(open("file150", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); -int t3505f96 = TEMP_FAILURE_RETRY(open("file151", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3505f96 = TEMP_FAILURE_RETRY(open("file151", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3505f96, buf, 100, 0)); TEMP_FAILURE_RETRY(write(t3533f90, buf, 10056)); close(t3533f90); @@ -3036,7 +3050,7 @@ TEMP_FAILURE_RETRY(pread(t3505f90, buf, 1, 0)); close(t3505f90); TEMP_FAILURE_RETRY(pread(t3505f96, buf, 16, 24)); t3505f90 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); -int t3533f99 = TEMP_FAILURE_RETRY(open("file153", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); +int t3533f99 = TEMP_FAILURE_RETRY(open("file153", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600)); close(t3533f99); TEMP_FAILURE_RETRY(pread(t3505f90, buf, 1, 0)); close(t3505f90); @@ -3046,7 +3060,7 @@ TEMP_FAILURE_RETRY(write(t3533f90, buf, 13271)); close(t3533f90); TEMP_FAILURE_RETRY(pread(t3505f96, buf, 4096, 16384)); TEMP_FAILURE_RETRY(pread(t3505f96, buf, 4096, 12288)); -int t3505f99 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3505f99 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3505f99, buf, 1, 0)); close(t3505f99); TEMP_FAILURE_RETRY(pread(t3505f96, buf, 16, 24)); @@ -3066,6 +3080,7 @@ TEMP_FAILURE_RETRY(pread(t3505f96, buf, 16, 24)); t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f90, buf, 1, 0)); close(t3499f90); +if (!checkpoint(88)) return -1; t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 512, 0)); TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4, 512)); @@ -3079,7 +3094,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f90, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f90)); -int t3499f97 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f97 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f97)); close(t3499f97); TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 12, 0)); @@ -3114,7 +3129,7 @@ close(t3499f90); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34438470)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 63, 34438500)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3681, 34435072)); // mmap2 -int t3576f95 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3576f95 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3576f95, buf, 1, 0)); close(t3576f95); t3499f92 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); @@ -3136,7 +3151,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f92, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3499f92, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f92, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f92)); -int t3499f95 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f95 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f95)); close(t3499f95); TEMP_FAILURE_RETRY(pwrite(t3499f92, buf, 12, 0)); @@ -3174,7 +3189,7 @@ close(t3499f92); t3576f95 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3576f95, buf, 1, 0)); close(t3576f95); -int t3499f100 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f100 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f100, buf, 1, 0)); close(t3499f100); t3499f100 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -3190,7 +3205,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f100, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f100)); -int t3499f106 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f106 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f106)); close(t3499f106); TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 12, 0)); @@ -3217,7 +3232,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 4096, 12828)); TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 4, 16924)); TEMP_FAILURE_RETRY(pread(t3499f100, buf, 8, 17408)); TEMP_FAILURE_RETRY(fdatasync(t3499f100)); -int t3499f105 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f105 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f105)); close(t3499f105); TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 12, 0)); @@ -3278,11 +3293,12 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f100)); close(t3499f100); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35636928)); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 60, 35636958)); +if (!checkpoint(91)) return -1; TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2062, 35635200)); // mmap2 t3499f84 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f84, buf, 1, 0)); close(t3499f84); -int t3499f27 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); +int t3499f27 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); TEMP_FAILURE_RETRY(pwrite(t3499f27, buf, 512, 0)); TEMP_FAILURE_RETRY(pwrite(t3499f27, buf, 4, 512)); TEMP_FAILURE_RETRY(pwrite(t3499f27, buf, 4096, 516)); @@ -3360,9 +3376,9 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f92)); TEMP_FAILURE_RETRY(pwrite(t3499f92, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f92)); close(t3499f92); -int t3545f92 = TEMP_FAILURE_RETRY(open("file154", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3545f92 = TEMP_FAILURE_RETRY(open("file154", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3545f92, buf, 100, 0)); -int t3545f97 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3545f97 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f97, buf, 1, 0)); close(t3545f97); TEMP_FAILURE_RETRY(pread(t3545f92, buf, 4096, 0)); @@ -3392,7 +3408,7 @@ t3545f97 = TEMP_FAILURE_RETRY(open("file156", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3545f97, buf, 8)); TEMP_FAILURE_RETRY(read(t3545f97, buf, 1)); close(t3545f97); -int t3545f100 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3545f100 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f100, buf, 1, 0)); close(t3545f100); TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24)); @@ -3427,11 +3443,11 @@ TEMP_FAILURE_RETRY(fdatasync(t3545f92)); TEMP_FAILURE_RETRY(pwrite(t3545f97, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3545f97)); close(t3545f97); -int t3545f104 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3545f104 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f104, buf, 1, 0)); close(t3545f104); TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24)); -int t3545f29 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3545f29 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f29, buf, 1, 0)); close(t3545f29); TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24)); @@ -3460,7 +3476,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3545f92)); TEMP_FAILURE_RETRY(pwrite(t3545f97, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3545f97)); close(t3545f97); -int t3575f29 = TEMP_FAILURE_RETRY(open("file16", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0)); +int t3575f29 = TEMP_FAILURE_RETRY(open("file16", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0)); TEMP_FAILURE_RETRY(write(t3575f29, buf, 17344)); close(t3575f29); t3545f97 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); @@ -3496,7 +3512,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3545f92)); TEMP_FAILURE_RETRY(pwrite(t3545f29, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3545f29)); close(t3545f29); -int t3499f26 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f26 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f26, buf, 1, 0)); close(t3499f26); t3499f26 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -3514,6 +3530,7 @@ TEMP_FAILURE_RETRY(pread(t3499f26, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f26)); t3499f97 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f97)); +if (!checkpoint(93)) return -1; close(t3499f97); TEMP_FAILURE_RETRY(pwrite(t3499f26, buf, 12, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f26)); @@ -3523,7 +3540,7 @@ close(t3499f26); t3499f26 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f26, buf, 1, 0)); close(t3499f26); -int t3499f28 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); +int t3499f28 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); TEMP_FAILURE_RETRY(pwrite(t3499f28, buf, 512, 0)); TEMP_FAILURE_RETRY(pwrite(t3499f28, buf, 4, 512)); TEMP_FAILURE_RETRY(pwrite(t3499f28, buf, 4096, 516)); @@ -3548,7 +3565,7 @@ t3545f97 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f97, buf, 1, 0)); close(t3545f97); TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24)); -int t3545f90 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3545f90 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f90, buf, 1, 0)); close(t3545f90); TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24)); @@ -3594,13 +3611,13 @@ TEMP_FAILURE_RETRY(fdatasync(t3545f92)); TEMP_FAILURE_RETRY(pwrite(t3545f29, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3545f29)); close(t3545f29); -int t3545f84 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3545f84 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f84, buf, 1, 0)); close(t3545f84); TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24)); -int t3584f84 = TEMP_FAILURE_RETRY(open("file157", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3584f84 = TEMP_FAILURE_RETRY(open("file157", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3584f84, buf, 100, 0)); -int t3584f90 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3584f90 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3584f90, buf, 1, 0)); close(t3584f90); t3545f90 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); @@ -3619,13 +3636,13 @@ TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 4, 8716)); TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 4, 8720)); TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 4, 12820)); -int t3584f99 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3584f99 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f90, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3545f90)); TEMP_FAILURE_RETRY(pread(t3584f99, buf, 1, 0)); close(t3584f99); TEMP_FAILURE_RETRY(pread(t3584f84, buf, 16, 24)); -int t3545f99 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3545f99 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3545f99)); close(t3545f99); TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 12, 0)); @@ -3637,16 +3654,16 @@ TEMP_FAILURE_RETRY(fdatasync(t3545f92)); TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3545f90)); close(t3545f90); -int t3584f29 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3584f29 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3584f29, buf, 1, 0)); close(t3584f29); TEMP_FAILURE_RETRY(pread(t3584f84, buf, 16, 24)); TEMP_FAILURE_RETRY(pread(t3584f84, buf, 4096, 8192)); -int t3584f27 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3584f27 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3584f27, buf, 1, 0)); close(t3584f27); TEMP_FAILURE_RETRY(pread(t3584f84, buf, 16, 24)); -int t3545f95 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3545f95 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); t3584f99 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3545f95, buf, 1, 0)); TEMP_FAILURE_RETRY(pread(t3584f99, buf, 1, 0)); @@ -3665,7 +3682,7 @@ TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 4612)); TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 4616)); TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4096, 4620)); TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 8716)); -int t3584f95 = TEMP_FAILURE_RETRY(open("file159", O_RDONLY|O_LARGEFILE)); +int t3584f95 = TEMP_FAILURE_RETRY(open("file159", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3584f95, buf, 8)); TEMP_FAILURE_RETRY(read(t3584f95, buf, 1)); close(t3584f95); @@ -3679,7 +3696,7 @@ TEMP_FAILURE_RETRY(pread(t3545f92, buf, 4096, 4096)); TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 16928)); TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4096, 16932)); TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 21028)); -int t3584f101 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3584f101 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3584f101, buf, 1, 0)); close(t3584f101); TEMP_FAILURE_RETRY(pread(t3584f84, buf, 16, 24)); @@ -3722,7 +3739,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3545f92)); TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3545f99)); close(t3545f99); -int t3581f99 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3581f99 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3581f99, buf, 1, 0)); close(t3581f99); TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34970937)); @@ -3760,6 +3777,7 @@ close(t3533f90); t3526f90 = TEMP_FAILURE_RETRY(open("file162", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384)); TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384)); +if (!checkpoint(96)) return -1; close(t3526f90); t3526f90 = TEMP_FAILURE_RETRY(open("file163", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384)); @@ -3773,20 +3791,20 @@ t3526f90 = TEMP_FAILURE_RETRY(open("file165", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384)); TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384)); close(t3526f90); -int t3586f102 = TEMP_FAILURE_RETRY(open("file166", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3586f102 = TEMP_FAILURE_RETRY(open("file166", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3586f102); -int t3586f97 = TEMP_FAILURE_RETRY(open("file167", O_RDONLY|O_LARGEFILE)); +int t3586f97 = TEMP_FAILURE_RETRY(open("file167", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3586f97, buf, 8192)); TEMP_FAILURE_RETRY(read(t3586f97, buf, 8192)); close(t3586f97); -int t3587f95 = TEMP_FAILURE_RETRY(open("file168", O_RDONLY|O_LARGEFILE)); +int t3587f95 = TEMP_FAILURE_RETRY(open("file168", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3587f95, buf, 16384)); close(t3587f95); t3499f28 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f28, buf, 1, 0)); close(t3499f28); -int t3496f28 = TEMP_FAILURE_RETRY(open("file169", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); -int t3499f103 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); +int t3496f28 = TEMP_FAILURE_RETRY(open("file169", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600)); +int t3499f103 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); TEMP_FAILURE_RETRY(pwrite(t3499f103, buf, 512, 0)); TEMP_FAILURE_RETRY(pwrite(t3499f103, buf, 4, 512)); TEMP_FAILURE_RETRY(pwrite(t3499f103, buf, 4096, 516)); @@ -3835,9 +3853,9 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f28)); TEMP_FAILURE_RETRY(pwrite(t3499f28, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f28)); close(t3499f28); -int t3541f103 = TEMP_FAILURE_RETRY(open("file170", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3541f103 = TEMP_FAILURE_RETRY(open("file170", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3541f103, buf, 100, 0)); -int t3541f105 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3541f105 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3541f105, buf, 1, 0)); close(t3541f105); TEMP_FAILURE_RETRY(pread(t3541f103, buf, 4096, 0)); @@ -3864,12 +3882,12 @@ t3541f105 = TEMP_FAILURE_RETRY(open("file172", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3541f105, buf, 8)); TEMP_FAILURE_RETRY(read(t3541f105, buf, 1)); close(t3541f105); -int t3541f106 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3541f106 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3541f106, buf, 1, 0)); close(t3541f106); TEMP_FAILURE_RETRY(pread(t3541f103, buf, 16, 24)); TEMP_FAILURE_RETRY(pread(t3541f103, buf, 4096, 20480)); -int t3499f107 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f107 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f107, buf, 1, 0)); close(t3499f107); t3499f107 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660)); @@ -3885,7 +3903,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f107, buf, 4096, 8724)); TEMP_FAILURE_RETRY(pwrite(t3499f107, buf, 4, 12820)); TEMP_FAILURE_RETRY(pread(t3499f107, buf, 8, 13312)); TEMP_FAILURE_RETRY(fdatasync(t3499f107)); -int t3499f108 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3499f108 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(fdatasync(t3499f108)); close(t3499f108); TEMP_FAILURE_RETRY(pwrite(t3499f107, buf, 12, 0)); @@ -3917,16 +3935,16 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f105)); TEMP_FAILURE_RETRY(pwrite(t3499f105, buf, 28, 0)); TEMP_FAILURE_RETRY(fdatasync(t3499f105)); close(t3499f105); -int t3505f106 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3505f106 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3505f106, buf, 1, 0)); close(t3505f106); -int t3540f107 = TEMP_FAILURE_RETRY(open("file173", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3540f107 = TEMP_FAILURE_RETRY(open("file173", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3540f107, buf, 100, 0)); -int t3540f108 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3540f108 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3540f108, buf, 1, 0)); close(t3540f108); TEMP_FAILURE_RETRY(pread(t3540f107, buf, 4096, 0)); -int t3540f105 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3540f105 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3540f105, buf, 1, 0)); close(t3540f105); TEMP_FAILURE_RETRY(pread(t3540f107, buf, 16, 24)); @@ -3949,7 +3967,7 @@ t3540f105 = TEMP_FAILURE_RETRY(open("file175", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3540f105, buf, 8)); TEMP_FAILURE_RETRY(read(t3540f105, buf, 1)); close(t3540f105); -int t3540f106 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3540f106 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3540f106, buf, 1, 0)); close(t3540f106); TEMP_FAILURE_RETRY(pread(t3540f107, buf, 16, 24)); @@ -3963,14 +3981,14 @@ t3540f106 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3540f106, buf, 1, 0)); close(t3540f106); TEMP_FAILURE_RETRY(pread(t3540f107, buf, 16, 24)); -int t3496f105 = TEMP_FAILURE_RETRY(open("file176", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); +int t3496f105 = TEMP_FAILURE_RETRY(open("file176", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC)); close(t3496f105); t3499f108 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3499f108, buf, 1, 0)); close(t3499f108); -int t3597f108 = TEMP_FAILURE_RETRY(open("file177", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); +int t3597f108 = TEMP_FAILURE_RETRY(open("file177", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600)); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 100, 0)); -int t3597f109 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3597f109 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3597f109, buf, 1, 0)); close(t3597f109); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 0)); @@ -3987,27 +4005,28 @@ t3597f109 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3597f109, buf, 1, 0)); close(t3597f109); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24)); -int t3540f109 = TEMP_FAILURE_RETRY(open("file179", O_RDONLY|O_LARGEFILE)); +int t3540f109 = TEMP_FAILURE_RETRY(open("file179", O_RDONLY|O_LARGEFILE)); TEMP_FAILURE_RETRY(read(t3540f109, buf, 4000)); -int t3597f110 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3597f110 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3597f110, buf, 1, 0)); close(t3597f110); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24)); close(t3540f109); +if (!checkpoint(99)) return -1; TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 16384)); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 12288)); t3597f109 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3597f109, buf, 1, 0)); close(t3597f109); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24)); -int t3597f111 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3597f111 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3597f111, buf, 1, 0)); close(t3597f111); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24)); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 24576)); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 20480)); TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 57344)); -int t3598f111 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); +int t3598f111 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC)); TEMP_FAILURE_RETRY(pread(t3598f111, buf, 1, 0)); close(t3598f111); close(t3540f107); @@ -4054,7 +4073,7 @@ static status_t CreateFile(const char* name, int len) { return OK; } -static status_t BenchmarkCreate() { +static status_t BenchmarkCreate(std::function checkpoint) { status_t res = 0; res |= CreateFile("stub", 0); @@ -4069,6 +4088,7 @@ res |= CreateFile("file175", 9); res |= CreateFile("file76", 0); res |= CreateFile("file140", 4042); res |= CreateFile("file80", 0); +if (!checkpoint(3)) return -1; res |= CreateFile("file139", 49152); res |= CreateFile("file50", 32768); res |= CreateFile("file179", 4000); @@ -4081,6 +4101,7 @@ res |= CreateFile("file53", 32768); res |= CreateFile("file72", 0); res |= CreateFile("file55", 16384); res |= CreateFile("file54", 39938); +if (!checkpoint(6)) return -1; res |= CreateFile("file129", 3974); res |= CreateFile("file107", 0); res |= CreateFile("file95", 0); @@ -4093,6 +4114,7 @@ res |= CreateFile("file89", 0); res |= CreateFile("file40", 4172); res |= CreateFile("file20", 1); res |= CreateFile("file151", 499712); +if (!checkpoint(10)) return -1; res |= CreateFile("file106", 0); res |= CreateFile("file159", 9); res |= CreateFile("file47", 32768); @@ -4105,6 +4127,7 @@ res |= CreateFile("file172", 9); res |= CreateFile("file148", 3461); res |= CreateFile("file7", 794976); res |= CreateFile("file68", 32768); +if (!checkpoint(13)) return -1; res |= CreateFile("file109", 0); res |= CreateFile("file142", 5057); res |= CreateFile("file147", 3834); @@ -4117,6 +4140,7 @@ res |= CreateFile("file105", 0); res |= CreateFile("file79", 0); res |= CreateFile("file65", 32768); res |= CreateFile("file135", 21257); +if (!checkpoint(16)) return -1; res |= CreateFile("file124", 0); res |= CreateFile("file87", 0); res |= CreateFile("file64", 49152); @@ -4129,6 +4153,7 @@ res |= CreateFile("file178", 1); res |= CreateFile("file163", 32768); res |= CreateFile("file67", 32768); res |= CreateFile("file155", 21512); +if (!checkpoint(20)) return -1; res |= CreateFile("file156", 9); res |= CreateFile("file23", 28700); res |= CreateFile("file61", 32768); @@ -4141,6 +4166,7 @@ res |= CreateFile("file24", 94220); res |= CreateFile("file57", 32768); res |= CreateFile("file104", 0); res |= CreateFile("file113", 0); +if (!checkpoint(23)) return -1; res |= CreateFile("file99", 0); res |= CreateFile("file120", 0); res |= CreateFile("file154", 73728); @@ -4153,6 +4179,7 @@ res |= CreateFile("file96", 0); res |= CreateFile("file91", 0); res |= CreateFile("file158", 1); res |= CreateFile("file174", 1); +if (!checkpoint(26)) return -1; res |= CreateFile("file48", 32768); res |= CreateFile("file33", 32566); res |= CreateFile("file83", 0); @@ -4165,6 +4192,7 @@ res |= CreateFile("file16", 31392); res |= CreateFile("file164", 32768); res |= CreateFile("file36", 192544); res |= CreateFile("file6", 4636); +if (!checkpoint(30)) return -1; res |= CreateFile("file10", 16484); res |= CreateFile("file150", 10056); res |= CreateFile("file62", 32768); @@ -4177,6 +4205,7 @@ res |= CreateFile("file100", 0); res |= CreateFile("file103", 0); res |= CreateFile("file26", 28676); res |= CreateFile("file46", 32768); +if (!checkpoint(33)) return -1; res |= CreateFile("file60", 32768); res |= CreateFile("file162", 32768); res |= CreateFile("file25", 32872); @@ -4189,6 +4218,7 @@ res |= CreateFile("file51", 32768); res |= CreateFile("file37", 159752); res |= CreateFile("file73", 0); res |= CreateFile("file71", 32768); +if (!checkpoint(36)) return -1; res |= CreateFile("file98", 0); res |= CreateFile("file74", 0); res |= CreateFile("file93", 0); @@ -4201,6 +4231,7 @@ res |= CreateFile("file136", 4199); res |= CreateFile("file132", 23233); res |= CreateFile("file92", 0); res |= CreateFile("file11", 0); +if (!checkpoint(40)) return -1; res |= CreateFile("file86", 0); res |= CreateFile("file22", 0); res |= CreateFile("file56", 16384); @@ -4213,6 +4244,7 @@ res |= CreateFile("file63", 49152); res |= CreateFile("file116", 0); res |= CreateFile("file29", 1035); res |= CreateFile("file35", 118788); +if (!checkpoint(43)) return -1; res |= CreateFile("file170", 24576); res |= CreateFile("file30", 98304); res |= CreateFile("file14", 0); @@ -4225,6 +4257,7 @@ res |= CreateFile("file18", 17416); res |= CreateFile("file134", 15056); res |= CreateFile("file31", 25608); res |= CreateFile("file97", 0); +if (!checkpoint(46)) return -1; res |= CreateFile("file84", 0); res |= CreateFile("file114", 0); res |= CreateFile("file88", 0); @@ -4237,6 +4270,7 @@ res |= CreateFile("file133", 13332); res |= CreateFile("file169", 11354); res |= CreateFile("file166", 0); res |= CreateFile("file49", 32768); +if (!checkpoint(50)) return -1; res |= CreateFile("file177", 61440); return res; diff --git a/bench/benchgen.py b/bench/benchgen.py index c852169..f119804 100644 --- a/bench/benchgen.py +++ b/bench/benchgen.py @@ -157,6 +157,7 @@ with open("BenchmarkGen.h", 'w') as bench: #include #include +#include #include #include @@ -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 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 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, """ From 701d05d32c8b415c6fbb2e8c9439185333870046 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 7 Nov 2017 09:44:16 -0800 Subject: [PATCH 050/106] Vold: Add fsync in writeStringToFile() Test: Build, test with ag/3180275 Bug: 68901441 Change-Id: Ieca9e5227025e00184a67508d5e8fbbddd12f21e --- KeyStorage.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/KeyStorage.cpp b/KeyStorage.cpp index 9d61555..20b2391 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -35,6 +35,7 @@ #include #include +#include #include @@ -153,10 +154,29 @@ 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)) { - PLOG(ERROR) << "Failed to write to " << 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; } From f4527740309a9f89d9a32de9da40cafaa628cd88 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Thu, 9 Nov 2017 15:59:39 -0700 Subject: [PATCH 051/106] Break vold dependency on keystore utilities. This is temporary. Keystore is in the process of being upgraded to use the new Keymaster 4.0 HAL, and I want to leave vold alone, using Keymaster 3.0 for the moment. This CL just copies relevant bits of keystore support utilities into vold, so it can stop depending on the copies from keystore. After the keystore update is complete, vold will be changed either to use Keymaster 4.0 or -- more likely -- to use keystore rather than talking to Keymaster directly. At that point the files added by this CL will be deleted. Test: Device boots and successfully decrypts /data Change-Id: I73f6d4cc4c5e20d89d7ac37d29d025bf279f9e12 --- Android.bp | 2 +- KeyStorage.cpp | 5 +- Keymaster.cpp | 7 +- Keymaster.h | 3 +- authorization_set.cpp | 420 ++++++++++++++++++++++++++++++++++++++++ authorization_set.h | 327 +++++++++++++++++++++++++++++++ keymaster_tags.h | 372 +++++++++++++++++++++++++++++++++++ keystore_hidl_support.h | 108 +++++++++++ 8 files changed, 1237 insertions(+), 7 deletions(-) create mode 100644 authorization_set.cpp create mode 100644 authorization_set.h create mode 100644 keymaster_tags.h create mode 100644 keystore_hidl_support.h diff --git a/Android.bp b/Android.bp index 5941cd9..cc015bf 100644 --- a/Android.bp +++ b/Android.bp @@ -50,7 +50,6 @@ cc_defaults { "libhardware_legacy", "libhidlbase", "libhwbinder", - "libkeystore_binder", "libkeyutils", "liblog", "liblogwrap", @@ -111,6 +110,7 @@ cc_library_static { "VoldNativeService.cpp", "VoldUtil.cpp", "VolumeManager.cpp", + "authorization_set.cpp", "cryptfs.cpp", "fs/Ext4.cpp", "fs/F2fs.cpp", diff --git a/KeyStorage.cpp b/KeyStorage.cpp index 8878a3c..7e1d4a7 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -40,14 +40,15 @@ #include -#include -#include extern "C" { #include "crypto_scrypt.h" } +#include "authorization_set.h" +#include "keystore_hidl_support.h" + namespace android { namespace vold { using namespace keystore; diff --git a/Keymaster.cpp b/Keymaster.cpp index 1bbeb61..e2e21e8 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -17,9 +17,10 @@ #include "Keymaster.h" #include -#include -#include -#include + +#include "authorization_set.h" +#include "keymaster_tags.h" +#include "keystore_hidl_support.h" using namespace ::keystore; using android::hardware::hidl_string; diff --git a/Keymaster.h b/Keymaster.h index f24a0c0..34fe59c 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -25,7 +25,8 @@ #include #include -#include + +#include "authorization_set.h" namespace android { namespace vold { diff --git a/authorization_set.cpp b/authorization_set.cpp new file mode 100644 index 0000000..e7a3401 --- /dev/null +++ b/authorization_set.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2014 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 "authorization_set.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace keystore { + +inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) { + if (a.tag != b.tag) return a.tag < b.tag; + int retval; + switch (typeFromTag(a.tag)) { + case TagType::INVALID: + case TagType::BOOL: + return false; + case TagType::ENUM: + case TagType::ENUM_REP: + case TagType::UINT: + case TagType::UINT_REP: + return a.f.integer < b.f.integer; + case TagType::ULONG: + case TagType::ULONG_REP: + return a.f.longInteger < b.f.longInteger; + case TagType::DATE: + return a.f.dateTime < b.f.dateTime; + case TagType::BIGNUM: + case TagType::BYTES: + // Handle the empty cases. + if (a.blob.size() == 0) return b.blob.size() != 0; + if (b.blob.size() == 0) return false; + + retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size())); + // if one is the prefix of the other the longer wins + if (retval == 0) return a.blob.size() < b.blob.size(); + // Otherwise a is less if a is less. + else + return retval < 0; + } + return false; +} + +inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) { + if (a.tag != b.tag) return false; + + switch (typeFromTag(a.tag)) { + case TagType::INVALID: + case TagType::BOOL: + return true; + case TagType::ENUM: + case TagType::ENUM_REP: + case TagType::UINT: + case TagType::UINT_REP: + return a.f.integer == b.f.integer; + case TagType::ULONG: + case TagType::ULONG_REP: + return a.f.longInteger == b.f.longInteger; + case TagType::DATE: + return a.f.dateTime == b.f.dateTime; + case TagType::BIGNUM: + case TagType::BYTES: + if (a.blob.size() != b.blob.size()) return false; + return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0; + } + return false; +} + +void AuthorizationSet::Sort() { + std::sort(data_.begin(), data_.end(), keyParamLess); +} + +void AuthorizationSet::Deduplicate() { + if (data_.empty()) return; + + Sort(); + std::vector result; + + auto curr = data_.begin(); + auto prev = curr++; + for (; curr != data_.end(); ++prev, ++curr) { + if (prev->tag == Tag::INVALID) continue; + + if (!keyParamEqual(*prev, *curr)) { + result.emplace_back(std::move(*prev)); + } + } + result.emplace_back(std::move(*prev)); + + std::swap(data_, result); +} + +void AuthorizationSet::Union(const AuthorizationSet& other) { + data_.insert(data_.end(), other.data_.begin(), other.data_.end()); + Deduplicate(); +} + +void AuthorizationSet::Subtract(const AuthorizationSet& other) { + Deduplicate(); + + auto i = other.begin(); + while (i != other.end()) { + int pos = -1; + do { + pos = find(i->tag, pos); + if (pos != -1 && keyParamEqual(*i, data_[pos])) { + data_.erase(data_.begin() + pos); + break; + } + } while (pos != -1); + ++i; + } +} + +int AuthorizationSet::find(Tag tag, int begin) const { + auto iter = data_.begin() + (1 + begin); + + while (iter != data_.end() && iter->tag != tag) ++iter; + + if (iter != data_.end()) return iter - data_.begin(); + return -1; +} + +bool AuthorizationSet::erase(int index) { + auto pos = data_.begin() + index; + if (pos != data_.end()) { + data_.erase(pos); + return true; + } + return false; +} + +KeyParameter& AuthorizationSet::operator[](int at) { + return data_[at]; +} + +const KeyParameter& AuthorizationSet::operator[](int at) const { + return data_[at]; +} + +void AuthorizationSet::Clear() { + data_.clear(); +} + +size_t AuthorizationSet::GetTagCount(Tag tag) const { + size_t count = 0; + for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count; + return count; +} + +NullOr AuthorizationSet::GetEntry(Tag tag) const { + int pos = find(tag); + if (pos == -1) return {}; + return data_[pos]; +} + +/** + * Persistent format is: + * | 32 bit indirect_size | + * -------------------------------- + * | indirect_size bytes of data | this is where the blob data is stored + * -------------------------------- + * | 32 bit element_count | number of entries + * | 32 bit elements_size | total bytes used by entries (entries have variable length) + * -------------------------------- + * | elementes_size bytes of data | where the elements are stored + */ + +/** + * Persistent format of blobs and bignums: + * | 32 bit tag | + * | 32 bit blob_length | + * | 32 bit indirect_offset | + */ + +struct OutStreams { + std::ostream& indirect; + std::ostream& elements; +}; + +OutStreams& serializeParamValue(OutStreams& out, const hidl_vec& blob) { + uint32_t buffer; + + // write blob_length + auto blob_length = blob.size(); + if (blob_length > std::numeric_limits::max()) { + out.elements.setstate(std::ios_base::badbit); + return out; + } + buffer = blob_length; + out.elements.write(reinterpret_cast(&buffer), sizeof(uint32_t)); + + // write indirect_offset + auto offset = out.indirect.tellp(); + if (offset < 0 || offset > std::numeric_limits::max() || + uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check + out.elements.setstate(std::ios_base::badbit); + return out; + } + buffer = offset; + out.elements.write(reinterpret_cast(&buffer), sizeof(uint32_t)); + + // write blob to indirect stream + if (blob_length) out.indirect.write(reinterpret_cast(&blob[0]), blob_length); + + return out; +} + +template +OutStreams& serializeParamValue(OutStreams& out, const T& value) { + out.elements.write(reinterpret_cast(&value), sizeof(T)); + return out; +} + +OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) { + // skip invalid entries. + return out; +} +template +OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) { + out.elements.write(reinterpret_cast(¶m.tag), sizeof(int32_t)); + return serializeParamValue(out, accessTagValue(ttag, param)); +} + +template +struct choose_serializer; +template +struct choose_serializer> { + static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + return choose_serializer::serialize(out, param); + } +}; +template <> +struct choose_serializer<> { + static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; } +}; +template +struct choose_serializer, Tail...> { + static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + if (param.tag == tag) { + return keystore::serialize(TypedTag(), out, param); + } else { + return choose_serializer::serialize(out, param); + } + } +}; + +OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + return choose_serializer::serialize(out, param); +} + +std::ostream& serialize(std::ostream& out, const std::vector& params) { + std::stringstream indirect; + std::stringstream elements; + OutStreams streams = {indirect, elements}; + for (const auto& param : params) { + serialize(streams, param); + } + if (indirect.bad() || elements.bad()) { + out.setstate(std::ios_base::badbit); + return out; + } + auto pos = indirect.tellp(); + if (pos < 0 || pos > std::numeric_limits::max()) { + out.setstate(std::ios_base::badbit); + return out; + } + uint32_t indirect_size = pos; + pos = elements.tellp(); + if (pos < 0 || pos > std::numeric_limits::max()) { + out.setstate(std::ios_base::badbit); + return out; + } + uint32_t elements_size = pos; + uint32_t element_count = params.size(); + + out.write(reinterpret_cast(&indirect_size), sizeof(uint32_t)); + + pos = out.tellp(); + if (indirect_size) out << indirect.rdbuf(); + assert(out.tellp() - pos == indirect_size); + + out.write(reinterpret_cast(&element_count), sizeof(uint32_t)); + out.write(reinterpret_cast(&elements_size), sizeof(uint32_t)); + + pos = out.tellp(); + if (elements_size) out << elements.rdbuf(); + assert(out.tellp() - pos == elements_size); + + return out; +} + +struct InStreams { + std::istream& indirect; + std::istream& elements; +}; + +InStreams& deserializeParamValue(InStreams& in, hidl_vec* blob) { + uint32_t blob_length = 0; + uint32_t offset = 0; + in.elements.read(reinterpret_cast(&blob_length), sizeof(uint32_t)); + blob->resize(blob_length); + in.elements.read(reinterpret_cast(&offset), sizeof(uint32_t)); + in.indirect.seekg(offset); + in.indirect.read(reinterpret_cast(&(*blob)[0]), blob->size()); + return in; +} + +template +InStreams& deserializeParamValue(InStreams& in, T* value) { + in.elements.read(reinterpret_cast(value), sizeof(T)); + return in; +} + +InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) { + // there should be no invalid KeyParamaters but if handle them as zero sized. + return in; +} + +template +InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) { + return deserializeParamValue(in, &accessTagValue(ttag, *param)); +} + +template +struct choose_deserializer; +template +struct choose_deserializer> { + static InStreams& deserialize(InStreams& in, KeyParameter* param) { + return choose_deserializer::deserialize(in, param); + } +}; +template <> +struct choose_deserializer<> { + static InStreams& deserialize(InStreams& in, KeyParameter*) { + // encountered an unknown tag -> fail parsing + in.elements.setstate(std::ios_base::badbit); + return in; + } +}; +template +struct choose_deserializer, Tail...> { + static InStreams& deserialize(InStreams& in, KeyParameter* param) { + if (param->tag == tag) { + return keystore::deserialize(TypedTag(), in, param); + } else { + return choose_deserializer::deserialize(in, param); + } + } +}; + +InStreams& deserialize(InStreams& in, KeyParameter* param) { + in.elements.read(reinterpret_cast(¶m->tag), sizeof(Tag)); + return choose_deserializer::deserialize(in, param); +} + +std::istream& deserialize(std::istream& in, std::vector* params) { + uint32_t indirect_size = 0; + in.read(reinterpret_cast(&indirect_size), sizeof(uint32_t)); + std::string indirect_buffer(indirect_size, '\0'); + if (indirect_buffer.size() != indirect_size) { + in.setstate(std::ios_base::badbit); + return in; + } + in.read(&indirect_buffer[0], indirect_buffer.size()); + + uint32_t element_count = 0; + in.read(reinterpret_cast(&element_count), sizeof(uint32_t)); + uint32_t elements_size = 0; + in.read(reinterpret_cast(&elements_size), sizeof(uint32_t)); + + std::string elements_buffer(elements_size, '\0'); + if (elements_buffer.size() != elements_size) { + in.setstate(std::ios_base::badbit); + return in; + } + in.read(&elements_buffer[0], elements_buffer.size()); + + if (in.bad()) return in; + + // TODO write one-shot stream buffer to avoid copying here + std::stringstream indirect(indirect_buffer); + std::stringstream elements(elements_buffer); + InStreams streams = {indirect, elements}; + + params->resize(element_count); + + for (uint32_t i = 0; i < element_count; ++i) { + deserialize(streams, &(*params)[i]); + } + return in; +} +void AuthorizationSet::Serialize(std::ostream* out) const { + serialize(*out, data_); +} +void AuthorizationSet::Deserialize(std::istream* in) { + deserialize(*in, &data_); +} + +} // namespace keystore diff --git a/authorization_set.h b/authorization_set.h new file mode 100644 index 0000000..8f68bb0 --- /dev/null +++ b/authorization_set.h @@ -0,0 +1,327 @@ +/* + * Copyright 2014 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 SYSTEM_VOLD_AUTHORIZATION_SET_H_ +#define SYSTEM_VOLD_AUTHORIZATION_SET_H_ + +#include + +#include "keymaster_tags.h" + +namespace keystore { + +class AuthorizationSetBuilder; + +/** + * An ordered collection of KeyParameters. It provides memory ownership and some convenient + * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters. + * For serialization, wrap the backing store of this structure in a hidl_vec. + */ +class AuthorizationSet { + public: + /** + * Construct an empty, dynamically-allocated, growable AuthorizationSet. + */ + AuthorizationSet(){}; + + // Copy constructor. + AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {} + + // Move constructor. + AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {} + + // Constructor from hidl_vec + AuthorizationSet(const hidl_vec& other) { *this = other; } + + // Copy assignment. + AuthorizationSet& operator=(const AuthorizationSet& other) { + data_ = other.data_; + return *this; + } + + // Move assignment. + AuthorizationSet& operator=(AuthorizationSet&& other) { + data_ = std::move(other.data_); + return *this; + } + + AuthorizationSet& operator=(const hidl_vec& other) { + if (other.size() > 0) { + data_.resize(other.size()); + for (size_t i = 0; i < data_.size(); ++i) { + /* This makes a deep copy even of embedded blobs. + * See assignment operator/copy constructor of hidl_vec.*/ + data_[i] = other[i]; + } + } + return *this; + } + + /** + * Clear existing authorization set data + */ + void Clear(); + + ~AuthorizationSet() = default; + + /** + * Returns the size of the set. + */ + size_t size() const { return data_.size(); } + + /** + * Returns true if the set is empty. + */ + bool empty() const { return size() == 0; } + + /** + * Returns the data in the set, directly. Be careful with this. + */ + const KeyParameter* data() const { return data_.data(); } + + /** + * Sorts the set + */ + void Sort(); + + /** + * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the + * AuthorizationSetBuilder). + */ + void Deduplicate(); + + /** + * Adds all elements from \p set that are not already present in this AuthorizationSet. As a + * side-effect, if \p set is not null this AuthorizationSet will end up sorted. + */ + void Union(const AuthorizationSet& set); + + /** + * Removes all elements in \p set from this AuthorizationSet. + */ + void Subtract(const AuthorizationSet& set); + + /** + * Returns the offset of the next entry that matches \p tag, starting from the element after \p + * begin. If not found, returns -1. + */ + int find(Tag tag, int begin = -1) const; + + /** + * Removes the entry at the specified index. Returns true if successful, false if the index was + * out of bounds. + */ + bool erase(int index); + + /** + * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration + */ + std::vector::const_iterator begin() const { return data_.begin(); } + + /** + * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration + */ + std::vector::const_iterator end() const { return data_.end(); } + + /** + * Returns the nth element of the set. + * Like for std::vector::operator[] there is no range check performed. Use of out of range + * indices is undefined. + */ + KeyParameter& operator[](int n); + + /** + * Returns the nth element of the set. + * Like for std::vector::operator[] there is no range check performed. Use of out of range + * indices is undefined. + */ + const KeyParameter& operator[](int n) const; + + /** + * Returns true if the set contains at least one instance of \p tag + */ + bool Contains(Tag tag) const { return find(tag) != -1; } + + template + bool Contains(TypedTag ttag, const ValueT& value) const { + for (const auto& param : data_) { + auto entry = authorizationValue(ttag, param); + if (entry.isOk() && entry.value() == value) return true; + } + return false; + } + /** + * Returns the number of \p tag entries. + */ + size_t GetTagCount(Tag tag) const; + + template + inline NullOr::type&> GetTagValue(T tag) const { + auto entry = GetEntry(tag); + if (entry.isOk()) return authorizationValue(tag, entry.value()); + return {}; + } + + void push_back(const KeyParameter& param) { data_.push_back(param); } + void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); } + + /** + * Append the tag and enumerated value to the set. + * "val" may be exactly one parameter unless a boolean parameter is added. + * In this case "val" is omitted. This condition is checked at compile time by Authorization() + */ + template + void push_back(TypedTagT tag, Value&&... val) { + push_back(Authorization(tag, std::forward(val)...)); + } + + template + void append(Iterator begin, Iterator end) { + while (begin != end) { + push_back(*begin); + ++begin; + } + } + + hidl_vec hidl_data() const { + hidl_vec result; + result.setToExternal(const_cast(data()), size()); + return result; + } + + void Serialize(std::ostream* out) const; + void Deserialize(std::istream* in); + + private: + NullOr GetEntry(Tag tag) const; + + std::vector data_; +}; + +class AuthorizationSetBuilder : public AuthorizationSet { + public: + template + AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) { + push_back(ttag, std::forward(value)...); + return *this; + } + + template + AuthorizationSetBuilder& Authorization(TypedTag ttag, const uint8_t* data, + size_t data_length) { + hidl_vec new_blob; + new_blob.setToExternal(const_cast(data), data_length); + push_back(ttag, std::move(new_blob)); + return *this; + } + + template + AuthorizationSetBuilder& Authorization(TypedTag ttag, const char* data, + size_t data_length) { + return Authorization(ttag, reinterpret_cast(data), data_length); + } + + AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& EcdsaKey(uint32_t key_size); + AuthorizationSetBuilder& AesKey(uint32_t key_size); + AuthorizationSetBuilder& HmacKey(uint32_t key_size); + + AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size); + AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size); + + AuthorizationSetBuilder& SigningKey(); + AuthorizationSetBuilder& EncryptionKey(); + AuthorizationSetBuilder& NoDigestOrPadding(); + AuthorizationSetBuilder& EcbMode(); + + AuthorizationSetBuilder& Digest(Digest digest) { return Authorization(TAG_DIGEST, digest); } + + AuthorizationSetBuilder& Padding(PaddingMode padding) { + return Authorization(TAG_PADDING, padding); + } +}; + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size, + uint64_t public_exponent) { + Authorization(TAG_ALGORITHM, Algorithm::RSA); + Authorization(TAG_KEY_SIZE, key_size); + Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent); + return *this; +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::EC); + Authorization(TAG_KEY_SIZE, key_size); + return *this; +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::AES); + return Authorization(TAG_KEY_SIZE, key_size); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::HMAC); + Authorization(TAG_KEY_SIZE, key_size); + return SigningKey(); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size, + uint64_t public_exponent) { + RsaKey(key_size, public_exponent); + return SigningKey(); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, + uint64_t public_exponent) { + RsaKey(key_size, public_exponent); + return EncryptionKey(); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) { + EcdsaKey(key_size); + return SigningKey(); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) { + AesKey(key_size); + return EncryptionKey(); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() { + Authorization(TAG_PURPOSE, KeyPurpose::SIGN); + return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() { + Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT); + return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() { + Authorization(TAG_DIGEST, Digest::NONE); + return Authorization(TAG_PADDING, PaddingMode::NONE); +} + +inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() { + return Authorization(TAG_BLOCK_MODE, BlockMode::ECB); +} + +} // namespace keystore + +#endif // SYSTEM_VOLD_AUTHORIZATION_SET_H_ diff --git a/keymaster_tags.h b/keymaster_tags.h new file mode 100644 index 0000000..c89354d --- /dev/null +++ b/keymaster_tags.h @@ -0,0 +1,372 @@ +/* + * Copyright 2014 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 SYSTEM_VOLD_KEYMASTER_TAGS_H_ +#define SYSTEM_VOLD_KEYMASTER_TAGS_H_ + +/** + * This header contains various definitions that make working with keymaster tags safer and easier. + * + * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose + * of making it impossible to make certain classes of mistakes when operating on keymaster + * authorizations. For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE + * and then to assign Algorithm::RSA to algorithm element of its union. But because the user + * must choose the union field, there could be a mismatch which the compiler has now way to + * diagnose. + * + * The machinery in this header solves these problems by describing which union field corresponds + * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a + * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG, + * we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal. + * + * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance + * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag + * to its value c++ type and the correct union element of KeyParameter. This is done by means of + * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping + * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a + * reference to the correct element of KeyParameter. + * E.g.: + * given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)" + * yields a reference to param.f.purpose + * If used in an assignment the compiler can now check the compatibility of the assigned value. + * + * For convenience we also provide the constructor like function Authorization(). + * Authorization takes a typed tag and a value and checks at compile time whether the value given + * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the + * given tag and value and returns it by value. + * + * The second convenience function, authorizationValue, allows access to the KeyParameter value in + * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped + * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped + * reference. + * E.g.: + * auto param = Authorization(TAG_ALGORITM, Algorithm::RSA); + * auto value1 = authorizationValue(TAG_PURPOSE, param); + * auto value2 = authorizationValue(TAG_ALGORITM, param); + * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access. + */ + +#include +#include +#include + +namespace keystore { + +using ::android::hardware::keymaster::V3_0::Algorithm; +using ::android::hardware::keymaster::V3_0::BlockMode; +using ::android::hardware::keymaster::V3_0::Digest; +using ::android::hardware::keymaster::V3_0::EcCurve; +using ::android::hardware::keymaster::V3_0::ErrorCode; +using ::android::hardware::keymaster::V3_0::HardwareAuthToken; +using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType; +using ::android::hardware::keymaster::V3_0::IKeymasterDevice; +using ::android::hardware::keymaster::V3_0::KeyBlobUsageRequirements; +using ::android::hardware::keymaster::V3_0::KeyCharacteristics; +using ::android::hardware::keymaster::V3_0::KeyDerivationFunction; +using ::android::hardware::keymaster::V3_0::KeyFormat; +using ::android::hardware::keymaster::V3_0::KeyOrigin; +using ::android::hardware::keymaster::V3_0::KeyParameter; +using ::android::hardware::keymaster::V3_0::KeyPurpose; +using ::android::hardware::keymaster::V3_0::PaddingMode; +using ::android::hardware::keymaster::V3_0::Tag; +using ::android::hardware::keymaster::V3_0::TagType; + +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; + +// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We +// need these old values to be able to support old keys that use them. +static const int32_t KM_TAG_DIGEST_OLD = static_cast(TagType::ENUM) | 5; +static const int32_t KM_TAG_PADDING_OLD = static_cast(TagType::ENUM) | 7; + +constexpr TagType typeFromTag(Tag tag) { + return static_cast(static_cast(tag) & static_cast(0xf0000000)); +} + +/** + * TypedTag is a templatized version of Tag, which provides compile-time checking of + * keymaster tag types. Instances are convertible to Tag, so they can be used wherever + * Tag is expected, and because they encode the tag type it's possible to create + * function overloads that only operate on tags with a particular type. + */ +template +struct TypedTag { + inline TypedTag() { + // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type + // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile + // error (no match for template specialization StaticAssert), with no run-time cost. + static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type"); + } + operator Tag() const { return tag; } +}; + +template +struct Tag2TypedTag { + typedef TypedTag type; +}; + +template +struct Tag2String; + +#define _TAGS_STRINGIFY(x) #x +#define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x) + +#define DECLARE_TYPED_TAG(name) \ + typedef typename Tag2TypedTag::type TAG_##name##_t; \ + extern TAG_##name##_t TAG_##name; \ + template <> \ + struct Tag2String { \ + static const char* value() { return "Tag::" TAGS_STRINGIFY(name); } \ + } + +DECLARE_TYPED_TAG(INVALID); +DECLARE_TYPED_TAG(KEY_SIZE); +DECLARE_TYPED_TAG(MAC_LENGTH); +DECLARE_TYPED_TAG(CALLER_NONCE); +DECLARE_TYPED_TAG(MIN_MAC_LENGTH); +DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT); +DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE); +DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID); +DECLARE_TYPED_TAG(ACTIVE_DATETIME); +DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME); +DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME); +DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS); +DECLARE_TYPED_TAG(MAX_USES_PER_BOOT); +DECLARE_TYPED_TAG(ALL_USERS); +DECLARE_TYPED_TAG(USER_ID); +DECLARE_TYPED_TAG(USER_SECURE_ID); +DECLARE_TYPED_TAG(NO_AUTH_REQUIRED); +DECLARE_TYPED_TAG(AUTH_TIMEOUT); +DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY); +DECLARE_TYPED_TAG(ALL_APPLICATIONS); +DECLARE_TYPED_TAG(APPLICATION_ID); +DECLARE_TYPED_TAG(APPLICATION_DATA); +DECLARE_TYPED_TAG(CREATION_DATETIME); +DECLARE_TYPED_TAG(ROLLBACK_RESISTANT); +DECLARE_TYPED_TAG(ROOT_OF_TRUST); +DECLARE_TYPED_TAG(ASSOCIATED_DATA); +DECLARE_TYPED_TAG(NONCE); +DECLARE_TYPED_TAG(AUTH_TOKEN); +DECLARE_TYPED_TAG(BOOTLOADER_ONLY); +DECLARE_TYPED_TAG(OS_VERSION); +DECLARE_TYPED_TAG(OS_PATCHLEVEL); +DECLARE_TYPED_TAG(UNIQUE_ID); +DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE); +DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID); +DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION); + +DECLARE_TYPED_TAG(PURPOSE); +DECLARE_TYPED_TAG(ALGORITHM); +DECLARE_TYPED_TAG(BLOCK_MODE); +DECLARE_TYPED_TAG(DIGEST); +DECLARE_TYPED_TAG(PADDING); +DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS); +DECLARE_TYPED_TAG(ORIGIN); +DECLARE_TYPED_TAG(USER_AUTH_TYPE); +DECLARE_TYPED_TAG(KDF); +DECLARE_TYPED_TAG(EC_CURVE); + +template +struct MetaList {}; + +using all_tags_t = MetaList< + TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t, + TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t, + TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, + TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t, + TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t, + TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, + TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, + TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, + TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t, + TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t, + TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>; + +/* implementation in keystore_utils.cpp */ +extern const char* stringifyTag(Tag tag); + +template +struct TypedTag2ValueType; + +#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \ + template \ + struct TypedTag2ValueType> { \ + typedef decltype(static_cast(nullptr)->field_name) type; \ + }; \ + template \ + inline auto accessTagValue(TypedTag, const KeyParameter& param) \ + ->const decltype(param.field_name)& { \ + return param.field_name; \ + } \ + template \ + inline auto accessTagValue(TypedTag, KeyParameter& param) \ + ->decltype(param.field_name)& { \ + return param.field_name; \ + } + +MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger) +MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger) +MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime) +MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer) +MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer) +MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue) +MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob) +MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob) + +#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \ + template <> \ + struct TypedTag2ValueType { \ + typedef decltype(static_cast(nullptr)->field_name) type; \ + }; \ + inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \ + ->const decltype(param.field_name)& { \ + return param.field_name; \ + } \ + inline auto accessTagValue(decltype(typed_tag), KeyParameter& param) \ + ->decltype(param.field_name)& { \ + return param.field_name; \ + } + +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType) + +template +inline KeyParameter makeKeyParameter(TypedTag ttag, ValueT&& value) { + KeyParameter param; + param.tag = tag; + param.f.longInteger = 0; + accessTagValue(ttag, param) = std::forward(value); + return param; +} + +// the boolean case +template +inline KeyParameter makeKeyParameter(TypedTag) { + KeyParameter param; + param.tag = tag; + param.f.boolValue = true; + return param; +} + +template +struct FirstOrNoneHelper; +template +struct FirstOrNoneHelper { + typedef First type; +}; +template <> +struct FirstOrNoneHelper<> { + struct type {}; +}; + +template +using FirstOrNone = typename FirstOrNoneHelper::type; + +template +inline KeyParameter Authorization(TypedTag ttag, Args&&... args) { + static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0), + "TagType::BOOL Authorizations do not take parameters. Presence is truth."); + static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1), + "Authorization other then TagType::BOOL take exactly one parameter."); + static_assert( + tag_type == TagType::BOOL || + std::is_convertible>>, + typename TypedTag2ValueType>::type>::value, + "Invalid argument type for given tag."); + + return makeKeyParameter(ttag, std::forward(args)...); +} + +/** + * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out + * of band. Note that if the wrapped value is a reference it is unsafe to access the value if + * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the + * wrapped value. In this case the pointer will be NULL though, and the value will be default + * constructed. + */ +template +class NullOr { + template + struct reference_initializer { + static T&& init() { return *static_cast*>(nullptr); } + }; + template + struct pointer_initializer { + static T init() { return nullptr; } + }; + template + struct value_initializer { + static T init() { return T(); } + }; + template + using initializer_t = std::conditional_t< + std::is_lvalue_reference::value, reference_initializer, + std::conditional_t::value, pointer_initializer, value_initializer>>; + + public: + NullOr() : value_(initializer_t::init()), null_(true) {} + NullOr(ValueT&& value) : value_(std::forward(value)), null_(false) {} + + bool isOk() const { return !null_; } + + const ValueT& value() const & { return value_; } + ValueT& value() & { return value_; } + ValueT&& value() && { return std::move(value_); } + + private: + ValueT value_; + bool null_; +}; + +template +std::remove_reference_t NullOrOr(T&& v) { + if (v.isOk()) return v; + return {}; +} + +template +std::remove_reference_t NullOrOr(Head&& head, Tail&&... tail) { + if (head.isOk()) return head; + return NullOrOr(std::forward(tail)...); +} + +template +std::remove_reference_t defaultOr(NullOr&& optional, Default&& def) { + static_assert( + std::is_convertible, std::remove_reference_t>::value, + "Type of default value must match the type wrapped by NullOr"); + if (optional.isOk()) return optional.value(); + return def; +} + +template +inline NullOr>::type&> authorizationValue( + TypedTag ttag, const KeyParameter& param) { + if (tag != param.tag) return {}; + return accessTagValue(ttag, param); +} + +} // namespace keystore + +#endif // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_ diff --git a/keystore_hidl_support.h b/keystore_hidl_support.h new file mode 100644 index 0000000..d21e02a --- /dev/null +++ b/keystore_hidl_support.h @@ -0,0 +1,108 @@ +/* + ** + ** Copyright 2016, 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 SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_ +#define SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_ + +#include +#include +#include + +#include + +#include "keymaster_tags.h" + +namespace keystore { + +inline static std::ostream& formatArgs(std::ostream& out) { + return out; +} + +template +inline static std::ostream& formatArgs(std::ostream& out, First&& first, Args&&... args) { + out << first; + return formatArgs(out, args...); +} + +template +inline static std::string argsToString(Args&&... args) { + std::stringstream s; + formatArgs(s, args...); + return s.str(); +} + +template +inline static ErrorCode ksHandleHidlError(const Return& error, Msgs&&... msgs) { + if (!error.isOk()) { + ALOGE("HIDL call failed with %s @ %s", error.description().c_str(), + argsToString(msgs...).c_str()); + return ErrorCode::UNKNOWN_ERROR; + } + return ErrorCode(error); +} +template +inline static ErrorCode ksHandleHidlError(const Return& error, Msgs&&... msgs) { + if (!error.isOk()) { + ALOGE("HIDL call failed with %s @ %s", error.description().c_str(), + argsToString(msgs...).c_str()); + return ErrorCode::UNKNOWN_ERROR; + } + return ErrorCode::OK; +} + +#define KS_HANDLE_HIDL_ERROR(rc) \ + ::keystore::ksHandleHidlError(rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__) + +inline static hidl_vec blob2hidlVec(const uint8_t* data, const size_t length, + bool inPlace = true) { + hidl_vec result; + if (inPlace) + result.setToExternal(const_cast(data), length); + else { + result.resize(length); + memcpy(&result[0], data, length); + } + return result; +} + +inline static hidl_vec blob2hidlVec(const std::string& value) { + hidl_vec result; + result.setToExternal( + reinterpret_cast(const_cast(value.data())), + static_cast(value.size())); + return result; +} + +inline static hidl_vec blob2hidlVec(const std::vector& blob) { + hidl_vec result; + result.setToExternal(const_cast(blob.data()), static_cast(blob.size())); + return result; +} + +template +inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) { + const uint8_t* value_ptr = reinterpret_cast(&value); + return std::copy(value_ptr, value_ptr + sizeof(value), dest); +} + +inline std::string hidlVec2String(const hidl_vec& value) { + return std::string(reinterpret_cast(&value[0]), value.size()); +} + +} // namespace keystore + +#endif // SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_ From a370c14f75e97e131b06662f6bdd4691c4bce0e9 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 17 Oct 2017 15:41:45 -0700 Subject: [PATCH 052/106] Add functions to handle idle maintenance runIdleMaint is equivalent with: 1. echo 1 > /sys/fs/f2fs/sdX/gc_urgent 2. wait until /sys/fs/f2fs/sdX/dirty_segments <= threshold or timeout 3. echo 0 > /sys/fs/f2fs/sdX/gc_urgent 4. fstrim abortIdleMaint forces the wait loop above to exit and skips fstrim. However, if fstrim is already running, abortIdleMaint will just leave it run to completion. Test: adb shell sm idle-maint [run|abort] Bug: 67776637 Change-Id: I4adff8d9b6bbd63bce41368cea55dc9e9b117eb6 --- IdleMaint.cpp | 196 +++++++++++++++++++++++++++++++++-- IdleMaint.h | 2 + VoldNativeService.cpp | 22 ++++ VoldNativeService.h | 4 + binder/android/os/IVold.aidl | 2 + model/PrivateVolume.h | 2 + 6 files changed, 220 insertions(+), 8 deletions(-) diff --git a/IdleMaint.cpp b/IdleMaint.cpp index ed6374f..62086cd 100644 --- a/IdleMaint.cpp +++ b/IdleMaint.cpp @@ -17,7 +17,12 @@ #include "IdleMaint.h" #include "Utils.h" #include "VolumeManager.h" +#include "model/PrivateVolume.h" +#include + +#include +#include #include #include #include @@ -31,26 +36,60 @@ #include #include +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 { -static const char* kWakeLock = "IdleMaint"; +enum class PathTypes { + kMountPoint = 1, + kBlkDevice, +}; -static void addFromVolumeManager(std::list* paths) { +enum class IdleMaintStats { + kStopped = 1, + kRunning, + kAbort, +}; + +static const char* kWakeLock = "IdleMaint"; +static const int DIRTY_SEGMENTS_THRESHOLD = 100; +static const int GC_TIMEOUT_SEC = 480; + +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* paths, + PathTypes path_type) { VolumeManager* vm = VolumeManager::Instance(); std::list privateIds; vm->listVolumes(VolumeBase::Type::kPrivate, privateIds); for (const auto& id : privateIds) { - auto vol = vm->findVolume(id); + PrivateVolume* vol = static_cast(vm->findVolume(id).get()); if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) { - paths->push_back(vol->getPath()); + 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* paths) { +static void addFromFstab(std::list* paths, PathTypes path_type) { std::unique_ptr fstab(fs_mgr_read_fstab_default(), fs_mgr_free_fstab); struct fstab_rec *prev_rec = NULL; @@ -79,7 +118,17 @@ static void addFromFstab(std::list* paths) { continue; } - paths->push_back(fstab->recs[i].mount_point); + 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]; } } @@ -89,8 +138,8 @@ void Trim(const android::sp& listener) { // Collect both fstab and vold volumes std::list paths; - addFromFstab(&paths); - addFromVolumeManager(&paths); + addFromFstab(&paths, PathTypes::kMountPoint); + addFromVolumeManager(&paths, PathTypes::kMountPoint); for (const auto& path : paths) { LOG(DEBUG) << "Starting trim of " << path; @@ -138,5 +187,136 @@ void Trim(const android::sp& listener) { release_wake_lock(kWakeLock); } +static bool waitForGc(const std::list& paths) { + std::unique_lock 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& paths) { + for (const auto& path : paths) { + LOG(DEBUG) << "Start GC on " << path; + if (!WriteStringToFile("1", path + "/gc_urgent")) { + PLOG(WARNING) << "Start GC failed on " << path; + } + } + return android::OK; +} + +static int stopGc(const std::list& 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; + } + } + return android::OK; +} + +int RunIdleMaint(const android::sp& listener) { + std::unique_lock 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 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); + } + + 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& listener) { + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); + + std::unique_lock 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 diff --git a/IdleMaint.h b/IdleMaint.h index 38dadfb..e043db4 100644 --- a/IdleMaint.h +++ b/IdleMaint.h @@ -23,6 +23,8 @@ namespace android { namespace vold { void Trim(const android::sp& listener); +int RunIdleMaint(const android::sp& listener); +int AbortIdleMaint(const android::sp& listener); } // namespace vold } // namespace android diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index d7a6576..e8e151f 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -481,6 +481,28 @@ binder::Status VoldNativeService::fstrim(int32_t fstrimFlags, return ok(); } +binder::Status VoldNativeService::runIdleMaint( + const android::sp& listener) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_LOCK; + + std::thread([=]() { + android::vold::RunIdleMaint(listener); + }).detach(); + return ok(); +} + +binder::Status VoldNativeService::abortIdleMaint( + const android::sp& 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); diff --git a/VoldNativeService.h b/VoldNativeService.h index 7ca72e5..d107138 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -66,6 +66,10 @@ public: binder::Status fstrim(int32_t fstrimFlags, const android::sp& listener); + binder::Status runIdleMaint( + const android::sp& listener); + binder::Status abortIdleMaint( + const android::sp& listener); binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId, android::base::unique_fd* _aidl_return); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 5d182c9..c3f5029 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -54,6 +54,8 @@ interface IVold { 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); diff --git a/model/PrivateVolume.h b/model/PrivateVolume.h index 95b718d..9508671 100644 --- a/model/PrivateVolume.h +++ b/model/PrivateVolume.h @@ -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; From c7c477b8fbadd30bec94b1f9c12f7fc44aed38d6 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 13 Nov 2017 17:38:39 -0800 Subject: [PATCH 053/106] Vold: format f2fs partition This patch formats f2fs paritition with proper flags. Change-Id: Ie5ded1f2ceb3869771b2eaf9bea3b0966cab18c5 Signed-off-by: Jaegeuk Kim --- fs/F2fs.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp index 0d12b07..56369d5 100644 --- a/fs/F2fs.cpp +++ b/fs/F2fs.cpp @@ -18,7 +18,9 @@ #include "Utils.h" #include +#include #include +#include #include #include @@ -72,8 +74,19 @@ status_t Mount(const std::string& source, const std::string& target) { status_t Format(const std::string& source) { std::vector 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(source); return ForkExecvp(cmd); } From a838863d77c68752a9b96894a487ac2c86907246 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Sat, 25 Nov 2017 08:47:19 -0800 Subject: [PATCH 054/106] Export AIDL files as a filegroup for framework.jar Put AIDL files into a filegroup so they can be imported as sources for framework.jar. Bug: 69917341 Test: m checkbuild Change-Id: I22e765ccf88832b1b192b42b2161898d9a6e5b2c --- Android.bp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Android.bp b/Android.bp index 5941cd9..db761e4 100644 --- a/Android.bp +++ b/Android.bp @@ -65,9 +65,7 @@ cc_library_static { defaults: ["vold_default_flags"], srcs: [ - "binder/android/os/IVold.aidl", - "binder/android/os/IVoldListener.aidl", - "binder/android/os/IVoldTaskListener.aidl", + ":vold_aidl", ], shared_libs: [ "libbinder", @@ -187,4 +185,13 @@ cc_binary { ], } +filegroup { + name: "vold_aidl", + srcs: [ + "binder/android/os/IVold.aidl", + "binder/android/os/IVoldListener.aidl", + "binder/android/os/IVoldTaskListener.aidl", + ], +} + subdirs = ["tests"] From aedae617fec702add64201534a2f514fa31c5965 Mon Sep 17 00:00:00 2001 From: Risan Date: Mon, 27 Nov 2017 18:01:35 +0900 Subject: [PATCH 055/106] [Vold] Conditional dependency to ARC++ ObbVolume Test: Compile Change-Id: Ic6348f7816b28302d45c05a359548a5d034fde24 Bug: 64500663 --- Android.bp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Android.bp b/Android.bp index 5941cd9..0377beb 100644 --- a/Android.bp +++ b/Android.bp @@ -80,6 +80,11 @@ cc_library_static { }, } +cc_library_headers { + name: "libvold_headers", + export_include_dirs: ["."], +} + // Static library factored out to support testing cc_library_static { name: "libvold", @@ -123,6 +128,16 @@ cc_library_static { "model/VolumeBase.cpp", "secontext.cpp", ], + product_variables: { + arc: { + exclude_srcs: [ + "model/ObbVolume.cpp", + ], + static_libs: [ + "libarcobbvolume", + ], + }, + }, } cc_binary { @@ -134,6 +149,13 @@ cc_binary { srcs: ["main.cpp"], static_libs: ["libvold"], + product_variables: { + arc: { + static_libs: [ + "libarcobbvolume", + ] + }, + }, init_rc: ["vold.rc"], required: [ From 5afbc6276daf9c4b1730b62a5fd5a85bcb7eac20 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 27 Nov 2017 09:42:17 -0800 Subject: [PATCH 056/106] No double encryption on FDE+FBE SD cards On FBE systems, adoptable storage uses both file-based encryption (for per-user protection) and full disk encryption (for metadata protection). For performance/battery reasons, we don't want to encrypt the same data twice; to that end, ensure that the allow_encrypt_override flag is sent to dm_crypt. Bug: 25861755 Test: see ag/3247969 Change-Id: Ib0c5891ab2d2ee9007e27a50254d29fc867d7bc5 --- cryptfs.cpp | 140 ++++++++++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 64 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index af7fda3..207f08c 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -96,6 +96,8 @@ extern "C" { #define RETRY_MOUNT_ATTEMPTS 10 #define RETRY_MOUNT_DELAY_SECONDS 1 +#define CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE (1) + static int put_crypt_ftr_and_key(struct crypt_mnt_ftr* crypt_ftr); static unsigned char saved_master_key[KEY_LEN_BYTES]; @@ -864,6 +866,7 @@ static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii); buff_offset = crypt_params - buffer; + SLOGI("Extra parameters for dm_crypt: %s\n", extra_params); snprintf(crypt_params, sizeof(buffer) - buff_offset, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name, master_key_ascii, real_blk_name, extra_params); @@ -919,71 +922,80 @@ static int get_dm_crypt_version(int fd, const char *name, int *version) return -1; } -static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, - const unsigned char *master_key, const char *real_blk_name, - char *crypto_blk_name, const char *name) { - char buffer[DM_CRYPT_BUF_SIZE]; - struct dm_ioctl *io; - unsigned int minor; - int fd=0; - int err; - int retval = -1; - int version[3]; - const char *extra_params; - int load_count; +static std::string extra_params_as_string(const std::vector& extra_params_vec) { + if (extra_params_vec.empty()) return ""; + std::string extra_params = std::to_string(extra_params_vec.size()); + for (const auto& p : extra_params_vec) { + extra_params.append(" "); + extra_params.append(p); + } + return extra_params; +} - if ((fd = open("/dev/device-mapper", O_RDWR|O_CLOEXEC)) < 0 ) { - SLOGE("Cannot open device-mapper\n"); - goto errout; - } +static int create_crypto_blk_dev(struct crypt_mnt_ftr* crypt_ftr, const unsigned char* master_key, + const char* real_blk_name, char* crypto_blk_name, const char* name, + uint32_t flags) { + char buffer[DM_CRYPT_BUF_SIZE]; + struct dm_ioctl* io; + unsigned int minor; + int fd = 0; + int err; + int retval = -1; + int version[3]; + int load_count; + std::vector extra_params_vec; - io = (struct dm_ioctl *) buffer; + if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) { + SLOGE("Cannot open device-mapper\n"); + goto errout; + } - ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); - err = ioctl(fd, DM_DEV_CREATE, io); - if (err) { - SLOGE("Cannot create dm-crypt device %s: %s\n", name, strerror(errno)); - goto errout; - } + io = (struct dm_ioctl*)buffer; - /* Get the device status, in particular, the name of it's device file */ - ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); - if (ioctl(fd, DM_DEV_STATUS, io)) { - SLOGE("Cannot retrieve dm-crypt device status\n"); - goto errout; - } - minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00); - snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor); + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + err = ioctl(fd, DM_DEV_CREATE, io); + if (err) { + SLOGE("Cannot create dm-crypt device %s: %s\n", name, strerror(errno)); + goto errout; + } - extra_params = ""; - if (! get_dm_crypt_version(fd, name, version)) { - /* Support for allow_discards was added in version 1.11.0 */ - if ((version[0] >= 2) || - ((version[0] == 1) && (version[1] >= 11))) { - extra_params = "1 allow_discards"; - SLOGI("Enabling support for allow_discards in dmcrypt.\n"); - } - } + /* Get the device status, in particular, the name of it's device file */ + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + if (ioctl(fd, DM_DEV_STATUS, io)) { + SLOGE("Cannot retrieve dm-crypt device status\n"); + goto errout; + } + minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00); + snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor); - load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name, - fd, extra_params); - if (load_count < 0) { - SLOGE("Cannot load dm-crypt mapping table.\n"); - goto errout; - } else if (load_count > 1) { - SLOGI("Took %d tries to load dmcrypt table.\n", load_count); - } + if (!get_dm_crypt_version(fd, name, version)) { + /* Support for allow_discards was added in version 1.11.0 */ + if ((version[0] >= 2) || ((version[0] == 1) && (version[1] >= 11))) { + extra_params_vec.emplace_back("allow_discards"); + } + } + if (flags & CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE) { + extra_params_vec.emplace_back("allow_encrypt_override"); + } + load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name, fd, + extra_params_as_string(extra_params_vec).c_str()); + if (load_count < 0) { + SLOGE("Cannot load dm-crypt mapping table.\n"); + goto errout; + } else if (load_count > 1) { + SLOGI("Took %d tries to load dmcrypt table.\n", load_count); + } - /* Resume this device to activate it */ - ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + /* Resume this device to activate it */ + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); - if (ioctl(fd, DM_DEV_SUSPEND, io)) { - SLOGE("Cannot resume the dm-crypt device\n"); - goto errout; - } + if (ioctl(fd, DM_DEV_SUSPEND, io)) { + SLOGE("Cannot resume the dm-crypt device\n"); + goto errout; + } - /* We made it here with no errors. Woot! */ - retval = 0; + /* We made it here with no errors. Woot! */ + retval = 0; errout: close(fd); /* If fd is <0 from a failed open call, it's safe to just ignore the close error */ @@ -1612,11 +1624,10 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, // Create crypto block device - all (non fatal) code paths // need it - if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, - real_blkdev, crypto_blkdev, label)) { - SLOGE("Error creating decrypted block device\n"); - rc = -1; - goto errout; + if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev, label, 0)) { + SLOGE("Error creating decrypted block device\n"); + rc = -1; + goto errout; } /* Work out if the problem is the password or the data */ @@ -1744,8 +1755,9 @@ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, strlcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN); - return create_crypto_blk_dev(&ext_crypt_ftr, key, real_blkdev, - out_crypto_blkdev, label); + return create_crypto_blk_dev( + &ext_crypt_ftr, key, real_blkdev, out_crypto_blkdev, label, + e4crypt_is_native() ? CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE : 0); } /* @@ -2313,7 +2325,7 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0); create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev, - CRYPTO_BLOCK_DEVICE); + CRYPTO_BLOCK_DEVICE, 0); /* If we are continuing, check checksums match */ rc = 0; From 401b2603516a64d3ee7804e270c966828e6b454a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 14 Dec 2017 22:15:20 -0700 Subject: [PATCH 057/106] Delay touching disks when secure keyguard showing. We've tried our best to protect against malicious storage devices with limited SELinux domains, but let's be even more paranoid and refuse to look at disks inserted while a secure keyguard is showing. We'll gladly scan them right away once the user confirms their credentials. Test: builds, boots, manual testing Bug: 68054513 Change-Id: I37fd6c25bbd6631fa4ba3f84e19384d746a22498 --- VoldNativeService.cpp | 7 +++ VoldNativeService.h | 2 + VolumeManager.cpp | 97 +++++++++++++++++++++++++----------- VolumeManager.h | 8 +++ binder/android/os/IVold.aidl | 2 + 5 files changed, 87 insertions(+), 29 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index e8e151f..9d8b990 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -285,6 +285,13 @@ binder::Status VoldNativeService::onUserStopped(int32_t userId) { 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); diff --git a/VoldNativeService.h b/VoldNativeService.h index d107138..1359d90 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -43,6 +43,8 @@ public: 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); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index e078c0d..0936ed0 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -90,6 +90,9 @@ VolumeManager *VolumeManager::Instance() { VolumeManager::VolumeManager() { mDebug = false; mNextObbId = 0; + // For security reasons, assume that a secure keyguard is + // showing until we hear otherwise + mSecureKeyguardShowing = true; } VolumeManager::~VolumeManager() { @@ -116,23 +119,13 @@ int VolumeManager::updateVirtualDisk() { auto disk = new android::vold::Disk("virtual", buf.st_rdev, "virtual", android::vold::Disk::Flags::kAdoptable | android::vold::Disk::Flags::kSd); - disk->create(); mVirtualDisk = std::shared_ptr(disk); - mDisks.push_back(mVirtualDisk); + handleDiskAdded(mVirtualDisk); } } else { if (mVirtualDisk != nullptr) { dev_t device = mVirtualDisk->getDevice(); - - auto i = mDisks.begin(); - while (i != mDisks.end()) { - if ((*i)->getDevice() == device) { - (*i)->destroy(); - i = mDisks.erase(i); - } else { - ++i; - } - } + handleDiskRemoved(device); Loop::destroyByDevice(mVirtualDiskPath.c_str()); mVirtualDisk = nullptr; @@ -217,8 +210,7 @@ void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { auto disk = new android::vold::Disk(eventPath, device, source->getNickname(), flags); - disk->create(); - mDisks.push_back(std::shared_ptr(disk)); + handleDiskAdded(std::shared_ptr(disk)); break; } } @@ -226,24 +218,11 @@ void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { } case NetlinkEvent::Action::kChange: { LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed"; - for (const auto& disk : mDisks) { - if (disk->getDevice() == device) { - disk->readMetadata(); - disk->readPartitions(); - } - } + handleDiskChanged(device); break; } case NetlinkEvent::Action::kRemove: { - auto i = mDisks.begin(); - while (i != mDisks.end()) { - if ((*i)->getDevice() == device) { - (*i)->destroy(); - i = mDisks.erase(i); - } else { - ++i; - } - } + handleDiskRemoved(device); break; } default: { @@ -253,6 +232,51 @@ void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { } } +void VolumeManager::handleDiskAdded(const std::shared_ptr& disk) { + // For security reasons, if secure keyguard is showing, wait + // until the user unlocks the device to actually touch it + if (mSecureKeyguardShowing) { + LOG(INFO) << "Found disk at " << disk->getEventPath() + << " but delaying scan due to secure keyguard"; + mPendingDisks.push_back(disk); + } else { + disk->create(); + mDisks.push_back(disk); + } +} + +void VolumeManager::handleDiskChanged(dev_t device) { + for (const auto& disk : mDisks) { + if (disk->getDevice() == device) { + disk->readMetadata(); + disk->readPartitions(); + } + } + + // For security reasons, we ignore all pending disks, since + // we'll scan them once the device is unlocked +} + +void VolumeManager::handleDiskRemoved(dev_t device) { + auto i = mDisks.begin(); + while (i != mDisks.end()) { + if ((*i)->getDevice() == device) { + (*i)->destroy(); + i = mDisks.erase(i); + } else { + ++i; + } + } + auto j = mPendingDisks.begin(); + while (j != mPendingDisks.end()) { + if ((*j)->getDevice() == device) { + j = mPendingDisks.erase(j); + } else { + ++j; + } + } +} + void VolumeManager::addDiskSource(const std::shared_ptr& diskSource) { std::lock_guard lock(mLock); mDiskSources.push_back(diskSource); @@ -367,6 +391,20 @@ int VolumeManager::onUserStopped(userid_t userId) { return 0; } +int VolumeManager::onSecureKeyguardStateChanged(bool isShowing) { + mSecureKeyguardShowing = isShowing; + if (!mSecureKeyguardShowing) { + // Now that secure keyguard has been dismissed, process + // any pending disks + for (const auto& disk : mPendingDisks) { + disk->create(); + mDisks.push_back(disk); + } + mPendingDisks.clear(); + } + return 0; +} + int VolumeManager::setPrimary(const std::shared_ptr& vol) { mPrimary = vol; for (userid_t userId : mStartedUsers) { @@ -554,6 +592,7 @@ int VolumeManager::shutdown() { disk->destroy(); } mDisks.clear(); + mPendingDisks.clear(); android::vold::sSleepOnUnmount = true; return 0; } diff --git a/VolumeManager.h b/VolumeManager.h index 5baa7ce..fb455d8 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -94,6 +94,8 @@ public: int onUserStarted(userid_t userId); int onUserStopped(userid_t userId); + int onSecureKeyguardStateChanged(bool isShowing); + int setPrimary(const std::shared_ptr& vol); int remountUid(uid_t uid, const std::string& mode); @@ -132,6 +134,10 @@ private: int linkPrimary(userid_t userId); + void handleDiskAdded(const std::shared_ptr& disk); + void handleDiskChanged(dev_t device); + void handleDiskRemoved(dev_t device); + std::mutex mLock; std::mutex mCryptLock; @@ -139,6 +145,7 @@ private: std::list> mDiskSources; std::list> mDisks; + std::list> mPendingDisks; std::list> mObbVolumes; std::unordered_map mAddedUsers; @@ -150,6 +157,7 @@ private: std::shared_ptr mPrimary; int mNextObbId; + bool mSecureKeyguardShowing; }; #endif diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index c3f5029..d073be2 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -33,6 +33,8 @@ interface IVold { 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); From 32a5b9aed304e6619248cb58727e8b29d61d3b1c Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 20 Dec 2017 12:38:47 -0800 Subject: [PATCH 058/106] StartsWith now allows std::string prefixes. Bug: N/A Test: builds Change-Id: I2e24632e95f2bf929c2c000152c5c4076d53186e --- Process.cpp | 4 ++-- VolumeManager.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Process.cpp b/Process.cpp index 042ba2d..9038af2 100644 --- a/Process.cpp +++ b/Process.cpp @@ -52,7 +52,7 @@ static bool checkMaps(const std::string& path, const std::string& prefix) { std::string::size_type pos = line.find('/'); if (pos != std::string::npos) { line = line.substr(pos); - if (android::base::StartsWith(line, prefix.c_str())) { + if (android::base::StartsWith(line, prefix)) { LOG(WARNING) << "Found map " << path << " referencing " << line; found = true; } @@ -64,7 +64,7 @@ static bool checkMaps(const std::string& path, const std::string& prefix) { 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.c_str())) { + if (android::base::StartsWith(res, prefix)) { LOG(WARNING) << "Found symlink " << path << " referencing " << res; return true; } diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 0936ed0..5e6e74f 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -426,7 +426,7 @@ static int unmount_tree(const std::string& prefix) { mntent* mentry; while ((mentry = getmntent(fp)) != NULL) { auto test = std::string(mentry->mnt_dir) + "/"; - if (android::base::StartsWith(test, prefix.c_str())) { + if (android::base::StartsWith(test, prefix)) { toUnmount.push_front(test); } } From 7ee87cfcbef114ef50e15f3f6770cee0fe61890a Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Fri, 22 Dec 2017 10:12:06 -0800 Subject: [PATCH 059/106] Remove all references to FDE enable wipe Bug: 64766105 Test: FBE boots, forceencrypt boots, set pattern, reboots, encryptable boots and can be encrypted Change-Id: I8c6dc0acdc37c3a6f1bea28d5607ed8938a4eb0c --- VoldNativeService.cpp | 17 +-- binder/android/os/IVold.aidl | 2 - cryptfs.cpp | 214 ++++++++--------------------------- cryptfs.h | 4 +- vdc.cpp | 3 +- vdc.rc | 2 +- 6 files changed, 55 insertions(+), 187 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 9d8b990..f7637fd 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -554,22 +554,12 @@ static int fdeEnableInternal(int32_t passwordType, const std::string& password, int32_t encryptionFlags) { bool noUi = (encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_NO_UI) != 0; - std::string how; - if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_IN_PLACE) != 0) { - how = "inplace"; - } else if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_WIPE) != 0) { - how = "wipe"; - } else { - LOG(ERROR) << "Missing encryption flag"; - return -1; - } - for (int tries = 0; tries < 2; ++tries) { int rc; if (passwordType == VoldNativeService::PASSWORD_TYPE_DEFAULT) { - rc = cryptfs_enable_default(how.c_str(), noUi); + rc = cryptfs_enable_default(noUi); } else { - rc = cryptfs_enable(how.c_str(), passwordType, password.c_str(), noUi); + rc = cryptfs_enable(passwordType, password.c_str(), noUi); } if (rc == 0) { @@ -591,9 +581,6 @@ binder::Status VoldNativeService::fdeEnable(int32_t passwordType, if (passwordType != PASSWORD_TYPE_DEFAULT) { return error("Unexpected password type"); } - if (encryptionFlags != (ENCRYPTION_FLAG_IN_PLACE | ENCRYPTION_FLAG_NO_UI)) { - return error("Unexpected flags"); - } return translateBool(e4crypt_enable_crypto()); } diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index d073be2..9facaf7 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -94,8 +94,6 @@ interface IVold { void secdiscard(@utf8InCpp String path); - const int ENCRYPTION_FLAG_WIPE = 1; - const int ENCRYPTION_FLAG_IN_PLACE = 2; const int ENCRYPTION_FLAG_NO_UI = 4; const int ENCRYPTION_STATE_NONE = 1; diff --git a/cryptfs.cpp b/cryptfs.cpp index af7fda3..427772c 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1925,73 +1925,6 @@ static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr) return 0; } -static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type) -{ - const char *args[10]; - char size_str[32]; /* Must be large enough to hold a %lld and null byte */ - int num_args; - int status; - int tmp; - int rc = -1; - - if (type == EXT4_FS) { - args[0] = "/system/bin/mke2fs"; - args[1] = "-M"; - args[2] = "/data"; - args[3] = "-b"; - args[4] = "4096"; - args[5] = "-t"; - args[6] = "ext4"; - args[7] = crypto_blkdev; - snprintf(size_str, sizeof(size_str), "%" PRId64, size / (4096 / 512)); - args[8] = size_str; - num_args = 9; - SLOGI("Making empty filesystem with command %s %s %s %s %s %s\n", - args[0], args[1], args[2], args[3], args[4], args[5]); - } else if (type == F2FS_FS) { - args[0] = "/system/bin/make_f2fs"; - args[1] = "-f"; - args[2] = "-d1"; - args[3] = "-O"; - args[4] = "encrypt"; - args[5] = "-O"; - args[6] = "quota"; - args[7] = crypto_blkdev; - snprintf(size_str, sizeof(size_str), "%" PRId64, size); - args[8] = size_str; - num_args = 9; - SLOGI("Making empty filesystem with command %s %s %s %s %s %s %s %s %s\n", - args[0], args[1], args[2], args[3], args[4], args[5], - args[6], args[7], args[8]); - } else { - SLOGE("cryptfs_enable_wipe(): unknown filesystem type %d\n", type); - return -1; - } - - tmp = android_fork_execvp(num_args, (char **)args, &status, false, true); - - if (tmp != 0) { - SLOGE("Error creating empty filesystem on %s due to logwrap error\n", crypto_blkdev); - } else { - if (WIFEXITED(status)) { - if (WEXITSTATUS(status)) { - SLOGE("Error creating filesystem on %s, exit status %d ", - crypto_blkdev, WEXITSTATUS(status)); - } else { - SLOGD("Successfully created filesystem on %s\n", crypto_blkdev); - rc = 0; - } - } else { - SLOGE("Error creating filesystem on %s, did not exit normally\n", crypto_blkdev); - } - } - - return rc; -} - -#define CRYPTO_ENABLE_WIPE 1 -#define CRYPTO_ENABLE_INPLACE 2 - #define FRAMEWORK_BOOT_WAIT 60 static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf) @@ -2020,60 +1953,31 @@ static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf) return 0; } -static int get_fs_type(struct fstab_rec *rec) -{ - if (!strcmp(rec->fs_type, "ext4")) { - return EXT4_FS; - } else if (!strcmp(rec->fs_type, "f2fs")) { - return F2FS_FS; - } else { - return -1; - } -} - -static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how, - char *crypto_blkdev, char *real_blkdev, - int previously_encrypted_upto) -{ +static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr* crypt_ftr, char* crypto_blkdev, + char* real_blkdev, int previously_encrypted_upto) { off64_t cur_encryption_done=0, tot_encryption_size=0; int rc = -1; /* The size of the userdata partition, and add in the vold volumes below */ tot_encryption_size = crypt_ftr->fs_size; - if (how == CRYPTO_ENABLE_WIPE) { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT); - int fs_type = get_fs_type(rec); - if (fs_type < 0) { - SLOGE("cryptfs_enable: unsupported fs type %s\n", rec->fs_type); - return -1; - } - rc = cryptfs_enable_wipe(crypto_blkdev, crypt_ftr->fs_size, fs_type); - } else if (how == CRYPTO_ENABLE_INPLACE) { - rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, - crypt_ftr->fs_size, &cur_encryption_done, - tot_encryption_size, - previously_encrypted_upto); + rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, crypt_ftr->fs_size, &cur_encryption_done, + tot_encryption_size, previously_encrypted_upto); - if (rc == ENABLE_INPLACE_ERR_DEV) { - /* Hack for b/17898962 */ - SLOGE("cryptfs_enable: crypto block dev failure. Must reboot...\n"); - cryptfs_reboot(RebootType::reboot); - } + if (rc == ENABLE_INPLACE_ERR_DEV) { + /* Hack for b/17898962 */ + SLOGE("cryptfs_enable: crypto block dev failure. Must reboot...\n"); + cryptfs_reboot(RebootType::reboot); + } - if (!rc) { - crypt_ftr->encrypted_upto = cur_encryption_done; - } + if (!rc) { + crypt_ftr->encrypted_upto = cur_encryption_done; + } - if (!rc && crypt_ftr->encrypted_upto == crypt_ftr->fs_size) { - /* The inplace routine never actually sets the progress to 100% due - * to the round down nature of integer division, so set it here */ - property_set("vold.encrypt_progress", "100"); - } - } else { - /* Shouldn't happen */ - SLOGE("cryptfs_enable: internal error, unknown option\n"); - rc = -1; + if (!rc && crypt_ftr->encrypted_upto == crypt_ftr->fs_size) { + /* The inplace routine never actually sets the progress to 100% due + * to the round down nature of integer division, so set it here */ + property_set("vold.encrypt_progress", "100"); } return rc; @@ -2084,10 +1988,7 @@ static int vold_unmountAll(void) { return vm->unmountAll(); } -int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *passwd, - int no_ui) -{ - int how = 0; +int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN]; unsigned char decrypted_master_key[KEY_LEN_BYTES]; int rc=-1, i; @@ -2102,17 +2003,7 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass bool onlyCreateHeader = false; int fd = -1; - if (!strcmp(howarg, "wipe")) { - how = CRYPTO_ENABLE_WIPE; - } else if (! strcmp(howarg, "inplace")) { - how = CRYPTO_ENABLE_INPLACE; - } else { - /* Shouldn't happen, as CommandListener vets the args */ - goto error_unencrypted; - } - - if (how == CRYPTO_ENABLE_INPLACE - && get_crypt_ftr_and_key(&crypt_ftr) == 0) { + if (get_crypt_ftr_and_key(&crypt_ftr) == 0) { if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) { /* An encryption was underway and was interrupted */ previously_encrypted_upto = crypt_ftr.encrypted_upto; @@ -2165,7 +2056,7 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass close(fd); /* If doing inplace encryption, make sure the orig fs doesn't include the crypto footer */ - if ((how == CRYPTO_ENABLE_INPLACE) && (!strcmp(key_loc, KEY_IN_FOOTER))) { + if (!strcmp(key_loc, KEY_IN_FOOTER)) { unsigned int fs_size_sec, max_fs_size_sec; fs_size_sec = get_fs_size(real_blkdev); if (fs_size_sec == 0) @@ -2212,7 +2103,7 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass } /* Do extra work for a better UX when doing the long inplace encryption */ - if (how == CRYPTO_ENABLE_INPLACE && !onlyCreateHeader) { + if (!onlyCreateHeader) { /* Now that /data is unmounted, we need to mount a tmpfs * /data, set a property saying we're doing inplace encryption, * and restart the framework. @@ -2299,7 +2190,7 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass cryptfs_reboot(RebootType::reboot); } - if (how == CRYPTO_ENABLE_INPLACE && (!no_ui || rebootEncryption)) { + if (!no_ui || rebootEncryption) { /* startup service classes main and late_start */ property_set("vold.decrypt", "trigger_restart_min_framework"); SLOGD("Just triggered restart_min_framework\n"); @@ -2329,14 +2220,12 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass } if (!rc) { - rc = cryptfs_enable_all_volumes(&crypt_ftr, how, - crypto_blkdev, real_blkdev, + rc = cryptfs_enable_all_volumes(&crypt_ftr, crypto_blkdev, real_blkdev, previously_encrypted_upto); } /* Calculate checksum if we are not finished */ - if (!rc && how == CRYPTO_ENABLE_INPLACE - && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) { + if (!rc && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) { rc = cryptfs_SHA256_fileblock(crypto_blkdev, crypt_ftr.hash_first_block); if (rc) { @@ -2352,8 +2241,7 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass /* Success */ crypt_ftr.flags &= ~CRYPT_INCONSISTENT_STATE; - if (how == CRYPTO_ENABLE_INPLACE - && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) { + if (crypt_ftr.encrypted_upto != crypt_ftr.fs_size) { SLOGD("Encrypted up to sector %lld - will continue after reboot", crypt_ftr.encrypted_upto); crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS; @@ -2361,30 +2249,29 @@ int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *pass put_crypt_ftr_and_key(&crypt_ftr); - if (how == CRYPTO_ENABLE_WIPE - || crypt_ftr.encrypted_upto == crypt_ftr.fs_size) { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.crypto.state", value, ""); - if (!strcmp(value, "")) { - /* default encryption - continue first boot sequence */ - property_set("ro.crypto.state", "encrypted"); - property_set("ro.crypto.type", "block"); - release_wake_lock(lockid); - if (rebootEncryption && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) { - // Bring up cryptkeeper that will check the password and set it - property_set("vold.decrypt", "trigger_shutdown_framework"); - sleep(2); - property_set("vold.encrypt_progress", ""); - cryptfs_trigger_restart_min_framework(); + if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.crypto.state", value, ""); + if (!strcmp(value, "")) { + /* default encryption - continue first boot sequence */ + property_set("ro.crypto.state", "encrypted"); + property_set("ro.crypto.type", "block"); + release_wake_lock(lockid); + if (rebootEncryption && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) { + // Bring up cryptkeeper that will check the password and set it + property_set("vold.decrypt", "trigger_shutdown_framework"); + sleep(2); + property_set("vold.encrypt_progress", ""); + cryptfs_trigger_restart_min_framework(); + } else { + cryptfs_check_passwd(DEFAULT_PASSWORD); + cryptfs_restart_internal(1); + } + return 0; } else { - cryptfs_check_passwd(DEFAULT_PASSWORD); - cryptfs_restart_internal(1); + sleep(2); /* Give the UI a chance to show 100% progress */ + cryptfs_reboot(RebootType::reboot); } - return 0; - } else { - sleep(2); /* Give the UI a chance to show 100% progress */ - cryptfs_reboot(RebootType::reboot); - } } else { sleep(2); /* Partially encrypted, ensure writes flushed to ssd */ cryptfs_reboot(RebootType::shutdown); @@ -2443,15 +2330,12 @@ error_shutting_down: return -1; } -int cryptfs_enable(const char *howarg, int type, const char *passwd, int no_ui) -{ - return cryptfs_enable_internal(howarg, type, passwd, no_ui); +int cryptfs_enable(int type, const char* passwd, int no_ui) { + return cryptfs_enable_internal(type, passwd, no_ui); } -int cryptfs_enable_default(const char *howarg, int no_ui) -{ - return cryptfs_enable_internal(howarg, CRYPT_TYPE_DEFAULT, - DEFAULT_PASSWORD, no_ui); +int cryptfs_enable_default(int no_ui) { + return cryptfs_enable_internal(CRYPT_TYPE_DEFAULT, DEFAULT_PASSWORD, no_ui); } int cryptfs_changepw(int crypt_type, const char *newpw) diff --git a/cryptfs.h b/cryptfs.h index 767270f..bf4b405 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -231,9 +231,9 @@ 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(const char* flag, int type, const char* passwd, int no_ui); +int cryptfs_enable(int type, const char* passwd, int no_ui); int cryptfs_changepw(int type, const char* newpw); -int cryptfs_enable_default(const char* flag, int no_ui); +int cryptfs_enable_default(int no_ui); int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const unsigned char* key, int keysize, char* out_crypto_blkdev); int cryptfs_revert_ext_volume(const char* label); diff --git a/vdc.cpp b/vdc.cpp index 19eb379..5ae4cd9 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -93,8 +93,7 @@ int main(int argc, char** argv) { 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_IN_PLACE - | android::os::IVold::ENCRYPTION_FLAG_NO_UI; + 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()); diff --git a/vdc.rc b/vdc.rc index 4d51ced..f2a8076 100644 --- a/vdc.rc +++ b/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) From 8c24ae7c47efa9e0a504dd97e54e9a2ccc972aff Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 4 Jan 2018 16:46:34 -0700 Subject: [PATCH 060/106] FBE devices now fully support adoptable storage. We've finished all the underlying work to support adoptable storage on FBE devices, so remove the code that was disabling it by default. To aid debugging, support blocking move commands (so that we log the stdout) via a system property, so we don't have to recompile end user devices stuck in funky states. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Bug: 29923055, 25861755, 33252673, 37289651 Change-Id: I6b781de7e196a1a50ba543843aca0caf74c3e282 --- MoveStorage.cpp | 23 ++++++++++++----------- model/Disk.cpp | 6 ------ 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/MoveStorage.cpp b/MoveStorage.cpp index 4f5ebe8..4624026 100644 --- a/MoveStorage.cpp +++ b/MoveStorage.cpp @@ -18,10 +18,11 @@ #include "Utils.h" #include "VolumeManager.h" -#include #include -#include +#include +#include #include +#include #include @@ -30,7 +31,7 @@ #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; @@ -93,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; @@ -116,7 +118,6 @@ static status_t execRm(const std::string& path, int startProgress, int stepProgr ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener); } return -1; -#endif } static status_t execCp(const std::string& fromPath, const std::string& toPath, int startProgress, @@ -144,9 +145,10 @@ static status_t execCp(const std::string& fromPath, const std::string& toPath, i } 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; @@ -167,7 +169,6 @@ static status_t execCp(const std::string& fromPath, const std::string& toPath, i ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener); } return -1; -#endif } static void bringOffline(const std::shared_ptr& vol) { diff --git a/model/Disk.cpp b/model/Disk.cpp index b42f215..9b772e4 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -455,12 +455,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; From 570b2864ee61749720ea15eee15c5e106751c341 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 31 Mar 2017 17:19:57 -0600 Subject: [PATCH 061/106] Grant "disk_reserved" GID to critical services. This GID extends the ability to use reserved disk space, giving the system a chance to be usable enough for the user to free up disk space used by apps. Test: builds, boots Bug: 62024591 Change-Id: I8bc47911a71e1f399616caae83678e2914781c7e --- vold.rc | 1 + 1 file changed, 1 insertion(+) diff --git a/vold.rc b/vold.rc index c27aeda..7d14453 100644 --- a/vold.rc +++ b/vold.rc @@ -5,3 +5,4 @@ service vold /system/bin/vold \ ioprio be 2 writepid /dev/cpuset/foreground/tasks shutdown critical + group reserved_disk From 53d5d7ca8a06d37bb79ca1f3662d0c2020b276ae Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 8 Jan 2018 10:43:00 -0700 Subject: [PATCH 062/106] Wire up reserved blocks presence for tests. This is how we tell CTS if the device has reserved blocks set aside for system critical services. Test: builds, boots Bug: 62024591 Change-Id: I7c8ec2294b246eed54668b5717df00e72f13887a --- main.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/main.cpp b/main.cpp index 01a2168..62ea6b7 100644 --- a/main.cpp +++ b/main.cpp @@ -41,7 +41,8 @@ #include #include -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); @@ -99,8 +100,9 @@ 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"; } @@ -122,6 +124,7 @@ int main(int argc, char** argv) { // a deadlock between vold and init (see b/34278978 for details) 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 @@ -204,7 +207,8 @@ static void coldboot(const char *path) { } } -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) { ATRACE_NAME("process_config"); fstab_default = fs_mgr_read_fstab_default(); @@ -216,11 +220,15 @@ 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; + *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(rec)) { if (fs_mgr_is_nonremovable(rec)) { From d7e51760430bc06617e7b42c77a8f4cfde80d041 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 8 Jan 2018 11:48:07 -0700 Subject: [PATCH 063/106] Add "default_normal" support to vold. This new flag isolates each user on a multi-user device for security reasons. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.ExternalStorageHostTest#testSecondaryUsersInaccessible Bug: 64672411 Change-Id: I3db8dde597a7715ca680779ac57957fb12a92f8e --- model/EmulatedVolume.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index d40cf3f..7f5c4ff 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -86,6 +86,7 @@ status_t EmulatedVolume::doMount() { "-m", "-w", "-G", + "-i", mRawPath.c_str(), label.c_str(), NULL)) { From 37ba125205023b3b6e80ed684ca4d282224c66dc Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 19 Jan 2018 10:55:18 +0900 Subject: [PATCH 064/106] Add basic exFAT support. Several partners have been requesting exFAT support. Android doesn't natively support exFAT, but we're at least willing to try mounting an exFAT filesystem if we detect the Linux kernel supports it, and if helper binaries are present. This CL is simple scaffolding, and it provides no actual implementation of exFAT. Test: builds, boots Bug: 67822822 Change-Id: Id4f8ec3967b32de6e1c0e3c4b47fe6e43a6291ab --- Android.bp | 1 + fs/Exfat.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++ fs/Exfat.h | 39 +++++++++++++++++ model/Disk.cpp | 13 +++--- model/PublicVolume.cpp | 46 ++++++++++++++------ 5 files changed, 177 insertions(+), 19 deletions(-) create mode 100644 fs/Exfat.cpp create mode 100644 fs/Exfat.h diff --git a/Android.bp b/Android.bp index aca6493..0a45395 100644 --- a/Android.bp +++ b/Android.bp @@ -115,6 +115,7 @@ cc_library_static { "VolumeManager.cpp", "authorization_set.cpp", "cryptfs.cpp", + "fs/Exfat.cpp", "fs/Ext4.cpp", "fs/F2fs.cpp", "fs/Vfat.cpp", diff --git a/fs/Exfat.cpp b/fs/Exfat.cpp new file mode 100644 index 0000000..5c15075 --- /dev/null +++ b/fs/Exfat.cpp @@ -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 + +#include +#include + +#include + +#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 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 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 diff --git a/fs/Exfat.h b/fs/Exfat.h new file mode 100644 index 0000000..768d8a5 --- /dev/null +++ b/fs/Exfat.h @@ -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 + +#include + +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 diff --git a/model/Disk.cpp b/model/Disk.cpp index 9b772e4..becf8b7 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -364,12 +364,13 @@ status_t Disk::readPartitions() { } switch (type) { - case 0x06: // FAT16 - case 0x0b: // W95 FAT32 (LBA) - case 0x0c: // W95 FAT32 (LBA) - case 0x0e: // W95 FAT16 (LBA) - createPublicVolume(partDevice); - break; + 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) { if (++it == split.end()) continue; diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 98c897f..efdb687 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ -#include "fs/Vfat.h" #include "PublicVolume.h" #include "Utils.h" #include "VolumeManager.h" +#include "fs/Exfat.h" +#include "fs/Vfat.h" #include #include @@ -93,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()) { @@ -130,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) { @@ -238,7 +250,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"; } @@ -246,6 +258,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; From 9929e7db3236070a6371ca9535085343a8d6a467 Mon Sep 17 00:00:00 2001 From: Risan Date: Mon, 22 Jan 2018 11:04:25 +0900 Subject: [PATCH 065/106] [VOLD] Add ARC++ ObbMount shared lib Unfortunately, static library dependency is not transitive (even if the dependency is a shared library). So I am wrapping the libarcobbvolume's dependency as libarcmounter shared library. Bug: 64500663 Test: Compile Change-Id: I12be7a9d885c7c1c043185bd134e0148d420c6fd --- Android.bp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Android.bp b/Android.bp index 0a45395..3760285 100644 --- a/Android.bp +++ b/Android.bp @@ -135,6 +135,9 @@ cc_library_static { static_libs: [ "libarcobbvolume", ], + shared_libs: [ + "libarcmounter", + ], }, }, } @@ -152,7 +155,11 @@ cc_binary { arc: { static_libs: [ "libarcobbvolume", - ] + ], + shared_libs: [ + "libarcmounter", + ], + }, }, init_rc: ["vold.rc"], From 71cd43f4340209780d441c234b3846646705e948 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 22 Jan 2018 11:25:29 -0800 Subject: [PATCH 066/106] Fingerprint data is now stored in one of two ways depending on the shipping API version: For devices shipped before Android P nothing changes, data is stored under /data/system/users//fpdata/... Devices shipped from now on will instead store fingerprint data under /data/vendor_de//fpdata. Support for /data/vendor_de and /data/vendor_ce has been added to vold. Bug: 36997597 Change-Id: I615e90d1c9ab08e768a8713968fa043598a0a526 Test: manually --- Ext4Crypt.cpp | 10 ++++++++++ Utils.cpp | 8 ++++++++ Utils.h | 2 ++ vold_prepare_subdirs.cpp | 13 +++++++++++++ 4 files changed, 33 insertions(+) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 85ace4a..1b71365 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -663,6 +663,7 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ // DE_n key auto system_de_path = android::vold::BuildDataSystemDePath(user_id); auto misc_de_path = android::vold::BuildDataMiscDePath(user_id); + auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id); auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id); if (volume_uuid.empty()) { @@ -675,6 +676,7 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ 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; @@ -685,6 +687,7 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ 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; } @@ -696,12 +699,14 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ // CE_n key auto system_ce_path = android::vold::BuildDataSystemCePath(user_id); auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id); + auto vendor_ce_path = android::vold::BuildDataVendorCePath(user_id); auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id); auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id); if (volume_uuid.empty()) { if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false; if (!prepare_dir(misc_ce_path, 01771, AID_SYSTEM, AID_MISC)) return false; + if (!prepare_dir(vendor_ce_path, 0771, AID_ROOT, AID_ROOT)) return false; } if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false; if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false; @@ -713,6 +718,7 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ 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; @@ -745,6 +751,7 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ // 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); @@ -753,6 +760,7 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ 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); @@ -769,6 +777,7 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ // 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); res &= destroy_dir(user_de_path); @@ -780,6 +789,7 @@ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_ 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); diff --git a/Utils.cpp b/Utils.cpp index 38edcb3..98e8a9b 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -635,6 +635,14 @@ std::string BuildDataProfilesDePath(userid_t userId) { return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath("").c_str(), userId); } +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.empty()) { diff --git a/Utils.h b/Utils.h index c5955cc..5caa4e9 100644 --- a/Utils.h +++ b/Utils.h @@ -107,6 +107,8 @@ 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 std::string& volumeUuid); std::string BuildDataMediaCePath(const std::string& volumeUuid, userid_t userid); diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp index 02bedde..1b466e9 100644 --- a/vold_prepare_subdirs.cpp +++ b/vold_prepare_subdirs.cpp @@ -38,6 +38,8 @@ #include "Utils.h" #include "android/os/IVold.h" +#include + static void usage(const char* progname) { std::cerr << "Usage: " << progname << " [ prepare | destroy ] " << std::endl; @@ -125,6 +127,11 @@ static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int fla 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); @@ -141,10 +148,16 @@ static bool destroy_subdirs(const std::string& volume_uuid, int user_id, int fla 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; From 785365b2f7baebe4e5fda619306d6c0dbc42ab46 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Sat, 20 Jan 2018 09:37:36 -0700 Subject: [PATCH 067/106] Clang-format Keymaster.{cpp|h} and KeyStorage.{cpp|h} Test: Build & boot Change-Id: I92bb107409f493770028cf6fd637d34af7644262 --- KeyStorage.cpp | 81 +++++++++++++++++++++++++------------------------- Keymaster.cpp | 50 +++++++++++++++---------------- Keymaster.h | 26 ++++++---------- 3 files changed, 73 insertions(+), 84 deletions(-) diff --git a/KeyStorage.cpp b/KeyStorage.cpp index 2f6aa1a..b564feb 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -41,7 +41,6 @@ #include - extern "C" { #include "crypto_scrypt.h" @@ -63,7 +62,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"; @@ -131,8 +130,7 @@ static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& return keymaster.generateKey(paramBuilder, key); } -static AuthorizationSet beginParams(const KeyAuthentication& auth, - const std::string& appId) { +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) @@ -204,10 +202,8 @@ bool readSecdiscardable(const std::string& filename, std::string* hash) { return true; } -static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, - KeyPurpose purpose, - const AuthorizationSet &keyParams, - const AuthorizationSet &opParams, +static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, KeyPurpose purpose, + const AuthorizationSet& keyParams, const AuthorizationSet& opParams, AuthorizationSet* outParams) { auto kmKeyPath = dir + "/" + kFn_keymaster_key_blob; std::string kmKey; @@ -238,8 +234,8 @@ static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, } static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, - const AuthorizationSet &keyParams, - const KeyBuffer& message, std::string* ciphertext) { + const AuthorizationSet& keyParams, const KeyBuffer& message, + std::string* ciphertext) { AuthorizationSet opParams; AuthorizationSet outParams; auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams); @@ -250,7 +246,8 @@ static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir return false; } // nonceBlob here is just a pointer into existing data, must not be freed - std::string nonce(reinterpret_cast(&nonceBlob.value()[0]), nonceBlob.value().size()); + std::string nonce(reinterpret_cast(&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; @@ -263,12 +260,11 @@ static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir } static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, - const AuthorizationSet &keyParams, + const AuthorizationSet& keyParams, 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 opParams = AuthorizationSetBuilder().Authorization(TAG_NONCE, blob2hidlVec(nonce)); auto opHandle = begin(keymaster, dir, KeyPurpose::DECRYPT, keyParams, opParams, nullptr); if (!opHandle) return false; if (!opHandle.updateCompletely(bodyAndMac, message)) return false; @@ -313,9 +309,9 @@ static bool stretchSecret(const std::string& stretching, const std::string& secr } stretched->assign(STRETCHED_BYTES, '\0'); if (crypto_scrypt(reinterpret_cast(secret.data()), secret.size(), - reinterpret_cast(salt.data()), salt.size(), - 1 << Nf, 1 << rf, 1 << pf, - reinterpret_cast(&(*stretched)[0]), stretched->size()) != 0) { + reinterpret_cast(salt.data()), salt.size(), 1 << Nf, + 1 << rf, 1 << pf, reinterpret_cast(&(*stretched)[0]), + stretched->size()) != 0) { LOG(ERROR) << "scrypt failed with params: " << stretching; return false; } @@ -339,8 +335,8 @@ static void logOpensslError() { LOG(ERROR) << "Openssl error: " << ERR_get_error(); } -static bool encryptWithoutKeymaster(const std::string& preKey, - const KeyBuffer& plaintext, std::string* ciphertext) { +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); @@ -352,16 +348,16 @@ static bool encryptWithoutKeymaster(const std::string& preKey, return false; } if (1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, - reinterpret_cast(key.data()), - reinterpret_cast(ciphertext->data()))) { + reinterpret_cast(key.data()), + reinterpret_cast(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(&(*ciphertext)[0] + GCM_NONCE_BYTES), &outlen, - reinterpret_cast(plaintext.data()), plaintext.size())) { + if (1 != EVP_EncryptUpdate( + ctx.get(), reinterpret_cast(&(*ciphertext)[0] + GCM_NONCE_BYTES), + &outlen, reinterpret_cast(plaintext.data()), plaintext.size())) { logOpensslError(); return false; } @@ -369,8 +365,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(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()), &outlen)) { + if (1 != EVP_EncryptFinal_ex( + ctx.get(), + reinterpret_cast(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()), + &outlen)) { logOpensslError(); return false; } @@ -379,15 +377,16 @@ 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(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()))) { + reinterpret_cast(&(*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; @@ -402,16 +401,16 @@ static bool decryptWithoutKeymaster(const std::string& preKey, return false; } if (1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, - reinterpret_cast(key.data()), - reinterpret_cast(ciphertext.data()))) { + reinterpret_cast(key.data()), + reinterpret_cast(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(&(*plaintext)[0]), &outlen, - reinterpret_cast(ciphertext.data() + GCM_NONCE_BYTES), plaintext->size())) { + if (1 != EVP_DecryptUpdate(ctx.get(), reinterpret_cast(&(*plaintext)[0]), &outlen, + reinterpret_cast(ciphertext.data() + GCM_NONCE_BYTES), + plaintext->size())) { logOpensslError(); return false; } @@ -420,13 +419,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( - reinterpret_cast(ciphertext.data() + GCM_NONCE_BYTES + plaintext->size())))) { + const_cast(reinterpret_cast( + ciphertext.data() + GCM_NONCE_BYTES + plaintext->size())))) { logOpensslError(); return false; } if (1 != EVP_DecryptFinal_ex(ctx.get(), - reinterpret_cast(&(*plaintext)[0] + plaintext->size()), &outlen)) { + reinterpret_cast(&(*plaintext)[0] + plaintext->size()), + &outlen)) { logOpensslError(); return false; } @@ -519,7 +519,8 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe Keymaster keymaster; if (!keymaster) return false; auto keyParams = beginParams(auth, appId); - if (!decryptWithKeymasterKey(keymaster, dir, keyParams, encryptedMessage, key)) return false; + if (!decryptWithKeymasterKey(keymaster, dir, keyParams, encryptedMessage, key)) + return false; } else { if (!decryptWithoutKeymaster(appId, encryptedMessage, key)) return false; } @@ -536,9 +537,7 @@ static bool deleteKey(const std::string& dir) { } bool runSecdiscardSingle(const std::string& file) { - if (ForkExecvp( - std::vector{kSecdiscardPath, "--", - file}) != 0) { + if (ForkExecvp(std::vector{kSecdiscardPath, "--", file}) != 0) { LOG(ERROR) << "secdiscard failed"; return false; } diff --git a/Keymaster.cpp b/Keymaster.cpp index e32d598..c39280e 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -33,12 +33,12 @@ KeymasterOperation::~KeymasterOperation() { } bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen, - const std::function consumer) { + const std::function consumer) { uint32_t inputConsumed = 0; ErrorCode km_error; - auto hidlCB = [&] (ErrorCode ret, uint32_t inputConsumedDelta, - const hidl_vec& /*ignored*/, const hidl_vec& _output) { + auto hidlCB = [&](ErrorCode ret, uint32_t inputConsumedDelta, + const hidl_vec& /*ignored*/, const hidl_vec& _output) { km_error = ret; if (km_error != ErrorCode::OK) return; inputConsumed += inputConsumedDelta; @@ -48,7 +48,7 @@ bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen, while (inputConsumed != inputLen) { size_t toRead = static_cast(inputLen - inputConsumed); auto inputBlob = - blob2hidlVec(reinterpret_cast(&input[inputConsumed]), toRead); + blob2hidlVec(reinterpret_cast(&input[inputConsumed]), toRead); auto error = mDevice->update(mOpHandle, hidl_vec(), inputBlob, hidlCB); if (!error.isOk()) { LOG(ERROR) << "update failed: " << error.description(); @@ -71,15 +71,14 @@ 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& /*ignored*/, - const hidl_vec& _output) { + auto hidlCb = [&](ErrorCode ret, const hidl_vec& /*ignored*/, + const hidl_vec& _output) { km_error = ret; if (km_error != ErrorCode::OK) return; - if (output) - output->assign(reinterpret_cast(&_output[0]), _output.size()); + if (output) output->assign(reinterpret_cast(&_output[0]), _output.size()); }; auto error = mDevice->finish(mOpHandle, hidl_vec(), hidl_vec(), - hidl_vec(), hidlCb); + hidl_vec(), hidlCb); mDevice = nullptr; if (!error.isOk()) { LOG(ERROR) << "finish failed: " << error.description(); @@ -98,12 +97,11 @@ Keymaster::Keymaster() { bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key) { ErrorCode km_error; - auto hidlCb = [&] (ErrorCode ret, const hidl_vec& keyBlob, - const KeyCharacteristics& /*ignored*/) { + auto hidlCb = [&](ErrorCode ret, const hidl_vec& keyBlob, + const KeyCharacteristics& /*ignored*/) { km_error = ret; if (km_error != ErrorCode::OK) return; - if (key) - key->assign(reinterpret_cast(&keyBlob[0]), keyBlob.size()); + if (key) key->assign(reinterpret_cast(&keyBlob[0]), keyBlob.size()); }; auto error = mDevice->generateKey(inParams.hidl_data(), hidlCb); @@ -136,12 +134,12 @@ bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& in std::string* newKey) { auto oldKeyBlob = blob2hidlVec(oldKey); ErrorCode km_error; - auto hidlCb = [&] (ErrorCode ret, const hidl_vec& upgradedKeyBlob) { + auto hidlCb = [&](ErrorCode ret, const hidl_vec& upgradedKeyBlob) { km_error = ret; if (km_error != ErrorCode::OK) return; if (newKey) newKey->assign(reinterpret_cast(&upgradedKeyBlob[0]), - upgradedKeyBlob.size()); + upgradedKeyBlob.size()); }; auto error = mDevice->upgradeKey(oldKeyBlob, inParams.hidl_data(), hidlCb); if (!error.isOk()) { @@ -156,18 +154,16 @@ bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& in } KeymasterOperation Keymaster::begin(KeyPurpose purpose, const std::string& key, - const AuthorizationSet& inParams, - AuthorizationSet* outParams) { + const AuthorizationSet& inParams, AuthorizationSet* outParams) { auto keyBlob = blob2hidlVec(key); uint64_t mOpHandle; ErrorCode km_error; - auto hidlCb = [&] (ErrorCode ret, const hidl_vec& _outParams, - uint64_t operationHandle) { + auto hidlCb = [&](ErrorCode ret, const hidl_vec& _outParams, + uint64_t operationHandle) { km_error = ret; if (km_error != ErrorCode::OK) return; - if (outParams) - *outParams = _outParams; + if (outParams) *outParams = _outParams; mOpHandle = operationHandle; }; @@ -184,9 +180,9 @@ KeymasterOperation Keymaster::begin(KeyPurpose purpose, const std::string& key, } bool Keymaster::isSecure() { bool _isSecure = false; - auto rc = mDevice->getHardwareFeatures( - [&] (bool isSecure, bool, bool, bool, bool, const hidl_string&, const hidl_string&) { - _isSecure = isSecure; }); + auto rc = + mDevice->getHardwareFeatures([&](bool isSecure, bool, bool, bool, bool, const hidl_string&, + const hidl_string&) { _isSecure = isSecure; }); return rc.isOk() && _isSecure; } @@ -298,7 +294,8 @@ KeymasterSignResult keymaster_sign_object_for_cryptfs_scrypt( if (op.errorCode() == ErrorCode::KEY_RATE_LIMIT_EXCEEDED) { sleep(ratelimit); continue; - } else break; + } else + break; } if (op.errorCode() == ErrorCode::KEY_REQUIRES_UPGRADE) { @@ -318,7 +315,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; } diff --git a/Keymaster.h b/Keymaster.h index 6ed5276..aef1602 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -23,8 +23,8 @@ #include #include -#include #include +#include #include "authorization_set.h" @@ -56,7 +56,7 @@ class KeymasterOperation { 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)); }); } @@ -69,11 +69,9 @@ class KeymasterOperation { mError = std::move(rhs.mError); } // 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{ErrorCode::UNKNOWN_ERROR} {} // Move Assignment - KeymasterOperation& operator= (KeymasterOperation&& rhs) { + KeymasterOperation& operator=(KeymasterOperation&& rhs) { mDevice = std::move(rhs.mDevice); mOpHandle = std::move(rhs.mOpHandle); mError = std::move(rhs.mError); @@ -84,10 +82,8 @@ class KeymasterOperation { private: KeymasterOperation(const sp& d, uint64_t h) - : mDevice{d}, mOpHandle{h}, mError {ErrorCode::OK} {} - KeymasterOperation(ErrorCode error) - : mDevice{nullptr}, mOpHandle{0}, - mError {error} {} + : mDevice{d}, mOpHandle{h}, mError{ErrorCode::OK} {} + KeymasterOperation(ErrorCode error) : mDevice{nullptr}, mOpHandle{0}, mError{error} {} bool updateCompletely(const char* input, size_t inputLen, const std::function consumer); @@ -146,12 +142,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, @@ -162,5 +155,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); - #endif From 353518194e520a0f78be9f2361939a2dffa9aae9 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Mon, 22 Jan 2018 09:08:32 -0700 Subject: [PATCH 068/106] Support Keymaster4 This CL changes vold from using a KM3 device directly to using the KM4 support wrapper from the KM4 support library, which supports both KM3 and KM4 devices (KM0, 1 and 2 devices are still supported as well, because the default KM3 device is a wrapper that uses them). In addition, I found myself getting confused about which "Keymaster" types were locally-defined vold keymaster types and which were from the KM4 HAL and support library, so I changd the approach to referencing the latter, so all of them are qualified with the "km::" namespace reference. Test: Build & boot Change-Id: I08ed5425641e7496f8597d5716cb3cd0cbd33a7f --- Android.bp | 3 +- KeyStorage.cpp | 88 +++++---- Keymaster.cpp | 149 +++++++------- Keymaster.h | 48 +++-- authorization_set.cpp | 420 ---------------------------------------- authorization_set.h | 327 ------------------------------- keymaster_tags.h | 372 ----------------------------------- keystore_hidl_support.h | 108 ----------- 8 files changed, 148 insertions(+), 1367 deletions(-) delete mode 100644 authorization_set.cpp delete mode 100644 authorization_set.h delete mode 100644 keymaster_tags.h delete mode 100644 keystore_hidl_support.h diff --git a/Android.bp b/Android.bp index 3760285..12d8b2d 100644 --- a/Android.bp +++ b/Android.bp @@ -38,6 +38,7 @@ cc_defaults { ], shared_libs: [ "android.hardware.keymaster@3.0", + "android.hardware.keymaster@4.0", "libbase", "libbinder", "libcrypto", @@ -50,6 +51,7 @@ cc_defaults { "libhardware_legacy", "libhidlbase", "libhwbinder", + "libkeymaster4support", "libkeyutils", "liblog", "liblogwrap", @@ -113,7 +115,6 @@ cc_library_static { "VoldNativeService.cpp", "VoldUtil.cpp", "VolumeManager.cpp", - "authorization_set.cpp", "cryptfs.cpp", "fs/Exfat.cpp", "fs/Ext4.cpp", diff --git a/KeyStorage.cpp b/KeyStorage.cpp index b564feb..0518930 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -40,18 +40,16 @@ #include #include +#include +#include extern "C" { #include "crypto_scrypt.h" } -#include "authorization_set.h" -#include "keystore_hidl_support.h" - namespace android { namespace vold { -using namespace keystore; const KeyAuthentication kEmptyAuthentication{"", ""}; @@ -106,15 +104,13 @@ static void hashWithPrefix(char const* prefix, const std::string& tohash, std::s 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,24 +119,24 @@ static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& return false; } const hw_auth_token_t* at = reinterpret_cast(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 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 paramBuilder; + return {paramBuilder, authToken}; } static bool readFileToString(const std::string& filename, std::string* result) { @@ -202,20 +198,22 @@ bool readSecdiscardable(const std::string& filename, std::string* hash) { return true; } -static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, KeyPurpose purpose, - const AuthorizationSet& keyParams, const AuthorizationSet& opParams, - AuthorizationSet* outParams) { +static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, + 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(); @@ -234,13 +232,15 @@ static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, Ke } static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, - const AuthorizationSet& keyParams, const KeyBuffer& message, - std::string* ciphertext) { - AuthorizationSet opParams; - AuthorizationSet outParams; - auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams); + const km::AuthorizationSet& keyParams, + const km::HardwareAuthToken& authToken, + const KeyBuffer& message, std::string* ciphertext) { + 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; @@ -260,12 +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; @@ -468,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; } @@ -518,8 +524,10 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe if (auth.usesKeymaster()) { Keymaster keymaster; if (!keymaster) return false; - auto keyParams = beginParams(auth, appId); - if (!decryptWithKeymasterKey(keymaster, dir, keyParams, encryptedMessage, key)) + 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; diff --git a/Keymaster.cpp b/Keymaster.cpp index c39280e..7d061bb 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -17,45 +17,48 @@ #include "Keymaster.h" #include - -#include "authorization_set.h" -#include "keymaster_tags.h" -#include "keystore_hidl_support.h" - -using namespace ::keystore; -using android::hardware::hidl_string; +#include +#include namespace android { namespace vold { +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; + 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 consumer) { uint32_t inputConsumed = 0; - ErrorCode km_error; - auto hidlCB = [&](ErrorCode ret, uint32_t inputConsumedDelta, - const hidl_vec& /*ignored*/, const hidl_vec& _output) { + km::ErrorCode km_error; + auto hidlCB = [&](km::ErrorCode ret, uint32_t inputConsumedDelta, + const hidl_vec& /*ignored*/, + const hidl_vec& _output) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; inputConsumed += inputConsumedDelta; consumer(reinterpret_cast(&_output[0]), _output.size()); }; while (inputConsumed != inputLen) { size_t toRead = static_cast(inputLen - inputConsumed); - auto inputBlob = - blob2hidlVec(reinterpret_cast(&input[inputConsumed]), toRead); - auto error = mDevice->update(mOpHandle, hidl_vec(), inputBlob, hidlCB); + auto inputBlob = km::support::blob2hidlVec( + reinterpret_cast(&input[inputConsumed]), toRead); + // TODO(swillden): Need to handle getting a VerificationToken from the TEE if mDevice is + // StrongBox, so we can provide it here. The VerificationToken will need to be + // requested/retrieved during Keymaster::begin(). + auto error = mDevice->update(mOpHandle, hidl_vec(), 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; @@ -70,21 +73,22 @@ 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& /*ignored*/, + km::ErrorCode km_error; + auto hidlCb = [&](km::ErrorCode ret, const hidl_vec& /*ignored*/, const hidl_vec& _output) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; if (output) output->assign(reinterpret_cast(&_output[0]), _output.size()); }; - auto error = mDevice->finish(mOpHandle, hidl_vec(), hidl_vec(), - hidl_vec(), hidlCb); + auto error = mDevice->finish(mOpHandle, hidl_vec(), hidl_vec(), + hidl_vec(), 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; } @@ -92,15 +96,21 @@ bool KeymasterOperation::finish(std::string* output) { } Keymaster::Keymaster() { - mDevice = ::android::hardware::keymaster::V3_0::IKeymasterDevice::getService(); + auto devices = KmDevice::enumerateAvailableDevices(); + if (devices.empty()) return; + mDevice = std::move(devices[0]); + 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& 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& keyBlob, + const km::KeyCharacteristics& /*ignored*/) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; if (key) key->assign(reinterpret_cast(&keyBlob[0]), keyBlob.size()); }; @@ -109,7 +119,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; } @@ -117,26 +127,26 @@ bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key) } bool Keymaster::deleteKey(const std::string& key) { - auto keyBlob = blob2hidlVec(key); + auto keyBlob = km::support::blob2hidlVec(key); auto error = mDevice->deleteKey(keyBlob); if (!error.isOk()) { LOG(ERROR) << "delete_key failed: " << error.description(); return false; } - if (ErrorCode(error) != ErrorCode::OK) { - LOG(ERROR) << "delete_key failed, code " << uint32_t(ErrorCode(error)); + if (error != km::ErrorCode::OK) { + LOG(ERROR) << "delete_key failed, code " << int32_t(km::ErrorCode(error)); return false; } return true; } -bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams, +bool Keymaster::upgradeKey(const std::string& oldKey, const km::AuthorizationSet& inParams, std::string* newKey) { - auto oldKeyBlob = blob2hidlVec(oldKey); - ErrorCode km_error; - auto hidlCb = [&](ErrorCode ret, const hidl_vec& upgradedKeyBlob) { + auto oldKeyBlob = km::support::blob2hidlVec(oldKey); + km::ErrorCode km_error; + auto hidlCb = [&](km::ErrorCode ret, const hidl_vec& upgradedKeyBlob) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; if (newKey) newKey->assign(reinterpret_cast(&upgradedKeyBlob[0]), upgradedKeyBlob.size()); @@ -146,44 +156,43 @@ bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& in LOG(ERROR) << "upgrade_key failed: " << error.description(); return false; } - if (km_error != ErrorCode::OK) { + if (km_error != km::ErrorCode::OK) { LOG(ERROR) << "upgrade_key failed, code " << int32_t(km_error); return false; } return true; } -KeymasterOperation Keymaster::begin(KeyPurpose purpose, const std::string& key, - const AuthorizationSet& inParams, AuthorizationSet* outParams) { - auto keyBlob = blob2hidlVec(key); +KeymasterOperation Keymaster::begin(km::KeyPurpose purpose, const std::string& key, + const km::AuthorizationSet& inParams, + const km::HardwareAuthToken& authToken, + km::AuthorizationSet* outParams) { + auto keyBlob = km::support::blob2hidlVec(key); uint64_t mOpHandle; - ErrorCode km_error; + km::ErrorCode km_error; - auto hidlCb = [&](ErrorCode ret, const hidl_vec& _outParams, + auto hidlCb = [&](km::ErrorCode ret, const hidl_vec& _outParams, uint64_t operationHandle) { km_error = ret; - if (km_error != ErrorCode::OK) return; + 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 @@ -216,17 +225,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, @@ -279,31 +285,28 @@ KeymasterSignResult keymaster_sign_object_for_cryptfs_scrypt( return KeymasterSignResult::error; } - AuthorizationSet outParams; + km::AuthorizationSet outParams; std::string key(reinterpret_cast(key_blob), key_blob_size); std::string input(reinterpret_cast(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; } - 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; } diff --git a/Keymaster.h b/Keymaster.h index aef1602..0bda8cd 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -24,16 +24,14 @@ #include #include -#include - -#include "authorization_set.h" +#include +#include 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 @@ -48,8 +46,8 @@ 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 @@ -63,34 +61,30 @@ class KeymasterOperation { // 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; + rhs.mError = km::ErrorCode::UNKNOWN_ERROR; rhs.mOpHandle = 0; return *this; } private: - KeymasterOperation(const sp& 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 consumer); - sp mDevice; + KmDevice* mDevice; uint64_t mOpHandle; - ErrorCode mError; + km::ErrorCode mError; DISALLOW_COPY_AND_ASSIGN(KeymasterOperation); friend class Keymaster; }; @@ -103,19 +97,21 @@ 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 mDevice; + std::unique_ptr mDevice; DISALLOW_COPY_AND_ASSIGN(Keymaster); }; diff --git a/authorization_set.cpp b/authorization_set.cpp deleted file mode 100644 index e7a3401..0000000 --- a/authorization_set.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2014 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 "authorization_set.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace keystore { - -inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) { - if (a.tag != b.tag) return a.tag < b.tag; - int retval; - switch (typeFromTag(a.tag)) { - case TagType::INVALID: - case TagType::BOOL: - return false; - case TagType::ENUM: - case TagType::ENUM_REP: - case TagType::UINT: - case TagType::UINT_REP: - return a.f.integer < b.f.integer; - case TagType::ULONG: - case TagType::ULONG_REP: - return a.f.longInteger < b.f.longInteger; - case TagType::DATE: - return a.f.dateTime < b.f.dateTime; - case TagType::BIGNUM: - case TagType::BYTES: - // Handle the empty cases. - if (a.blob.size() == 0) return b.blob.size() != 0; - if (b.blob.size() == 0) return false; - - retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size())); - // if one is the prefix of the other the longer wins - if (retval == 0) return a.blob.size() < b.blob.size(); - // Otherwise a is less if a is less. - else - return retval < 0; - } - return false; -} - -inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) { - if (a.tag != b.tag) return false; - - switch (typeFromTag(a.tag)) { - case TagType::INVALID: - case TagType::BOOL: - return true; - case TagType::ENUM: - case TagType::ENUM_REP: - case TagType::UINT: - case TagType::UINT_REP: - return a.f.integer == b.f.integer; - case TagType::ULONG: - case TagType::ULONG_REP: - return a.f.longInteger == b.f.longInteger; - case TagType::DATE: - return a.f.dateTime == b.f.dateTime; - case TagType::BIGNUM: - case TagType::BYTES: - if (a.blob.size() != b.blob.size()) return false; - return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0; - } - return false; -} - -void AuthorizationSet::Sort() { - std::sort(data_.begin(), data_.end(), keyParamLess); -} - -void AuthorizationSet::Deduplicate() { - if (data_.empty()) return; - - Sort(); - std::vector result; - - auto curr = data_.begin(); - auto prev = curr++; - for (; curr != data_.end(); ++prev, ++curr) { - if (prev->tag == Tag::INVALID) continue; - - if (!keyParamEqual(*prev, *curr)) { - result.emplace_back(std::move(*prev)); - } - } - result.emplace_back(std::move(*prev)); - - std::swap(data_, result); -} - -void AuthorizationSet::Union(const AuthorizationSet& other) { - data_.insert(data_.end(), other.data_.begin(), other.data_.end()); - Deduplicate(); -} - -void AuthorizationSet::Subtract(const AuthorizationSet& other) { - Deduplicate(); - - auto i = other.begin(); - while (i != other.end()) { - int pos = -1; - do { - pos = find(i->tag, pos); - if (pos != -1 && keyParamEqual(*i, data_[pos])) { - data_.erase(data_.begin() + pos); - break; - } - } while (pos != -1); - ++i; - } -} - -int AuthorizationSet::find(Tag tag, int begin) const { - auto iter = data_.begin() + (1 + begin); - - while (iter != data_.end() && iter->tag != tag) ++iter; - - if (iter != data_.end()) return iter - data_.begin(); - return -1; -} - -bool AuthorizationSet::erase(int index) { - auto pos = data_.begin() + index; - if (pos != data_.end()) { - data_.erase(pos); - return true; - } - return false; -} - -KeyParameter& AuthorizationSet::operator[](int at) { - return data_[at]; -} - -const KeyParameter& AuthorizationSet::operator[](int at) const { - return data_[at]; -} - -void AuthorizationSet::Clear() { - data_.clear(); -} - -size_t AuthorizationSet::GetTagCount(Tag tag) const { - size_t count = 0; - for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count; - return count; -} - -NullOr AuthorizationSet::GetEntry(Tag tag) const { - int pos = find(tag); - if (pos == -1) return {}; - return data_[pos]; -} - -/** - * Persistent format is: - * | 32 bit indirect_size | - * -------------------------------- - * | indirect_size bytes of data | this is where the blob data is stored - * -------------------------------- - * | 32 bit element_count | number of entries - * | 32 bit elements_size | total bytes used by entries (entries have variable length) - * -------------------------------- - * | elementes_size bytes of data | where the elements are stored - */ - -/** - * Persistent format of blobs and bignums: - * | 32 bit tag | - * | 32 bit blob_length | - * | 32 bit indirect_offset | - */ - -struct OutStreams { - std::ostream& indirect; - std::ostream& elements; -}; - -OutStreams& serializeParamValue(OutStreams& out, const hidl_vec& blob) { - uint32_t buffer; - - // write blob_length - auto blob_length = blob.size(); - if (blob_length > std::numeric_limits::max()) { - out.elements.setstate(std::ios_base::badbit); - return out; - } - buffer = blob_length; - out.elements.write(reinterpret_cast(&buffer), sizeof(uint32_t)); - - // write indirect_offset - auto offset = out.indirect.tellp(); - if (offset < 0 || offset > std::numeric_limits::max() || - uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check - out.elements.setstate(std::ios_base::badbit); - return out; - } - buffer = offset; - out.elements.write(reinterpret_cast(&buffer), sizeof(uint32_t)); - - // write blob to indirect stream - if (blob_length) out.indirect.write(reinterpret_cast(&blob[0]), blob_length); - - return out; -} - -template -OutStreams& serializeParamValue(OutStreams& out, const T& value) { - out.elements.write(reinterpret_cast(&value), sizeof(T)); - return out; -} - -OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) { - // skip invalid entries. - return out; -} -template -OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) { - out.elements.write(reinterpret_cast(¶m.tag), sizeof(int32_t)); - return serializeParamValue(out, accessTagValue(ttag, param)); -} - -template -struct choose_serializer; -template -struct choose_serializer> { - static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { - return choose_serializer::serialize(out, param); - } -}; -template <> -struct choose_serializer<> { - static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; } -}; -template -struct choose_serializer, Tail...> { - static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { - if (param.tag == tag) { - return keystore::serialize(TypedTag(), out, param); - } else { - return choose_serializer::serialize(out, param); - } - } -}; - -OutStreams& serialize(OutStreams& out, const KeyParameter& param) { - return choose_serializer::serialize(out, param); -} - -std::ostream& serialize(std::ostream& out, const std::vector& params) { - std::stringstream indirect; - std::stringstream elements; - OutStreams streams = {indirect, elements}; - for (const auto& param : params) { - serialize(streams, param); - } - if (indirect.bad() || elements.bad()) { - out.setstate(std::ios_base::badbit); - return out; - } - auto pos = indirect.tellp(); - if (pos < 0 || pos > std::numeric_limits::max()) { - out.setstate(std::ios_base::badbit); - return out; - } - uint32_t indirect_size = pos; - pos = elements.tellp(); - if (pos < 0 || pos > std::numeric_limits::max()) { - out.setstate(std::ios_base::badbit); - return out; - } - uint32_t elements_size = pos; - uint32_t element_count = params.size(); - - out.write(reinterpret_cast(&indirect_size), sizeof(uint32_t)); - - pos = out.tellp(); - if (indirect_size) out << indirect.rdbuf(); - assert(out.tellp() - pos == indirect_size); - - out.write(reinterpret_cast(&element_count), sizeof(uint32_t)); - out.write(reinterpret_cast(&elements_size), sizeof(uint32_t)); - - pos = out.tellp(); - if (elements_size) out << elements.rdbuf(); - assert(out.tellp() - pos == elements_size); - - return out; -} - -struct InStreams { - std::istream& indirect; - std::istream& elements; -}; - -InStreams& deserializeParamValue(InStreams& in, hidl_vec* blob) { - uint32_t blob_length = 0; - uint32_t offset = 0; - in.elements.read(reinterpret_cast(&blob_length), sizeof(uint32_t)); - blob->resize(blob_length); - in.elements.read(reinterpret_cast(&offset), sizeof(uint32_t)); - in.indirect.seekg(offset); - in.indirect.read(reinterpret_cast(&(*blob)[0]), blob->size()); - return in; -} - -template -InStreams& deserializeParamValue(InStreams& in, T* value) { - in.elements.read(reinterpret_cast(value), sizeof(T)); - return in; -} - -InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) { - // there should be no invalid KeyParamaters but if handle them as zero sized. - return in; -} - -template -InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) { - return deserializeParamValue(in, &accessTagValue(ttag, *param)); -} - -template -struct choose_deserializer; -template -struct choose_deserializer> { - static InStreams& deserialize(InStreams& in, KeyParameter* param) { - return choose_deserializer::deserialize(in, param); - } -}; -template <> -struct choose_deserializer<> { - static InStreams& deserialize(InStreams& in, KeyParameter*) { - // encountered an unknown tag -> fail parsing - in.elements.setstate(std::ios_base::badbit); - return in; - } -}; -template -struct choose_deserializer, Tail...> { - static InStreams& deserialize(InStreams& in, KeyParameter* param) { - if (param->tag == tag) { - return keystore::deserialize(TypedTag(), in, param); - } else { - return choose_deserializer::deserialize(in, param); - } - } -}; - -InStreams& deserialize(InStreams& in, KeyParameter* param) { - in.elements.read(reinterpret_cast(¶m->tag), sizeof(Tag)); - return choose_deserializer::deserialize(in, param); -} - -std::istream& deserialize(std::istream& in, std::vector* params) { - uint32_t indirect_size = 0; - in.read(reinterpret_cast(&indirect_size), sizeof(uint32_t)); - std::string indirect_buffer(indirect_size, '\0'); - if (indirect_buffer.size() != indirect_size) { - in.setstate(std::ios_base::badbit); - return in; - } - in.read(&indirect_buffer[0], indirect_buffer.size()); - - uint32_t element_count = 0; - in.read(reinterpret_cast(&element_count), sizeof(uint32_t)); - uint32_t elements_size = 0; - in.read(reinterpret_cast(&elements_size), sizeof(uint32_t)); - - std::string elements_buffer(elements_size, '\0'); - if (elements_buffer.size() != elements_size) { - in.setstate(std::ios_base::badbit); - return in; - } - in.read(&elements_buffer[0], elements_buffer.size()); - - if (in.bad()) return in; - - // TODO write one-shot stream buffer to avoid copying here - std::stringstream indirect(indirect_buffer); - std::stringstream elements(elements_buffer); - InStreams streams = {indirect, elements}; - - params->resize(element_count); - - for (uint32_t i = 0; i < element_count; ++i) { - deserialize(streams, &(*params)[i]); - } - return in; -} -void AuthorizationSet::Serialize(std::ostream* out) const { - serialize(*out, data_); -} -void AuthorizationSet::Deserialize(std::istream* in) { - deserialize(*in, &data_); -} - -} // namespace keystore diff --git a/authorization_set.h b/authorization_set.h deleted file mode 100644 index 8f68bb0..0000000 --- a/authorization_set.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright 2014 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 SYSTEM_VOLD_AUTHORIZATION_SET_H_ -#define SYSTEM_VOLD_AUTHORIZATION_SET_H_ - -#include - -#include "keymaster_tags.h" - -namespace keystore { - -class AuthorizationSetBuilder; - -/** - * An ordered collection of KeyParameters. It provides memory ownership and some convenient - * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters. - * For serialization, wrap the backing store of this structure in a hidl_vec. - */ -class AuthorizationSet { - public: - /** - * Construct an empty, dynamically-allocated, growable AuthorizationSet. - */ - AuthorizationSet(){}; - - // Copy constructor. - AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {} - - // Move constructor. - AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {} - - // Constructor from hidl_vec - AuthorizationSet(const hidl_vec& other) { *this = other; } - - // Copy assignment. - AuthorizationSet& operator=(const AuthorizationSet& other) { - data_ = other.data_; - return *this; - } - - // Move assignment. - AuthorizationSet& operator=(AuthorizationSet&& other) { - data_ = std::move(other.data_); - return *this; - } - - AuthorizationSet& operator=(const hidl_vec& other) { - if (other.size() > 0) { - data_.resize(other.size()); - for (size_t i = 0; i < data_.size(); ++i) { - /* This makes a deep copy even of embedded blobs. - * See assignment operator/copy constructor of hidl_vec.*/ - data_[i] = other[i]; - } - } - return *this; - } - - /** - * Clear existing authorization set data - */ - void Clear(); - - ~AuthorizationSet() = default; - - /** - * Returns the size of the set. - */ - size_t size() const { return data_.size(); } - - /** - * Returns true if the set is empty. - */ - bool empty() const { return size() == 0; } - - /** - * Returns the data in the set, directly. Be careful with this. - */ - const KeyParameter* data() const { return data_.data(); } - - /** - * Sorts the set - */ - void Sort(); - - /** - * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the - * AuthorizationSetBuilder). - */ - void Deduplicate(); - - /** - * Adds all elements from \p set that are not already present in this AuthorizationSet. As a - * side-effect, if \p set is not null this AuthorizationSet will end up sorted. - */ - void Union(const AuthorizationSet& set); - - /** - * Removes all elements in \p set from this AuthorizationSet. - */ - void Subtract(const AuthorizationSet& set); - - /** - * Returns the offset of the next entry that matches \p tag, starting from the element after \p - * begin. If not found, returns -1. - */ - int find(Tag tag, int begin = -1) const; - - /** - * Removes the entry at the specified index. Returns true if successful, false if the index was - * out of bounds. - */ - bool erase(int index); - - /** - * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration - */ - std::vector::const_iterator begin() const { return data_.begin(); } - - /** - * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration - */ - std::vector::const_iterator end() const { return data_.end(); } - - /** - * Returns the nth element of the set. - * Like for std::vector::operator[] there is no range check performed. Use of out of range - * indices is undefined. - */ - KeyParameter& operator[](int n); - - /** - * Returns the nth element of the set. - * Like for std::vector::operator[] there is no range check performed. Use of out of range - * indices is undefined. - */ - const KeyParameter& operator[](int n) const; - - /** - * Returns true if the set contains at least one instance of \p tag - */ - bool Contains(Tag tag) const { return find(tag) != -1; } - - template - bool Contains(TypedTag ttag, const ValueT& value) const { - for (const auto& param : data_) { - auto entry = authorizationValue(ttag, param); - if (entry.isOk() && entry.value() == value) return true; - } - return false; - } - /** - * Returns the number of \p tag entries. - */ - size_t GetTagCount(Tag tag) const; - - template - inline NullOr::type&> GetTagValue(T tag) const { - auto entry = GetEntry(tag); - if (entry.isOk()) return authorizationValue(tag, entry.value()); - return {}; - } - - void push_back(const KeyParameter& param) { data_.push_back(param); } - void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); } - - /** - * Append the tag and enumerated value to the set. - * "val" may be exactly one parameter unless a boolean parameter is added. - * In this case "val" is omitted. This condition is checked at compile time by Authorization() - */ - template - void push_back(TypedTagT tag, Value&&... val) { - push_back(Authorization(tag, std::forward(val)...)); - } - - template - void append(Iterator begin, Iterator end) { - while (begin != end) { - push_back(*begin); - ++begin; - } - } - - hidl_vec hidl_data() const { - hidl_vec result; - result.setToExternal(const_cast(data()), size()); - return result; - } - - void Serialize(std::ostream* out) const; - void Deserialize(std::istream* in); - - private: - NullOr GetEntry(Tag tag) const; - - std::vector data_; -}; - -class AuthorizationSetBuilder : public AuthorizationSet { - public: - template - AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) { - push_back(ttag, std::forward(value)...); - return *this; - } - - template - AuthorizationSetBuilder& Authorization(TypedTag ttag, const uint8_t* data, - size_t data_length) { - hidl_vec new_blob; - new_blob.setToExternal(const_cast(data), data_length); - push_back(ttag, std::move(new_blob)); - return *this; - } - - template - AuthorizationSetBuilder& Authorization(TypedTag ttag, const char* data, - size_t data_length) { - return Authorization(ttag, reinterpret_cast(data), data_length); - } - - AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& EcdsaKey(uint32_t key_size); - AuthorizationSetBuilder& AesKey(uint32_t key_size); - AuthorizationSetBuilder& HmacKey(uint32_t key_size); - - AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size); - AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size); - - AuthorizationSetBuilder& SigningKey(); - AuthorizationSetBuilder& EncryptionKey(); - AuthorizationSetBuilder& NoDigestOrPadding(); - AuthorizationSetBuilder& EcbMode(); - - AuthorizationSetBuilder& Digest(Digest digest) { return Authorization(TAG_DIGEST, digest); } - - AuthorizationSetBuilder& Padding(PaddingMode padding) { - return Authorization(TAG_PADDING, padding); - } -}; - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size, - uint64_t public_exponent) { - Authorization(TAG_ALGORITHM, Algorithm::RSA); - Authorization(TAG_KEY_SIZE, key_size); - Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent); - return *this; -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::EC); - Authorization(TAG_KEY_SIZE, key_size); - return *this; -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::AES); - return Authorization(TAG_KEY_SIZE, key_size); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::HMAC); - Authorization(TAG_KEY_SIZE, key_size); - return SigningKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size, - uint64_t public_exponent) { - RsaKey(key_size, public_exponent); - return SigningKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, - uint64_t public_exponent) { - RsaKey(key_size, public_exponent); - return EncryptionKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) { - EcdsaKey(key_size); - return SigningKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) { - AesKey(key_size); - return EncryptionKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() { - Authorization(TAG_PURPOSE, KeyPurpose::SIGN); - return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() { - Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT); - return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() { - Authorization(TAG_DIGEST, Digest::NONE); - return Authorization(TAG_PADDING, PaddingMode::NONE); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() { - return Authorization(TAG_BLOCK_MODE, BlockMode::ECB); -} - -} // namespace keystore - -#endif // SYSTEM_VOLD_AUTHORIZATION_SET_H_ diff --git a/keymaster_tags.h b/keymaster_tags.h deleted file mode 100644 index c89354d..0000000 --- a/keymaster_tags.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright 2014 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 SYSTEM_VOLD_KEYMASTER_TAGS_H_ -#define SYSTEM_VOLD_KEYMASTER_TAGS_H_ - -/** - * This header contains various definitions that make working with keymaster tags safer and easier. - * - * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose - * of making it impossible to make certain classes of mistakes when operating on keymaster - * authorizations. For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE - * and then to assign Algorithm::RSA to algorithm element of its union. But because the user - * must choose the union field, there could be a mismatch which the compiler has now way to - * diagnose. - * - * The machinery in this header solves these problems by describing which union field corresponds - * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a - * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG, - * we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal. - * - * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance - * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag - * to its value c++ type and the correct union element of KeyParameter. This is done by means of - * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping - * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a - * reference to the correct element of KeyParameter. - * E.g.: - * given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)" - * yields a reference to param.f.purpose - * If used in an assignment the compiler can now check the compatibility of the assigned value. - * - * For convenience we also provide the constructor like function Authorization(). - * Authorization takes a typed tag and a value and checks at compile time whether the value given - * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the - * given tag and value and returns it by value. - * - * The second convenience function, authorizationValue, allows access to the KeyParameter value in - * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped - * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped - * reference. - * E.g.: - * auto param = Authorization(TAG_ALGORITM, Algorithm::RSA); - * auto value1 = authorizationValue(TAG_PURPOSE, param); - * auto value2 = authorizationValue(TAG_ALGORITM, param); - * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access. - */ - -#include -#include -#include - -namespace keystore { - -using ::android::hardware::keymaster::V3_0::Algorithm; -using ::android::hardware::keymaster::V3_0::BlockMode; -using ::android::hardware::keymaster::V3_0::Digest; -using ::android::hardware::keymaster::V3_0::EcCurve; -using ::android::hardware::keymaster::V3_0::ErrorCode; -using ::android::hardware::keymaster::V3_0::HardwareAuthToken; -using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType; -using ::android::hardware::keymaster::V3_0::IKeymasterDevice; -using ::android::hardware::keymaster::V3_0::KeyBlobUsageRequirements; -using ::android::hardware::keymaster::V3_0::KeyCharacteristics; -using ::android::hardware::keymaster::V3_0::KeyDerivationFunction; -using ::android::hardware::keymaster::V3_0::KeyFormat; -using ::android::hardware::keymaster::V3_0::KeyOrigin; -using ::android::hardware::keymaster::V3_0::KeyParameter; -using ::android::hardware::keymaster::V3_0::KeyPurpose; -using ::android::hardware::keymaster::V3_0::PaddingMode; -using ::android::hardware::keymaster::V3_0::Tag; -using ::android::hardware::keymaster::V3_0::TagType; - -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; - -// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We -// need these old values to be able to support old keys that use them. -static const int32_t KM_TAG_DIGEST_OLD = static_cast(TagType::ENUM) | 5; -static const int32_t KM_TAG_PADDING_OLD = static_cast(TagType::ENUM) | 7; - -constexpr TagType typeFromTag(Tag tag) { - return static_cast(static_cast(tag) & static_cast(0xf0000000)); -} - -/** - * TypedTag is a templatized version of Tag, which provides compile-time checking of - * keymaster tag types. Instances are convertible to Tag, so they can be used wherever - * Tag is expected, and because they encode the tag type it's possible to create - * function overloads that only operate on tags with a particular type. - */ -template -struct TypedTag { - inline TypedTag() { - // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type - // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile - // error (no match for template specialization StaticAssert), with no run-time cost. - static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type"); - } - operator Tag() const { return tag; } -}; - -template -struct Tag2TypedTag { - typedef TypedTag type; -}; - -template -struct Tag2String; - -#define _TAGS_STRINGIFY(x) #x -#define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x) - -#define DECLARE_TYPED_TAG(name) \ - typedef typename Tag2TypedTag::type TAG_##name##_t; \ - extern TAG_##name##_t TAG_##name; \ - template <> \ - struct Tag2String { \ - static const char* value() { return "Tag::" TAGS_STRINGIFY(name); } \ - } - -DECLARE_TYPED_TAG(INVALID); -DECLARE_TYPED_TAG(KEY_SIZE); -DECLARE_TYPED_TAG(MAC_LENGTH); -DECLARE_TYPED_TAG(CALLER_NONCE); -DECLARE_TYPED_TAG(MIN_MAC_LENGTH); -DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT); -DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE); -DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID); -DECLARE_TYPED_TAG(ACTIVE_DATETIME); -DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME); -DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME); -DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS); -DECLARE_TYPED_TAG(MAX_USES_PER_BOOT); -DECLARE_TYPED_TAG(ALL_USERS); -DECLARE_TYPED_TAG(USER_ID); -DECLARE_TYPED_TAG(USER_SECURE_ID); -DECLARE_TYPED_TAG(NO_AUTH_REQUIRED); -DECLARE_TYPED_TAG(AUTH_TIMEOUT); -DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY); -DECLARE_TYPED_TAG(ALL_APPLICATIONS); -DECLARE_TYPED_TAG(APPLICATION_ID); -DECLARE_TYPED_TAG(APPLICATION_DATA); -DECLARE_TYPED_TAG(CREATION_DATETIME); -DECLARE_TYPED_TAG(ROLLBACK_RESISTANT); -DECLARE_TYPED_TAG(ROOT_OF_TRUST); -DECLARE_TYPED_TAG(ASSOCIATED_DATA); -DECLARE_TYPED_TAG(NONCE); -DECLARE_TYPED_TAG(AUTH_TOKEN); -DECLARE_TYPED_TAG(BOOTLOADER_ONLY); -DECLARE_TYPED_TAG(OS_VERSION); -DECLARE_TYPED_TAG(OS_PATCHLEVEL); -DECLARE_TYPED_TAG(UNIQUE_ID); -DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE); -DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID); -DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION); - -DECLARE_TYPED_TAG(PURPOSE); -DECLARE_TYPED_TAG(ALGORITHM); -DECLARE_TYPED_TAG(BLOCK_MODE); -DECLARE_TYPED_TAG(DIGEST); -DECLARE_TYPED_TAG(PADDING); -DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS); -DECLARE_TYPED_TAG(ORIGIN); -DECLARE_TYPED_TAG(USER_AUTH_TYPE); -DECLARE_TYPED_TAG(KDF); -DECLARE_TYPED_TAG(EC_CURVE); - -template -struct MetaList {}; - -using all_tags_t = MetaList< - TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t, - TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t, - TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, - TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t, - TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t, - TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, - TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, - TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, - TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t, - TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t, - TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>; - -/* implementation in keystore_utils.cpp */ -extern const char* stringifyTag(Tag tag); - -template -struct TypedTag2ValueType; - -#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \ - template \ - struct TypedTag2ValueType> { \ - typedef decltype(static_cast(nullptr)->field_name) type; \ - }; \ - template \ - inline auto accessTagValue(TypedTag, const KeyParameter& param) \ - ->const decltype(param.field_name)& { \ - return param.field_name; \ - } \ - template \ - inline auto accessTagValue(TypedTag, KeyParameter& param) \ - ->decltype(param.field_name)& { \ - return param.field_name; \ - } - -MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger) -MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger) -MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime) -MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer) -MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer) -MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue) -MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob) -MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob) - -#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \ - template <> \ - struct TypedTag2ValueType { \ - typedef decltype(static_cast(nullptr)->field_name) type; \ - }; \ - inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \ - ->const decltype(param.field_name)& { \ - return param.field_name; \ - } \ - inline auto accessTagValue(decltype(typed_tag), KeyParameter& param) \ - ->decltype(param.field_name)& { \ - return param.field_name; \ - } - -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType) - -template -inline KeyParameter makeKeyParameter(TypedTag ttag, ValueT&& value) { - KeyParameter param; - param.tag = tag; - param.f.longInteger = 0; - accessTagValue(ttag, param) = std::forward(value); - return param; -} - -// the boolean case -template -inline KeyParameter makeKeyParameter(TypedTag) { - KeyParameter param; - param.tag = tag; - param.f.boolValue = true; - return param; -} - -template -struct FirstOrNoneHelper; -template -struct FirstOrNoneHelper { - typedef First type; -}; -template <> -struct FirstOrNoneHelper<> { - struct type {}; -}; - -template -using FirstOrNone = typename FirstOrNoneHelper::type; - -template -inline KeyParameter Authorization(TypedTag ttag, Args&&... args) { - static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0), - "TagType::BOOL Authorizations do not take parameters. Presence is truth."); - static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1), - "Authorization other then TagType::BOOL take exactly one parameter."); - static_assert( - tag_type == TagType::BOOL || - std::is_convertible>>, - typename TypedTag2ValueType>::type>::value, - "Invalid argument type for given tag."); - - return makeKeyParameter(ttag, std::forward(args)...); -} - -/** - * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out - * of band. Note that if the wrapped value is a reference it is unsafe to access the value if - * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the - * wrapped value. In this case the pointer will be NULL though, and the value will be default - * constructed. - */ -template -class NullOr { - template - struct reference_initializer { - static T&& init() { return *static_cast*>(nullptr); } - }; - template - struct pointer_initializer { - static T init() { return nullptr; } - }; - template - struct value_initializer { - static T init() { return T(); } - }; - template - using initializer_t = std::conditional_t< - std::is_lvalue_reference::value, reference_initializer, - std::conditional_t::value, pointer_initializer, value_initializer>>; - - public: - NullOr() : value_(initializer_t::init()), null_(true) {} - NullOr(ValueT&& value) : value_(std::forward(value)), null_(false) {} - - bool isOk() const { return !null_; } - - const ValueT& value() const & { return value_; } - ValueT& value() & { return value_; } - ValueT&& value() && { return std::move(value_); } - - private: - ValueT value_; - bool null_; -}; - -template -std::remove_reference_t NullOrOr(T&& v) { - if (v.isOk()) return v; - return {}; -} - -template -std::remove_reference_t NullOrOr(Head&& head, Tail&&... tail) { - if (head.isOk()) return head; - return NullOrOr(std::forward(tail)...); -} - -template -std::remove_reference_t defaultOr(NullOr&& optional, Default&& def) { - static_assert( - std::is_convertible, std::remove_reference_t>::value, - "Type of default value must match the type wrapped by NullOr"); - if (optional.isOk()) return optional.value(); - return def; -} - -template -inline NullOr>::type&> authorizationValue( - TypedTag ttag, const KeyParameter& param) { - if (tag != param.tag) return {}; - return accessTagValue(ttag, param); -} - -} // namespace keystore - -#endif // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_ diff --git a/keystore_hidl_support.h b/keystore_hidl_support.h deleted file mode 100644 index d21e02a..0000000 --- a/keystore_hidl_support.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - ** - ** Copyright 2016, 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 SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_ -#define SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_ - -#include -#include -#include - -#include - -#include "keymaster_tags.h" - -namespace keystore { - -inline static std::ostream& formatArgs(std::ostream& out) { - return out; -} - -template -inline static std::ostream& formatArgs(std::ostream& out, First&& first, Args&&... args) { - out << first; - return formatArgs(out, args...); -} - -template -inline static std::string argsToString(Args&&... args) { - std::stringstream s; - formatArgs(s, args...); - return s.str(); -} - -template -inline static ErrorCode ksHandleHidlError(const Return& error, Msgs&&... msgs) { - if (!error.isOk()) { - ALOGE("HIDL call failed with %s @ %s", error.description().c_str(), - argsToString(msgs...).c_str()); - return ErrorCode::UNKNOWN_ERROR; - } - return ErrorCode(error); -} -template -inline static ErrorCode ksHandleHidlError(const Return& error, Msgs&&... msgs) { - if (!error.isOk()) { - ALOGE("HIDL call failed with %s @ %s", error.description().c_str(), - argsToString(msgs...).c_str()); - return ErrorCode::UNKNOWN_ERROR; - } - return ErrorCode::OK; -} - -#define KS_HANDLE_HIDL_ERROR(rc) \ - ::keystore::ksHandleHidlError(rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__) - -inline static hidl_vec blob2hidlVec(const uint8_t* data, const size_t length, - bool inPlace = true) { - hidl_vec result; - if (inPlace) - result.setToExternal(const_cast(data), length); - else { - result.resize(length); - memcpy(&result[0], data, length); - } - return result; -} - -inline static hidl_vec blob2hidlVec(const std::string& value) { - hidl_vec result; - result.setToExternal( - reinterpret_cast(const_cast(value.data())), - static_cast(value.size())); - return result; -} - -inline static hidl_vec blob2hidlVec(const std::vector& blob) { - hidl_vec result; - result.setToExternal(const_cast(blob.data()), static_cast(blob.size())); - return result; -} - -template -inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) { - const uint8_t* value_ptr = reinterpret_cast(&value); - return std::copy(value_ptr, value_ptr + sizeof(value), dest); -} - -inline std::string hidlVec2String(const hidl_vec& value) { - return std::string(reinterpret_cast(&value[0]), value.size()); -} - -} // namespace keystore - -#endif // SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_ From 772cc85d712dd36e1a328bf6d2518103e1763f07 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Thu, 1 Feb 2018 09:53:27 -0800 Subject: [PATCH 069/106] Refactor logging in EncryptInplace.cpp Done as part of work towards metadata encryption. Bug: 63927601 Test: Boot Taimen to SUW Change-Id: I0f5fda0e002944ab658756c7cfcb386c3658a446 --- EncryptInplace.cpp | 175 ++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 98 deletions(-) diff --git a/EncryptInplace.cpp b/EncryptInplace.cpp index 16a108c..45734a8 100644 --- a/EncryptInplace.cpp +++ b/EncryptInplace.cpp @@ -29,9 +29,8 @@ #include -#include "cutils/properties.h" -#define LOG_TAG "EncryptInplace" -#include "cutils/log.h" +#include +#include // HORRIBLE HACK, FIXME #include "cryptfs.h" @@ -93,13 +92,13 @@ static void update_progress(struct encryptGroupsData* data, int is_used) 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 @@ -114,7 +113,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; } } @@ -130,15 +129,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 @@ -153,21 +150,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); @@ -189,18 +181,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, @@ -211,7 +203,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; } @@ -259,13 +251,9 @@ 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) { u32 i; struct encryptGroupsData data; int rc; // Can't initialize without causing warning -Wclobbered @@ -273,7 +261,7 @@ 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; } @@ -282,8 +270,7 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev, data.crypto_blkdev = crypto_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; } @@ -291,25 +278,25 @@ static int cryptfs_enable_inplace_ext4(char *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; } @@ -318,7 +305,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) { @@ -329,7 +316,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; @@ -337,7 +324,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; } @@ -360,13 +347,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 @@ -385,12 +372,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); @@ -399,18 +388,14 @@ 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) { 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)); @@ -419,13 +404,12 @@ static int cryptfs_enable_inplace_f2fs(char *crypto_blkdev, 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; } @@ -447,7 +431,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; } @@ -457,7 +441,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; } @@ -466,8 +450,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); @@ -478,11 +461,9 @@ 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) { int realfd, cryptofd; char *buf[CRYPT_INPLACE_BUFSIZE]; int rc = ENABLE_INPLACE_ERR_OTHER; @@ -491,13 +472,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; } @@ -512,32 +492,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; } } @@ -551,33 +531,34 @@ static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev, 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 cur_pct) { + if (set_progress_properties && new_pct > cur_pct) { char buf[8]; cur_pct = new_pct; @@ -575,13 +585,17 @@ 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) { + 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) { 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; } @@ -590,30 +604,33 @@ int cryptfs_enable_inplace(char* crypto_blkdev, char* real_blkdev, off64_t size, * 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; } 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; } 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); + 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; } diff --git a/EncryptInplace.h b/EncryptInplace.h index de5a1c5..71644ac 100644 --- a/EncryptInplace.h +++ b/EncryptInplace.h @@ -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 diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 24047f9..4a847e3 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -31,8 +31,9 @@ #include #include +#include #include -#include +#include #include #include "EncryptInplace.h" @@ -71,26 +72,17 @@ 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_default); - 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: " << key; + if (!fs_mkdirs(dir.c_str(), 0700)) { + PLOG(ERROR) << "Creating directories: " << dir; + } auto temp = key_dir + "/tmp"; if (!android::vold::retrieveKey(create_if_absent, dir, temp, key)) return false; return true; @@ -103,7 +95,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; } @@ -211,108 +202,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_default); - 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_default); + 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(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(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(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(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; } diff --git a/MetadataCrypt.h b/MetadataCrypt.h index f6634ea..841dc97 100644 --- a/MetadataCrypt.h +++ b/MetadataCrypt.h @@ -17,7 +17,8 @@ #ifndef _METADATA_CRYPT_H #define _METADATA_CRYPT_H -bool e4crypt_mount_metadata_encrypted(); -bool e4crypt_enable_crypto(); +#include + +bool e4crypt_mount_metadata_encrypted(const std::string& mount_point, bool needs_encrypt); #endif diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index f7637fd..f4961ce 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -247,16 +247,6 @@ binder::Status VoldNativeService::shutdown() { return translate(VolumeManager::Instance()->shutdown()); } -binder::Status VoldNativeService::mountAll() { - ENFORCE_UID(AID_SYSTEM); - ACQUIRE_LOCK; - - struct fstab* fstab = fs_mgr_read_fstab_default(); - int res = fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT); - fs_mgr_free_fstab(fstab); - return translate(res); -} - binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; @@ -577,12 +567,12 @@ binder::Status VoldNativeService::fdeEnable(int32_t passwordType, ENFORCE_UID(AID_SYSTEM); ACQUIRE_CRYPT_LOCK; + LOG(DEBUG) << "fdeEnable(" << passwordType << ", *, " << encryptionFlags << ")"; if (e4crypt_is_native()) { - if (passwordType != PASSWORD_TYPE_DEFAULT) { - return error("Unexpected password type"); - } - return translateBool(e4crypt_enable_crypto()); + 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. @@ -665,14 +655,12 @@ binder::Status VoldNativeService::mountDefaultEncrypted() { ENFORCE_UID(AID_SYSTEM); ACQUIRE_CRYPT_LOCK; - if (e4crypt_is_native()) { - return translateBool(e4crypt_mount_metadata_encrypted()); - } else { + 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(); } + return ok(); } binder::Status VoldNativeService::initUser0() { @@ -690,6 +678,20 @@ binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) { 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); diff --git a/VoldNativeService.h b/VoldNativeService.h index 1359d90..817f815 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -36,7 +36,6 @@ public: binder::Status monitor(); binder::Status reset(); binder::Status shutdown(); - binder::Status mountAll(); binder::Status onUserAdded(int32_t userId, int32_t userSerial); binder::Status onUserRemoved(int32_t userId); @@ -96,6 +95,8 @@ public: 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); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 9facaf7..a664dfa 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -26,7 +26,6 @@ interface IVold { void monitor(); void reset(); void shutdown(); - void mountAll(); void onUserAdded(int userId, int userSerial); void onUserRemoved(int userId); @@ -79,6 +78,8 @@ interface IVold { 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); diff --git a/cryptfs.cpp b/cryptfs.cpp index aa60541..e363835 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1974,7 +1974,7 @@ static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr* crypt_ftr, char* cry tot_encryption_size = crypt_ftr->fs_size; rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, crypt_ftr->fs_size, &cur_encryption_done, - tot_encryption_size, previously_encrypted_upto); + tot_encryption_size, previously_encrypted_upto, true); if (rc == ENABLE_INPLACE_ERR_DEV) { /* Hack for b/17898962 */ diff --git a/main.cpp b/main.cpp index 62ea6b7..5525e85 100644 --- a/main.cpp +++ b/main.cpp @@ -51,12 +51,14 @@ 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(INFO) << "Vold 3.0 (the awakening) firing up"; LOG(VERBOSE) << "Detected support for:" << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "") @@ -113,6 +115,8 @@ int main(int argc, char** argv) { } ATRACE_END(); + LOG(DEBUG) << "VoldNativeService::start() completed OK"; + ATRACE_BEGIN("NetlinkManager::start"); if (nm->start()) { PLOG(ERROR) << "Unable to start NetlinkManager"; diff --git a/vdc.cpp b/vdc.cpp index 5ae4cd9..3c449ae 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -44,7 +44,7 @@ static android::sp getServiceAggressive() { android::sp res; auto sm = android::defaultServiceManager(); auto name = android::String16("vold"); - for (int i = 0; i < 500; i++) { + for (int i = 0; i < 5000; i++) { res = sm->checkService(name); if (res) { LOG(VERBOSE) << "Waited " << (i * 10) << "ms for vold"; @@ -101,6 +101,10 @@ int main(int argc, char** argv) { 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 { LOG(ERROR) << "Raw commands are no longer supported"; exit(EINVAL); From 3e02df8d3c1d75db8cafdf5cd69fd81a19e98e1f Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Wed, 7 Feb 2018 15:06:06 -0700 Subject: [PATCH 071/106] Prevent spurious call to keymaster abort(). During the analysis of b/72953784 it was noticed that vold was calling keymaster abort() and failing, though vold was succeeding with its keymaster operation. This had nothing to do with the bug, but the presence of the error appeared to implicate keymaster, and it's bad form in any case. This CL correctly clears the mDevice member during a move, so the destructor will not attempt to call abort. Test: Build & boot Bug: 72953784 Change-Id: Ib0700f829e87f19b089396087085585ddd6b96a5 --- Keymaster.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Keymaster.h b/Keymaster.h index 0bda8cd..7571402 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -66,11 +66,15 @@ class KeymasterOperation { 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 = km::ErrorCode::UNKNOWN_ERROR; + mDevice = rhs.mDevice; + rhs.mDevice = nullptr; + + mOpHandle = rhs.mOpHandle; rhs.mOpHandle = 0; + + mError = rhs.mError; + rhs.mError = km::ErrorCode::UNKNOWN_ERROR; + return *this; } From 026072f81b9bf12a14b514f8c00b4cdb9d8b3698 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 9 Feb 2018 09:15:50 -0800 Subject: [PATCH 072/106] cryptfs: Remove unused variable We'll be allowing modifyable key sizes in the near future, and want to remove this variable to reduce confusion with this change. Bug: 73079191 Test: None Change-Id: I7047bb375553d8c46ff0724add697a5105ebc68c --- cryptfs.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index e363835..4e163bc 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1056,7 +1056,6 @@ static int scrypt(const char *passwd, const unsigned char *salt, int p = 1 << ftr->p_factor; /* Turn the password into a key and IV that can decrypt the master key */ - unsigned int keysize; crypto_scrypt((const uint8_t*)passwd, strlen(passwd), salt, SALT_LEN, N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES); From b610e77fd24f9cb8beceff9c9bd4328e5a8b6e77 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 9 Feb 2018 09:19:54 -0800 Subject: [PATCH 073/106] cryptfs: Fix format string Test: None Change-Id: Id16acb4ed5e89e759b69ec2d2f2db54cc54f1959 --- cryptfs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 4e163bc..8ffe1a7 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -2685,7 +2685,7 @@ int cryptfs_setfield(const char *fieldname, const char *value) } for (field_id = 1; field_id < num_entries; field_id++) { - snprintf(temp_field, sizeof(temp_field), "%s_%d", fieldname, field_id); + snprintf(temp_field, sizeof(temp_field), "%s_%u", fieldname, field_id); if (persist_set_key(temp_field, value + field_id * (PROPERTY_VALUE_MAX - 1), encrypted)) { // fail to set key, should not happen as we have already checked the available space. From f45a70c416e74437bfc10e7a1dab55746f3edf25 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 9 Feb 2018 13:41:12 -0800 Subject: [PATCH 074/106] cryptfs: Don't hardcode ikey buffer size We were hardcoding the size of the ikey buffer, but then had logic which used KEY_LEN_BYTES and IV_LEN_BYTES to offset into the array and describe the length of its contents. In anticipation of allowing the keysize to be set via a property, instead of at compile time, we change this code to make the relation between the keysize and the buffer size explicit. Bug: 73079191 Test: Flashed an encrypted sailfish and it booted. Change-Id: I109a5dc812662220e53163bfb4b5e51bf5abf185 --- cryptfs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 8ffe1a7..ebc4c4a 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1109,7 +1109,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, unsigned char *encrypted_master_key, struct crypt_mnt_ftr *crypt_ftr) { - unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */ + unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 }; EVP_CIPHER_CTX e_ctx; int encrypted_len, final_len; int rc = 0; @@ -1196,7 +1196,7 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, unsigned char** intermediate_key, size_t* intermediate_key_size) { - unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */ + unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 }; EVP_CIPHER_CTX d_ctx; int decrypted_len, final_len; From 1452b27d4e445d71863d2bc2afce2825b9f68f13 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 9 Feb 2018 16:11:38 -0800 Subject: [PATCH 075/106] cryptfs: Don't hardcode ascii buffer size We're removing hardcoded buffer sizes in anticipation of allowing different keysizes. In this case, our buffer was sufficiently large for all current cases. But if we ever changed the crypt_mnt_ftr struct to allow larger keys, this code will adjust with the change. Bug: 73079191 Test: Flashed an encrypted sailfish and it booted. Change-Id: I261e729a77b351e287fbb55327564fe512a23d47 --- cryptfs.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index ebc4c4a..1d21124 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -846,7 +846,10 @@ static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, struct dm_ioctl *io; struct dm_target_spec *tgt; char *crypt_params; - char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */ + // We can't assume the key is only KEY_LEN_BYTES. But we do know its limit + // due to the crypt_mnt_ftr struct. We need two ASCII characters to represent + // each byte, and need space for the '\0' terminator. + char master_key_ascii[sizeof(crypt_ftr->master_key) * 2 + 1]; size_t buff_offset; int i; From 4a35ef0a53d1f8041adc8bf49585e700bb7af803 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 9 Feb 2018 17:01:06 -0800 Subject: [PATCH 076/106] cryptfs: Make decrypted key buffers large enough Looking at the EVP_DecryptUpdate() documentation, we need a buffer which isn't just the keysize, but also provides the cipher block length minus one byte extra. For EVP_aes_128_cbc(), that block length is 16, but we use the maximum block length to be safe for any future cipher change. For two of our decrypted_master_key usages, the buffer was already sufficiently sized. But for one of our instances, in cryptfs_enable_internal(), the buffer was previously smaller than this. So this CL represents a possible behavior change if we were ever overrunning that buffer. Bug: 73079191, 73176599 Test: Flashed an encrypted sailfish and it booted. Change-Id: Ic5043340910dc7d625e6e5baedbca5bd4b2bfb03 --- cryptfs.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 1d21124..f500a15 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -98,6 +98,11 @@ extern "C" { #define CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE (1) +// EVP_DecryptUpdate() requires not just our key length, but up to +// block length - 1 additional bytes for its work. We provide a buffer +// size that will work for all possible ciphers. +#define DECRYPTED_MASTER_KEY_BUF_SIZE (KEY_LEN_BYTES + EVP_MAX_BLOCK_LENGTH - 1) + static int put_crypt_ftr_and_key(struct crypt_mnt_ftr* crypt_ftr); static unsigned char saved_master_key[KEY_LEN_BYTES]; @@ -1595,8 +1600,7 @@ static int do_crypto_complete(const char *mount_point) static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, const char *passwd, const char *mount_point, const char *label) { - /* Allocate enough space for a 256 bit key, but we may use less */ - unsigned char decrypted_master_key[32]; + unsigned char decrypted_master_key[DECRYPTED_MASTER_KEY_BUF_SIZE]; char crypto_blkdev[MAXPATHLEN]; char real_blkdev[MAXPATHLEN]; char tmp_mount_point[64]; @@ -1853,8 +1857,7 @@ int cryptfs_check_passwd(const char *passwd) int cryptfs_verify_passwd(const char *passwd) { struct crypt_mnt_ftr crypt_ftr; - /* Allocate enough space for a 256 bit key, but we may use less */ - unsigned char decrypted_master_key[32]; + unsigned char decrypted_master_key[DECRYPTED_MASTER_KEY_BUF_SIZE]; char encrypted_state[PROPERTY_VALUE_MAX]; int rc; @@ -2004,7 +2007,7 @@ static int vold_unmountAll(void) { int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN]; - unsigned char decrypted_master_key[KEY_LEN_BYTES]; + unsigned char decrypted_master_key[DECRYPTED_MASTER_KEY_BUF_SIZE]; int rc=-1, i; struct crypt_mnt_ftr crypt_ftr; struct crypt_persist_data *pdata; From 291fec178925fe7cd724b3d345bfcfbb98d87f52 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 9 Feb 2018 18:24:59 -0800 Subject: [PATCH 077/106] cryptfs: Optionally get crypt type from properties Instead of hardcoding to "aes-cbc-essiv:sha256", we introduce a new property, "ro.crypto.crypt_type_name", to allow the use of different crypt methods. The only other method we currently support is "speck128-xts-plain64", although new methods are easily added. We intentionally derive things like the keysize from the given crypt name, to reduce exploit vectors. We also only accept crypt names the code has whitelisted. The biggest impact is replacing the hard-coded KEY_LEN_BYTES. For compile-time buffers, we use the MAX_KEY_LEN to assure they will be big enough for any crypt type. For run-time sizing, we use the value derived from our property. Bug: 73079191 Test: On an encrypted gobo, booted successfully with (1) no property set, (2) proproperty set to invalid value (and confirmed we defaulted to aes), and (3) after wiping userdata, with property set to "speck128-xts-plain64", confirmed we were using SPECK. Change-Id: Ic4e10840d6ee2a4d4df58582448e0f768e6f403f --- cryptfs.cpp | 145 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 116 insertions(+), 29 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index f500a15..234899e 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -72,7 +72,6 @@ extern "C" { #define DM_CRYPT_BUF_SIZE 4096 #define HASH_COUNT 2000 -#define KEY_LEN_BYTES 16 #define IV_LEN_BYTES 16 #define KEY_IN_FOOTER "footer" @@ -101,11 +100,11 @@ extern "C" { // EVP_DecryptUpdate() requires not just our key length, but up to // block length - 1 additional bytes for its work. We provide a buffer // size that will work for all possible ciphers. -#define DECRYPTED_MASTER_KEY_BUF_SIZE (KEY_LEN_BYTES + EVP_MAX_BLOCK_LENGTH - 1) +#define DECRYPTED_MASTER_KEY_BUF_SIZE (MAX_KEY_LEN + EVP_MAX_BLOCK_LENGTH - 1) static int put_crypt_ftr_and_key(struct crypt_mnt_ftr* crypt_ftr); -static unsigned char saved_master_key[KEY_LEN_BYTES]; +static unsigned char saved_master_key[MAX_KEY_LEN]; static char *saved_mount_point; static int master_key_saved = 0; static struct crypt_persist_data *persist_data = NULL; @@ -260,6 +259,94 @@ static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, u } } +namespace { + +struct CryptType; + +// Use to get the CryptType in use on this device. +const CryptType &get_crypt_type(); + +struct CryptType { + const char * name; + __le32 keysize; + + constexpr CryptType(const char *n, size_t size) : name(n), keysize(size) {} + + private: + friend const CryptType &get_crypt_type(); + static const CryptType &get_device_crypt_name(); +}; + +// We only want to parse this read-only property once. But we need to wait +// until the system is initialized before we can read it. So we use a static +// scoped within this function to get it only once. +const CryptType &get_crypt_type() { + static CryptType crypt_type = CryptType::get_device_crypt_name(); + return crypt_type; +} + +__le32 get_keysize() { + return get_crypt_type().keysize; +} + +const char *get_crypt_name() { + return get_crypt_type().name; +} + + + +constexpr CryptType default_crypt_type = CryptType("aes-cbc-essiv:sha256", 16); + +constexpr CryptType supported_crypt_types[] = { + default_crypt_type, + CryptType("speck128-xts-plain64", 32), + // Add new CryptTypes here. Order is not important. +}; + + +// ---------- START COMPILE-TIME SANITY CHECK BLOCK ------------------------- +// We confirm all supported_crypt_types have a small enough keysize. + +template +constexpr size_t array_length(T (&)[N]) { return N; } + +constexpr bool indexOutOfBoundsForCryptTypes(size_t index) { + return (index >= array_length(supported_crypt_types)); +} + +// Note in C++11 that constexpr functions can only have a single line. +// So our code is a bit convoluted (using recursion instead of a loop), +// but it's asserting at compile time that all of our key lengths are valid. +constexpr bool validateSupportedCryptTypes(size_t index) { + return indexOutOfBoundsForCryptTypes(index) || + ((supported_crypt_types[index].keysize <= MAX_KEY_LEN) && + validateSupportedCryptTypes(index + 1)); +} + +static_assert(validateSupportedCryptTypes(0), + "We have a CryptType with keysize > MAX_KEYSIZE"); +// ---------- END COMPILE-TIME SANITY CHECK BLOCK ------------------------- + + +// Don't call this directly, use get_crypt_type(), which caches this result. +const CryptType &CryptType::get_device_crypt_name() { + constexpr char CRYPT_TYPE_PROP[] = "ro.crypto.crypt_type_name"; + char paramstr[PROPERTY_VALUE_MAX]; + + property_get(CRYPT_TYPE_PROP, paramstr, default_crypt_type.name); + for (auto const &ctype : supported_crypt_types) { + if (strcmp(paramstr, ctype.name) == 0) { + return ctype; + } + } + ALOGE("Invalid name (%s) for %s. Defaulting to %s\n", paramstr, + CRYPT_TYPE_PROP, default_crypt_type.name); + return default_crypt_type; +} + +} // namespace + + /** * Gets the default device scrypt parameters for key derivation time tuning. * The parameters should lead to about one second derivation time for the @@ -851,7 +938,7 @@ static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, struct dm_ioctl *io; struct dm_target_spec *tgt; char *crypt_params; - // We can't assume the key is only KEY_LEN_BYTES. But we do know its limit + // We can't assume the key is only get_keysize(). But we do know its limit // due to the crypt_mnt_ftr struct. We need two ASCII characters to represent // each byte, and need space for the '\0' terminator. char master_key_ascii[sizeof(crypt_ftr->master_key) * 2 + 1]; @@ -1048,7 +1135,7 @@ static int pbkdf2(const char *passwd, const unsigned char *salt, /* Turn the password into a key and IV that can decrypt the master key */ return PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, SALT_LEN, - HASH_COUNT, KEY_LEN_BYTES + IV_LEN_BYTES, + HASH_COUNT, get_keysize() + IV_LEN_BYTES, ikey) != 1; } @@ -1066,7 +1153,7 @@ static int scrypt(const char *passwd, const unsigned char *salt, /* Turn the password into a key and IV that can decrypt the master key */ crypto_scrypt((const uint8_t*)passwd, strlen(passwd), salt, SALT_LEN, N, r, p, ikey, - KEY_LEN_BYTES + IV_LEN_BYTES); + get_keysize() + IV_LEN_BYTES); return 0; } @@ -1087,21 +1174,21 @@ static int scrypt_keymaster(const char *passwd, const unsigned char *salt, rc = crypto_scrypt((const uint8_t*)passwd, strlen(passwd), salt, SALT_LEN, N, r, p, ikey, - KEY_LEN_BYTES + IV_LEN_BYTES); + get_keysize() + IV_LEN_BYTES); if (rc) { SLOGE("scrypt failed"); return -1; } - if (keymaster_sign_object(ftr, ikey, KEY_LEN_BYTES + IV_LEN_BYTES, + if (keymaster_sign_object(ftr, ikey, get_keysize() + IV_LEN_BYTES, &signature, &signature_size)) { SLOGE("Signing failed"); return -1; } rc = crypto_scrypt(signature, signature_size, salt, SALT_LEN, - N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES); + N, r, p, ikey, get_keysize() + IV_LEN_BYTES); free(signature); if (rc) { @@ -1117,7 +1204,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, unsigned char *encrypted_master_key, struct crypt_mnt_ftr *crypt_ftr) { - unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 }; + unsigned char ikey[MAX_KEY_LEN+IV_LEN_BYTES] = { 0 }; EVP_CIPHER_CTX e_ctx; int encrypted_len, final_len; int rc = 0; @@ -1152,7 +1239,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, /* Initialize the decryption engine */ EVP_CIPHER_CTX_init(&e_ctx); - if (! EVP_EncryptInit_ex(&e_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+KEY_LEN_BYTES)) { + if (! EVP_EncryptInit_ex(&e_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+get_keysize())) { SLOGE("EVP_EncryptInit failed\n"); return -1; } @@ -1160,7 +1247,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, /* Encrypt the master key */ if (! EVP_EncryptUpdate(&e_ctx, encrypted_master_key, &encrypted_len, - decrypted_master_key, KEY_LEN_BYTES)) { + decrypted_master_key, get_keysize())) { SLOGE("EVP_EncryptUpdate failed\n"); return -1; } @@ -1169,7 +1256,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, return -1; } - if (encrypted_len + final_len != KEY_LEN_BYTES) { + if (encrypted_len + final_len != static_cast(get_keysize())) { SLOGE("EVP_Encryption length check failed with %d, %d bytes\n", encrypted_len, final_len); return -1; } @@ -1183,7 +1270,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, int r = 1 << crypt_ftr->r_factor; int p = 1 << crypt_ftr->p_factor; - rc = crypto_scrypt(ikey, KEY_LEN_BYTES, + rc = crypto_scrypt(ikey, get_keysize(), crypt_ftr->salt, sizeof(crypt_ftr->salt), N, r, p, crypt_ftr->scrypted_intermediate_key, sizeof(crypt_ftr->scrypted_intermediate_key)); @@ -1204,7 +1291,7 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, unsigned char** intermediate_key, size_t* intermediate_key_size) { - unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 }; + unsigned char ikey[MAX_KEY_LEN+IV_LEN_BYTES] = { 0 }; EVP_CIPHER_CTX d_ctx; int decrypted_len, final_len; @@ -1217,29 +1304,29 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, /* Initialize the decryption engine */ EVP_CIPHER_CTX_init(&d_ctx); - if (! EVP_DecryptInit_ex(&d_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+KEY_LEN_BYTES)) { + if (! EVP_DecryptInit_ex(&d_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+get_keysize())) { return -1; } EVP_CIPHER_CTX_set_padding(&d_ctx, 0); /* Turn off padding as our data is block aligned */ /* Decrypt the master key */ if (! EVP_DecryptUpdate(&d_ctx, decrypted_master_key, &decrypted_len, - encrypted_master_key, KEY_LEN_BYTES)) { + encrypted_master_key, get_keysize())) { return -1; } if (! EVP_DecryptFinal_ex(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) { return -1; } - if (decrypted_len + final_len != KEY_LEN_BYTES) { + if (decrypted_len + final_len != static_cast(get_keysize())) { return -1; } /* Copy intermediate key if needed by params */ if (intermediate_key && intermediate_key_size) { - *intermediate_key = (unsigned char*) malloc(KEY_LEN_BYTES); + *intermediate_key = (unsigned char*) malloc(get_keysize()); if (*intermediate_key) { - memcpy(*intermediate_key, ikey, KEY_LEN_BYTES); - *intermediate_key_size = KEY_LEN_BYTES; + memcpy(*intermediate_key, ikey, get_keysize()); + *intermediate_key_size = get_keysize(); } } @@ -1285,7 +1372,7 @@ static int decrypt_master_key(const char *passwd, unsigned char *decrypted_maste static int create_encrypted_random_key(const char *passwd, unsigned char *master_key, unsigned char *salt, struct crypt_mnt_ftr *crypt_ftr) { int fd; - unsigned char key_buf[KEY_LEN_BYTES]; + unsigned char key_buf[MAX_KEY_LEN]; /* Get some random bits for a key */ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); @@ -1683,7 +1770,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, /* Also save a the master key so we can reencrypted the key * the key when we want to change the password on it. */ - memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES); + memcpy(saved_master_key, decrypted_master_key, get_keysize()); saved_mount_point = strdup(mount_point); master_key_saved = 1; SLOGD("%s(): Master key saved\n", __FUNCTION__); @@ -1758,7 +1845,7 @@ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr)); ext_crypt_ftr.fs_size = nr_sec; ext_crypt_ftr.keysize = keysize; - strlcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", + strlcpy((char*) ext_crypt_ftr.crypto_type_name, get_crypt_name(), MAX_CRYPTO_TYPE_NAME_LEN); return create_crypto_blk_dev( @@ -1901,7 +1988,7 @@ int cryptfs_verify_passwd(const char *passwd) } /* Initialize a crypt_mnt_ftr structure. The keysize is - * defaulted to 16 bytes, and the filesystem size to 0. + * defaulted to get_keysize(), and the filesystem size to 0. * Presumably, at a minimum, the caller will update the * filesystem size and crypto_type_name after calling this function. */ @@ -1914,7 +2001,7 @@ static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr) ftr->major_version = CURRENT_MAJOR_VERSION; ftr->minor_version = CURRENT_MINOR_VERSION; ftr->ftr_size = sizeof(struct crypt_mnt_ftr); - ftr->keysize = KEY_LEN_BYTES; + ftr->keysize = get_keysize(); switch (keymaster_check_compatibility()) { case 1: @@ -2166,7 +2253,7 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; } crypt_ftr.crypt_type = crypt_type; - strlcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN); + strlcpy((char *)crypt_ftr.crypto_type_name, get_crypt_name(), MAX_CRYPTO_TYPE_NAME_LEN); /* Make an encrypted master key */ if (create_encrypted_random_key(onlyCreateHeader ? DEFAULT_PASSWORD : passwd, @@ -2177,8 +2264,8 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { /* Replace scrypted intermediate key if we are preparing for a reboot */ if (onlyCreateHeader) { - unsigned char fake_master_key[KEY_LEN_BYTES]; - unsigned char encrypted_fake_master_key[KEY_LEN_BYTES]; + unsigned char fake_master_key[MAX_KEY_LEN]; + unsigned char encrypted_fake_master_key[MAX_KEY_LEN]; memset(fake_master_key, 0, sizeof(fake_master_key)); encrypt_master_key(passwd, crypt_ftr.salt, fake_master_key, encrypted_fake_master_key, &crypt_ftr); From fa099611bf915a0e95505546a6ea69d069ea82ff Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Wed, 14 Feb 2018 11:26:00 -0800 Subject: [PATCH 078/106] Revert "cryptfs: Optionally get crypt type from properties" This reverts commit 291fec178925fe7cd724b3d345bfcfbb98d87f52. --- cryptfs.cpp | 145 +++++++++++----------------------------------------- 1 file changed, 29 insertions(+), 116 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 234899e..f500a15 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -72,6 +72,7 @@ extern "C" { #define DM_CRYPT_BUF_SIZE 4096 #define HASH_COUNT 2000 +#define KEY_LEN_BYTES 16 #define IV_LEN_BYTES 16 #define KEY_IN_FOOTER "footer" @@ -100,11 +101,11 @@ extern "C" { // EVP_DecryptUpdate() requires not just our key length, but up to // block length - 1 additional bytes for its work. We provide a buffer // size that will work for all possible ciphers. -#define DECRYPTED_MASTER_KEY_BUF_SIZE (MAX_KEY_LEN + EVP_MAX_BLOCK_LENGTH - 1) +#define DECRYPTED_MASTER_KEY_BUF_SIZE (KEY_LEN_BYTES + EVP_MAX_BLOCK_LENGTH - 1) static int put_crypt_ftr_and_key(struct crypt_mnt_ftr* crypt_ftr); -static unsigned char saved_master_key[MAX_KEY_LEN]; +static unsigned char saved_master_key[KEY_LEN_BYTES]; static char *saved_mount_point; static int master_key_saved = 0; static struct crypt_persist_data *persist_data = NULL; @@ -259,94 +260,6 @@ static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, u } } -namespace { - -struct CryptType; - -// Use to get the CryptType in use on this device. -const CryptType &get_crypt_type(); - -struct CryptType { - const char * name; - __le32 keysize; - - constexpr CryptType(const char *n, size_t size) : name(n), keysize(size) {} - - private: - friend const CryptType &get_crypt_type(); - static const CryptType &get_device_crypt_name(); -}; - -// We only want to parse this read-only property once. But we need to wait -// until the system is initialized before we can read it. So we use a static -// scoped within this function to get it only once. -const CryptType &get_crypt_type() { - static CryptType crypt_type = CryptType::get_device_crypt_name(); - return crypt_type; -} - -__le32 get_keysize() { - return get_crypt_type().keysize; -} - -const char *get_crypt_name() { - return get_crypt_type().name; -} - - - -constexpr CryptType default_crypt_type = CryptType("aes-cbc-essiv:sha256", 16); - -constexpr CryptType supported_crypt_types[] = { - default_crypt_type, - CryptType("speck128-xts-plain64", 32), - // Add new CryptTypes here. Order is not important. -}; - - -// ---------- START COMPILE-TIME SANITY CHECK BLOCK ------------------------- -// We confirm all supported_crypt_types have a small enough keysize. - -template -constexpr size_t array_length(T (&)[N]) { return N; } - -constexpr bool indexOutOfBoundsForCryptTypes(size_t index) { - return (index >= array_length(supported_crypt_types)); -} - -// Note in C++11 that constexpr functions can only have a single line. -// So our code is a bit convoluted (using recursion instead of a loop), -// but it's asserting at compile time that all of our key lengths are valid. -constexpr bool validateSupportedCryptTypes(size_t index) { - return indexOutOfBoundsForCryptTypes(index) || - ((supported_crypt_types[index].keysize <= MAX_KEY_LEN) && - validateSupportedCryptTypes(index + 1)); -} - -static_assert(validateSupportedCryptTypes(0), - "We have a CryptType with keysize > MAX_KEYSIZE"); -// ---------- END COMPILE-TIME SANITY CHECK BLOCK ------------------------- - - -// Don't call this directly, use get_crypt_type(), which caches this result. -const CryptType &CryptType::get_device_crypt_name() { - constexpr char CRYPT_TYPE_PROP[] = "ro.crypto.crypt_type_name"; - char paramstr[PROPERTY_VALUE_MAX]; - - property_get(CRYPT_TYPE_PROP, paramstr, default_crypt_type.name); - for (auto const &ctype : supported_crypt_types) { - if (strcmp(paramstr, ctype.name) == 0) { - return ctype; - } - } - ALOGE("Invalid name (%s) for %s. Defaulting to %s\n", paramstr, - CRYPT_TYPE_PROP, default_crypt_type.name); - return default_crypt_type; -} - -} // namespace - - /** * Gets the default device scrypt parameters for key derivation time tuning. * The parameters should lead to about one second derivation time for the @@ -938,7 +851,7 @@ static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, struct dm_ioctl *io; struct dm_target_spec *tgt; char *crypt_params; - // We can't assume the key is only get_keysize(). But we do know its limit + // We can't assume the key is only KEY_LEN_BYTES. But we do know its limit // due to the crypt_mnt_ftr struct. We need two ASCII characters to represent // each byte, and need space for the '\0' terminator. char master_key_ascii[sizeof(crypt_ftr->master_key) * 2 + 1]; @@ -1135,7 +1048,7 @@ static int pbkdf2(const char *passwd, const unsigned char *salt, /* Turn the password into a key and IV that can decrypt the master key */ return PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, SALT_LEN, - HASH_COUNT, get_keysize() + IV_LEN_BYTES, + HASH_COUNT, KEY_LEN_BYTES + IV_LEN_BYTES, ikey) != 1; } @@ -1153,7 +1066,7 @@ static int scrypt(const char *passwd, const unsigned char *salt, /* Turn the password into a key and IV that can decrypt the master key */ crypto_scrypt((const uint8_t*)passwd, strlen(passwd), salt, SALT_LEN, N, r, p, ikey, - get_keysize() + IV_LEN_BYTES); + KEY_LEN_BYTES + IV_LEN_BYTES); return 0; } @@ -1174,21 +1087,21 @@ static int scrypt_keymaster(const char *passwd, const unsigned char *salt, rc = crypto_scrypt((const uint8_t*)passwd, strlen(passwd), salt, SALT_LEN, N, r, p, ikey, - get_keysize() + IV_LEN_BYTES); + KEY_LEN_BYTES + IV_LEN_BYTES); if (rc) { SLOGE("scrypt failed"); return -1; } - if (keymaster_sign_object(ftr, ikey, get_keysize() + IV_LEN_BYTES, + if (keymaster_sign_object(ftr, ikey, KEY_LEN_BYTES + IV_LEN_BYTES, &signature, &signature_size)) { SLOGE("Signing failed"); return -1; } rc = crypto_scrypt(signature, signature_size, salt, SALT_LEN, - N, r, p, ikey, get_keysize() + IV_LEN_BYTES); + N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES); free(signature); if (rc) { @@ -1204,7 +1117,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, unsigned char *encrypted_master_key, struct crypt_mnt_ftr *crypt_ftr) { - unsigned char ikey[MAX_KEY_LEN+IV_LEN_BYTES] = { 0 }; + unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 }; EVP_CIPHER_CTX e_ctx; int encrypted_len, final_len; int rc = 0; @@ -1239,7 +1152,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, /* Initialize the decryption engine */ EVP_CIPHER_CTX_init(&e_ctx); - if (! EVP_EncryptInit_ex(&e_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+get_keysize())) { + if (! EVP_EncryptInit_ex(&e_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+KEY_LEN_BYTES)) { SLOGE("EVP_EncryptInit failed\n"); return -1; } @@ -1247,7 +1160,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, /* Encrypt the master key */ if (! EVP_EncryptUpdate(&e_ctx, encrypted_master_key, &encrypted_len, - decrypted_master_key, get_keysize())) { + decrypted_master_key, KEY_LEN_BYTES)) { SLOGE("EVP_EncryptUpdate failed\n"); return -1; } @@ -1256,7 +1169,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, return -1; } - if (encrypted_len + final_len != static_cast(get_keysize())) { + if (encrypted_len + final_len != KEY_LEN_BYTES) { SLOGE("EVP_Encryption length check failed with %d, %d bytes\n", encrypted_len, final_len); return -1; } @@ -1270,7 +1183,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, int r = 1 << crypt_ftr->r_factor; int p = 1 << crypt_ftr->p_factor; - rc = crypto_scrypt(ikey, get_keysize(), + rc = crypto_scrypt(ikey, KEY_LEN_BYTES, crypt_ftr->salt, sizeof(crypt_ftr->salt), N, r, p, crypt_ftr->scrypted_intermediate_key, sizeof(crypt_ftr->scrypted_intermediate_key)); @@ -1291,7 +1204,7 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, unsigned char** intermediate_key, size_t* intermediate_key_size) { - unsigned char ikey[MAX_KEY_LEN+IV_LEN_BYTES] = { 0 }; + unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 }; EVP_CIPHER_CTX d_ctx; int decrypted_len, final_len; @@ -1304,29 +1217,29 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, /* Initialize the decryption engine */ EVP_CIPHER_CTX_init(&d_ctx); - if (! EVP_DecryptInit_ex(&d_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+get_keysize())) { + if (! EVP_DecryptInit_ex(&d_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+KEY_LEN_BYTES)) { return -1; } EVP_CIPHER_CTX_set_padding(&d_ctx, 0); /* Turn off padding as our data is block aligned */ /* Decrypt the master key */ if (! EVP_DecryptUpdate(&d_ctx, decrypted_master_key, &decrypted_len, - encrypted_master_key, get_keysize())) { + encrypted_master_key, KEY_LEN_BYTES)) { return -1; } if (! EVP_DecryptFinal_ex(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) { return -1; } - if (decrypted_len + final_len != static_cast(get_keysize())) { + if (decrypted_len + final_len != KEY_LEN_BYTES) { return -1; } /* Copy intermediate key if needed by params */ if (intermediate_key && intermediate_key_size) { - *intermediate_key = (unsigned char*) malloc(get_keysize()); + *intermediate_key = (unsigned char*) malloc(KEY_LEN_BYTES); if (*intermediate_key) { - memcpy(*intermediate_key, ikey, get_keysize()); - *intermediate_key_size = get_keysize(); + memcpy(*intermediate_key, ikey, KEY_LEN_BYTES); + *intermediate_key_size = KEY_LEN_BYTES; } } @@ -1372,7 +1285,7 @@ static int decrypt_master_key(const char *passwd, unsigned char *decrypted_maste static int create_encrypted_random_key(const char *passwd, unsigned char *master_key, unsigned char *salt, struct crypt_mnt_ftr *crypt_ftr) { int fd; - unsigned char key_buf[MAX_KEY_LEN]; + unsigned char key_buf[KEY_LEN_BYTES]; /* Get some random bits for a key */ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); @@ -1770,7 +1683,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, /* Also save a the master key so we can reencrypted the key * the key when we want to change the password on it. */ - memcpy(saved_master_key, decrypted_master_key, get_keysize()); + memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES); saved_mount_point = strdup(mount_point); master_key_saved = 1; SLOGD("%s(): Master key saved\n", __FUNCTION__); @@ -1845,7 +1758,7 @@ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr)); ext_crypt_ftr.fs_size = nr_sec; ext_crypt_ftr.keysize = keysize; - strlcpy((char*) ext_crypt_ftr.crypto_type_name, get_crypt_name(), + strlcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN); return create_crypto_blk_dev( @@ -1988,7 +1901,7 @@ int cryptfs_verify_passwd(const char *passwd) } /* Initialize a crypt_mnt_ftr structure. The keysize is - * defaulted to get_keysize(), and the filesystem size to 0. + * defaulted to 16 bytes, and the filesystem size to 0. * Presumably, at a minimum, the caller will update the * filesystem size and crypto_type_name after calling this function. */ @@ -2001,7 +1914,7 @@ static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr) ftr->major_version = CURRENT_MAJOR_VERSION; ftr->minor_version = CURRENT_MINOR_VERSION; ftr->ftr_size = sizeof(struct crypt_mnt_ftr); - ftr->keysize = get_keysize(); + ftr->keysize = KEY_LEN_BYTES; switch (keymaster_check_compatibility()) { case 1: @@ -2253,7 +2166,7 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; } crypt_ftr.crypt_type = crypt_type; - strlcpy((char *)crypt_ftr.crypto_type_name, get_crypt_name(), MAX_CRYPTO_TYPE_NAME_LEN); + strlcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN); /* Make an encrypted master key */ if (create_encrypted_random_key(onlyCreateHeader ? DEFAULT_PASSWORD : passwd, @@ -2264,8 +2177,8 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { /* Replace scrypted intermediate key if we are preparing for a reboot */ if (onlyCreateHeader) { - unsigned char fake_master_key[MAX_KEY_LEN]; - unsigned char encrypted_fake_master_key[MAX_KEY_LEN]; + unsigned char fake_master_key[KEY_LEN_BYTES]; + unsigned char encrypted_fake_master_key[KEY_LEN_BYTES]; memset(fake_master_key, 0, sizeof(fake_master_key)); encrypt_master_key(passwd, crypt_ftr.salt, fake_master_key, encrypted_fake_master_key, &crypt_ftr); From 2c92d7b6a15962eff987d67729147433c857650d Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Wed, 14 Feb 2018 11:26:08 -0800 Subject: [PATCH 079/106] Revert "cryptfs: Make decrypted key buffers large enough" This reverts commit 4a35ef0a53d1f8041adc8bf49585e700bb7af803. --- cryptfs.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index f500a15..1d21124 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -98,11 +98,6 @@ extern "C" { #define CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE (1) -// EVP_DecryptUpdate() requires not just our key length, but up to -// block length - 1 additional bytes for its work. We provide a buffer -// size that will work for all possible ciphers. -#define DECRYPTED_MASTER_KEY_BUF_SIZE (KEY_LEN_BYTES + EVP_MAX_BLOCK_LENGTH - 1) - static int put_crypt_ftr_and_key(struct crypt_mnt_ftr* crypt_ftr); static unsigned char saved_master_key[KEY_LEN_BYTES]; @@ -1600,7 +1595,8 @@ static int do_crypto_complete(const char *mount_point) static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, const char *passwd, const char *mount_point, const char *label) { - unsigned char decrypted_master_key[DECRYPTED_MASTER_KEY_BUF_SIZE]; + /* Allocate enough space for a 256 bit key, but we may use less */ + unsigned char decrypted_master_key[32]; char crypto_blkdev[MAXPATHLEN]; char real_blkdev[MAXPATHLEN]; char tmp_mount_point[64]; @@ -1857,7 +1853,8 @@ int cryptfs_check_passwd(const char *passwd) int cryptfs_verify_passwd(const char *passwd) { struct crypt_mnt_ftr crypt_ftr; - unsigned char decrypted_master_key[DECRYPTED_MASTER_KEY_BUF_SIZE]; + /* Allocate enough space for a 256 bit key, but we may use less */ + unsigned char decrypted_master_key[32]; char encrypted_state[PROPERTY_VALUE_MAX]; int rc; @@ -2007,7 +2004,7 @@ static int vold_unmountAll(void) { int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN]; - unsigned char decrypted_master_key[DECRYPTED_MASTER_KEY_BUF_SIZE]; + unsigned char decrypted_master_key[KEY_LEN_BYTES]; int rc=-1, i; struct crypt_mnt_ftr crypt_ftr; struct crypt_persist_data *pdata; From b802078adcaa7f3af84a96e1dc94b6339e8e22a7 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Wed, 14 Feb 2018 11:26:12 -0800 Subject: [PATCH 080/106] Revert "cryptfs: Don't hardcode ikey buffer size" This reverts commit f45a70c416e74437bfc10e7a1dab55746f3edf25. --- cryptfs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 1d21124..465fd60 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1112,7 +1112,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, unsigned char *encrypted_master_key, struct crypt_mnt_ftr *crypt_ftr) { - unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 }; + unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */ EVP_CIPHER_CTX e_ctx; int encrypted_len, final_len; int rc = 0; @@ -1199,7 +1199,7 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, unsigned char** intermediate_key, size_t* intermediate_key_size) { - unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 }; + unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */ EVP_CIPHER_CTX d_ctx; int decrypted_len, final_len; From c0de9c7dba5efdfc067ab2d72014a162211a33f6 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Wed, 14 Feb 2018 20:05:54 -0800 Subject: [PATCH 081/106] cryptfs: Clarify sizing of intermediate key Some parts of the code were intermingling constants for the master key and the intermediate key. That works at the moment because these are the same size. But we'll be introducing logic allowing different sized master keys, while keeping the intermediate the same. To aid that introduction, we use separate constants for the intermediate key. Bug: 73079191 Test: Build Change-Id: I22b1dbf18aff2f76229df1c898fc606d6c1af3ca --- cryptfs.cpp | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 465fd60..f32bb42 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -73,7 +73,15 @@ extern "C" { #define HASH_COUNT 2000 #define KEY_LEN_BYTES 16 -#define IV_LEN_BYTES 16 + +constexpr size_t INTERMEDIATE_KEY_LEN_BYTES = 16; +constexpr size_t INTERMEDIATE_IV_LEN_BYTES = 16; +constexpr size_t INTERMEDIATE_BUF_SIZE = + (INTERMEDIATE_KEY_LEN_BYTES + INTERMEDIATE_IV_LEN_BYTES); + +// SCRYPT_LEN is used by struct crypt_mnt_ftr for its intermediate key. +static_assert(INTERMEDIATE_BUF_SIZE == SCRYPT_LEN, + "Mismatch of intermediate key sizes"); #define KEY_IN_FOOTER "footer" @@ -1043,7 +1051,7 @@ static int pbkdf2(const char *passwd, const unsigned char *salt, /* Turn the password into a key and IV that can decrypt the master key */ return PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, SALT_LEN, - HASH_COUNT, KEY_LEN_BYTES + IV_LEN_BYTES, + HASH_COUNT, INTERMEDIATE_BUF_SIZE, ikey) != 1; } @@ -1061,7 +1069,7 @@ static int scrypt(const char *passwd, const unsigned char *salt, /* Turn the password into a key and IV that can decrypt the master key */ crypto_scrypt((const uint8_t*)passwd, strlen(passwd), salt, SALT_LEN, N, r, p, ikey, - KEY_LEN_BYTES + IV_LEN_BYTES); + INTERMEDIATE_BUF_SIZE); return 0; } @@ -1082,21 +1090,21 @@ static int scrypt_keymaster(const char *passwd, const unsigned char *salt, rc = crypto_scrypt((const uint8_t*)passwd, strlen(passwd), salt, SALT_LEN, N, r, p, ikey, - KEY_LEN_BYTES + IV_LEN_BYTES); + INTERMEDIATE_BUF_SIZE); if (rc) { SLOGE("scrypt failed"); return -1; } - if (keymaster_sign_object(ftr, ikey, KEY_LEN_BYTES + IV_LEN_BYTES, + if (keymaster_sign_object(ftr, ikey, INTERMEDIATE_BUF_SIZE, &signature, &signature_size)) { SLOGE("Signing failed"); return -1; } rc = crypto_scrypt(signature, signature_size, salt, SALT_LEN, - N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES); + N, r, p, ikey, INTERMEDIATE_BUF_SIZE); free(signature); if (rc) { @@ -1112,7 +1120,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, unsigned char *encrypted_master_key, struct crypt_mnt_ftr *crypt_ftr) { - unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */ + unsigned char ikey[INTERMEDIATE_BUF_SIZE] = { 0 }; EVP_CIPHER_CTX e_ctx; int encrypted_len, final_len; int rc = 0; @@ -1147,7 +1155,8 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, /* Initialize the decryption engine */ EVP_CIPHER_CTX_init(&e_ctx); - if (! EVP_EncryptInit_ex(&e_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+KEY_LEN_BYTES)) { + if (! EVP_EncryptInit_ex(&e_ctx, EVP_aes_128_cbc(), NULL, ikey, + ikey+INTERMEDIATE_KEY_LEN_BYTES)) { SLOGE("EVP_EncryptInit failed\n"); return -1; } @@ -1178,7 +1187,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, int r = 1 << crypt_ftr->r_factor; int p = 1 << crypt_ftr->p_factor; - rc = crypto_scrypt(ikey, KEY_LEN_BYTES, + rc = crypto_scrypt(ikey, INTERMEDIATE_KEY_LEN_BYTES, crypt_ftr->salt, sizeof(crypt_ftr->salt), N, r, p, crypt_ftr->scrypted_intermediate_key, sizeof(crypt_ftr->scrypted_intermediate_key)); @@ -1199,7 +1208,7 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, unsigned char** intermediate_key, size_t* intermediate_key_size) { - unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */ + unsigned char ikey[INTERMEDIATE_BUF_SIZE] = { 0 }; EVP_CIPHER_CTX d_ctx; int decrypted_len, final_len; @@ -1212,7 +1221,7 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, /* Initialize the decryption engine */ EVP_CIPHER_CTX_init(&d_ctx); - if (! EVP_DecryptInit_ex(&d_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+KEY_LEN_BYTES)) { + if (! EVP_DecryptInit_ex(&d_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+INTERMEDIATE_KEY_LEN_BYTES)) { return -1; } EVP_CIPHER_CTX_set_padding(&d_ctx, 0); /* Turn off padding as our data is block aligned */ @@ -1231,10 +1240,10 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, /* Copy intermediate key if needed by params */ if (intermediate_key && intermediate_key_size) { - *intermediate_key = (unsigned char*) malloc(KEY_LEN_BYTES); + *intermediate_key = (unsigned char*) malloc(INTERMEDIATE_KEY_LEN_BYTES); if (*intermediate_key) { - memcpy(*intermediate_key, ikey, KEY_LEN_BYTES); - *intermediate_key_size = KEY_LEN_BYTES; + memcpy(*intermediate_key, ikey, INTERMEDIATE_KEY_LEN_BYTES); + *intermediate_key_size = INTERMEDIATE_KEY_LEN_BYTES; } } From 00eda3863566b607f54f4be33b82732f7bb2710e Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Wed, 14 Feb 2018 20:15:18 -0800 Subject: [PATCH 082/106] cryptfs: Don't use bare integers for key size Rather than use an integer and have a comment, we use a named constant for sizing these master key buffers. This will help avoid confusion when we switch to allowing different sized master keys. Bug: 73079191 Test: Build Change-Id: Ifaffdd94d337bb2d5a178f818dfe00f9386ae03b --- cryptfs.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index f32bb42..d0de553 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1604,8 +1604,7 @@ static int do_crypto_complete(const char *mount_point) static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, const char *passwd, const char *mount_point, const char *label) { - /* Allocate enough space for a 256 bit key, but we may use less */ - unsigned char decrypted_master_key[32]; + unsigned char decrypted_master_key[KEY_LEN_BYTES]; char crypto_blkdev[MAXPATHLEN]; char real_blkdev[MAXPATHLEN]; char tmp_mount_point[64]; @@ -1862,8 +1861,7 @@ int cryptfs_check_passwd(const char *passwd) int cryptfs_verify_passwd(const char *passwd) { struct crypt_mnt_ftr crypt_ftr; - /* Allocate enough space for a 256 bit key, but we may use less */ - unsigned char decrypted_master_key[32]; + unsigned char decrypted_master_key[KEY_LEN_BYTES]; char encrypted_state[PROPERTY_VALUE_MAX]; int rc; From 59ad018d0b8c78427b30101099fb1f37a21c0770 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 16 Feb 2018 13:01:36 -0800 Subject: [PATCH 083/106] cryptfs: Use the crypt_mnt_ftr keysize Our code has places where we were reading in the crypt_mnt_ftr struct from disk, but then proceeding to use a hardcoded constant for the keysize. We plan to allow crypto with different sized keys in the future, so we want to just trust the keysize we get off of disk. While doing this, we reject any crypt_mnt_ftr we read from disk which has a keysize in excess of MAX_KEY_LEN. This defends us against buffer overflows in the case of corrupt disk data. Bug: 73079191 Test: Compiled and tested in combination with other CLs. Change-Id: Id6f192b905960e5508833e9cd3b4668d4754dc7e --- cryptfs.cpp | 60 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index d0de553..8c66e01 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -72,7 +72,7 @@ extern "C" { #define DM_CRYPT_BUF_SIZE 4096 #define HASH_COUNT 2000 -#define KEY_LEN_BYTES 16 +#define DEFAULT_KEY_LEN_BYTES 16 constexpr size_t INTERMEDIATE_KEY_LEN_BYTES = 16; constexpr size_t INTERMEDIATE_IV_LEN_BYTES = 16; @@ -108,7 +108,7 @@ static_assert(INTERMEDIATE_BUF_SIZE == SCRYPT_LEN, static int put_crypt_ftr_and_key(struct crypt_mnt_ftr* crypt_ftr); -static unsigned char saved_master_key[KEY_LEN_BYTES]; +static unsigned char saved_master_key[MAX_KEY_LEN]; static char *saved_mount_point; static int master_key_saved = 0; static struct crypt_persist_data *persist_data = NULL; @@ -585,6 +585,17 @@ static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr) goto errout; } + // We risk buffer overflows with oversized keys, so we just reject them. + // 0-sized keys are problematic (essentially by-passing encryption), and + // AES-CBC key wrapping only works for multiples of 16 bytes. + if ((crypt_ftr->keysize == 0) || ((crypt_ftr->keysize % 16) != 0) || + (crypt_ftr->keysize > MAX_KEY_LEN)) { + SLOGE("Invalid keysize (%u) for block device %s; Must be non-zero, " + "divisible by 16, and <= %d\n", crypt_ftr->keysize, fname, + MAX_KEY_LEN); + goto errout; + } + if (crypt_ftr->minor_version > CURRENT_MINOR_VERSION) { SLOGW("Warning: crypto footer minor version %d, expected <= %d, continuing...\n", crypt_ftr->minor_version, CURRENT_MINOR_VERSION); @@ -854,10 +865,9 @@ static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, struct dm_ioctl *io; struct dm_target_spec *tgt; char *crypt_params; - // We can't assume the key is only KEY_LEN_BYTES. But we do know its limit - // due to the crypt_mnt_ftr struct. We need two ASCII characters to represent - // each byte, and need space for the '\0' terminator. - char master_key_ascii[sizeof(crypt_ftr->master_key) * 2 + 1]; + // We need two ASCII characters to represent each byte, and need space for + // the '\0' terminator. + char master_key_ascii[MAX_KEY_LEN * 2 + 1]; size_t buff_offset; int i; @@ -1164,7 +1174,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, /* Encrypt the master key */ if (! EVP_EncryptUpdate(&e_ctx, encrypted_master_key, &encrypted_len, - decrypted_master_key, KEY_LEN_BYTES)) { + decrypted_master_key, crypt_ftr->keysize)) { SLOGE("EVP_EncryptUpdate failed\n"); return -1; } @@ -1173,7 +1183,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, return -1; } - if (encrypted_len + final_len != KEY_LEN_BYTES) { + if (encrypted_len + final_len != static_cast(crypt_ftr->keysize)) { SLOGE("EVP_Encryption length check failed with %d, %d bytes\n", encrypted_len, final_len); return -1; } @@ -1202,7 +1212,8 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt, } static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, - unsigned char *encrypted_master_key, + const unsigned char *encrypted_master_key, + size_t keysize, unsigned char *decrypted_master_key, kdf_func kdf, void *kdf_params, unsigned char** intermediate_key, @@ -1227,14 +1238,14 @@ static int decrypt_master_key_aux(const char *passwd, unsigned char *salt, EVP_CIPHER_CTX_set_padding(&d_ctx, 0); /* Turn off padding as our data is block aligned */ /* Decrypt the master key */ if (! EVP_DecryptUpdate(&d_ctx, decrypted_master_key, &decrypted_len, - encrypted_master_key, KEY_LEN_BYTES)) { + encrypted_master_key, keysize)) { return -1; } if (! EVP_DecryptFinal_ex(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) { return -1; } - if (decrypted_len + final_len != KEY_LEN_BYTES) { + if (decrypted_len + final_len != static_cast(keysize)) { return -1; } @@ -1277,6 +1288,7 @@ static int decrypt_master_key(const char *passwd, unsigned char *decrypted_maste get_kdf_func(crypt_ftr, &kdf, &kdf_params); ret = decrypt_master_key_aux(passwd, crypt_ftr->salt, crypt_ftr->master_key, + crypt_ftr->keysize, decrypted_master_key, kdf, kdf_params, intermediate_key, intermediate_key_size); if (ret != 0) { @@ -1289,7 +1301,7 @@ static int decrypt_master_key(const char *passwd, unsigned char *decrypted_maste static int create_encrypted_random_key(const char *passwd, unsigned char *master_key, unsigned char *salt, struct crypt_mnt_ftr *crypt_ftr) { int fd; - unsigned char key_buf[KEY_LEN_BYTES]; + unsigned char key_buf[MAX_KEY_LEN]; /* Get some random bits for a key */ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); @@ -1604,7 +1616,7 @@ static int do_crypto_complete(const char *mount_point) static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, const char *passwd, const char *mount_point, const char *label) { - unsigned char decrypted_master_key[KEY_LEN_BYTES]; + unsigned char decrypted_master_key[MAX_KEY_LEN]; char crypto_blkdev[MAXPATHLEN]; char real_blkdev[MAXPATHLEN]; char tmp_mount_point[64]; @@ -1687,7 +1699,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, /* Also save a the master key so we can reencrypted the key * the key when we want to change the password on it. */ - memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES); + memcpy(saved_master_key, decrypted_master_key, crypt_ftr->keysize); saved_mount_point = strdup(mount_point); master_key_saved = 1; SLOGD("%s(): Master key saved\n", __FUNCTION__); @@ -1748,6 +1760,11 @@ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, SLOGE("Failed to open %s: %s", real_blkdev, strerror(errno)); return -1; } + if (keysize > MAX_KEY_LEN) { + SLOGE("ext_volume keysize (%d) larger than max (%d)\n", keysize, + MAX_KEY_LEN); + return -1; + } unsigned long nr_sec = 0; get_blkdev_size(fd, &nr_sec); @@ -1861,7 +1878,7 @@ int cryptfs_check_passwd(const char *passwd) int cryptfs_verify_passwd(const char *passwd) { struct crypt_mnt_ftr crypt_ftr; - unsigned char decrypted_master_key[KEY_LEN_BYTES]; + unsigned char decrypted_master_key[MAX_KEY_LEN]; char encrypted_state[PROPERTY_VALUE_MAX]; int rc; @@ -1905,7 +1922,7 @@ int cryptfs_verify_passwd(const char *passwd) } /* Initialize a crypt_mnt_ftr structure. The keysize is - * defaulted to 16 bytes, and the filesystem size to 0. + * defaulted to DEFAULT_KEY_LEN_BYTES bytes, and the filesystem size to 0. * Presumably, at a minimum, the caller will update the * filesystem size and crypto_type_name after calling this function. */ @@ -1918,7 +1935,7 @@ static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr) ftr->major_version = CURRENT_MAJOR_VERSION; ftr->minor_version = CURRENT_MINOR_VERSION; ftr->ftr_size = sizeof(struct crypt_mnt_ftr); - ftr->keysize = KEY_LEN_BYTES; + ftr->keysize = DEFAULT_KEY_LEN_BYTES; switch (keymaster_check_compatibility()) { case 1: @@ -2011,7 +2028,7 @@ static int vold_unmountAll(void) { int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN]; - unsigned char decrypted_master_key[KEY_LEN_BYTES]; + unsigned char decrypted_master_key[MAX_KEY_LEN]; int rc=-1, i; struct crypt_mnt_ftr crypt_ftr; struct crypt_persist_data *pdata; @@ -2050,6 +2067,9 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { crypt_ftr.flags |= CRYPT_FORCE_COMPLETE; rebootEncryption = true; } + } else { + // We don't want to accidentally reference invalid data. + memset(&crypt_ftr, 0, sizeof(crypt_ftr)); } property_get("ro.crypto.state", encrypted_state, ""); @@ -2181,8 +2201,8 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { /* Replace scrypted intermediate key if we are preparing for a reboot */ if (onlyCreateHeader) { - unsigned char fake_master_key[KEY_LEN_BYTES]; - unsigned char encrypted_fake_master_key[KEY_LEN_BYTES]; + unsigned char fake_master_key[MAX_KEY_LEN]; + unsigned char encrypted_fake_master_key[MAX_KEY_LEN]; memset(fake_master_key, 0, sizeof(fake_master_key)); encrypt_master_key(passwd, crypt_ftr.salt, fake_master_key, encrypted_fake_master_key, &crypt_ftr); From 57f9af6af4492673d42da587dc02f941d2339788 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 16 Feb 2018 13:13:58 -0800 Subject: [PATCH 084/106] cryptfs: Require ext disk crypt to match code Our external partitions have no crypto header/footer, so we only get the keysize and key. Our code has been implicitly assuming that this keysize off of disk matches the crypto type we have in our code (and thus matches the keysize our code is using as well). We now make this assumption explicit, and check for this and no longer allow external code to pass a keysize in to cryptfs. Bug: 73079191 Test: Compiled and tested in combination with other CLs. Change-Id: I1a1996187e1aaad6f103982652b1bcdfd5be33ce --- cryptfs.cpp | 28 ++++++++++++++++------------ cryptfs.h | 6 +++++- model/Disk.cpp | 4 +++- model/PrivateVolume.cpp | 7 ++++++- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 8c66e01..62eb9a7 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -282,6 +282,14 @@ static void get_device_scrypt_params(struct crypt_mnt_ftr *ftr) { ftr->p_factor = pf; } +uint32_t cryptfs_get_keysize() { + return DEFAULT_KEY_LEN_BYTES; +} + +const char *cryptfs_get_crypto_name() { + return "aes-cbc-essiv:sha256"; +} + static unsigned int get_fs_size(char *dev) { int fd, block_size; @@ -1749,22 +1757,18 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, /* * Called by vold when it's asked to mount an encrypted external * storage volume. The incoming partition has no crypto header/footer, - * as any metadata is been stored in a separate, small partition. + * as any metadata is been stored in a separate, small partition. We + * assume it must be using our same crypt type and keysize. * * out_crypto_blkdev must be MAXPATHLEN. */ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, - const unsigned char* key, int keysize, char* out_crypto_blkdev) { + const unsigned char* key, char* out_crypto_blkdev) { int fd = open(real_blkdev, O_RDONLY|O_CLOEXEC); if (fd == -1) { SLOGE("Failed to open %s: %s", real_blkdev, strerror(errno)); return -1; } - if (keysize > MAX_KEY_LEN) { - SLOGE("ext_volume keysize (%d) larger than max (%d)\n", keysize, - MAX_KEY_LEN); - return -1; - } unsigned long nr_sec = 0; get_blkdev_size(fd, &nr_sec); @@ -1778,8 +1782,8 @@ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, struct crypt_mnt_ftr ext_crypt_ftr; memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr)); ext_crypt_ftr.fs_size = nr_sec; - ext_crypt_ftr.keysize = keysize; - strlcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", + ext_crypt_ftr.keysize = cryptfs_get_keysize(); + strlcpy((char*) ext_crypt_ftr.crypto_type_name, cryptfs_get_crypto_name(), MAX_CRYPTO_TYPE_NAME_LEN); return create_crypto_blk_dev( @@ -1922,7 +1926,7 @@ int cryptfs_verify_passwd(const char *passwd) } /* Initialize a crypt_mnt_ftr structure. The keysize is - * defaulted to DEFAULT_KEY_LEN_BYTES bytes, and the filesystem size to 0. + * defaulted to cryptfs_get_keysize() bytes, and the filesystem size to 0. * Presumably, at a minimum, the caller will update the * filesystem size and crypto_type_name after calling this function. */ @@ -1935,7 +1939,7 @@ static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr) ftr->major_version = CURRENT_MAJOR_VERSION; ftr->minor_version = CURRENT_MINOR_VERSION; ftr->ftr_size = sizeof(struct crypt_mnt_ftr); - ftr->keysize = DEFAULT_KEY_LEN_BYTES; + ftr->keysize = cryptfs_get_keysize(); switch (keymaster_check_compatibility()) { case 1: @@ -2190,7 +2194,7 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; } crypt_ftr.crypt_type = crypt_type; - strlcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN); + strlcpy((char *)crypt_ftr.crypto_type_name, cryptfs_get_crypto_name(), MAX_CRYPTO_TYPE_NAME_LEN); /* Make an encrypted master key */ if (create_encrypted_random_key(onlyCreateHeader ? DEFAULT_PASSWORD : passwd, diff --git a/cryptfs.h b/cryptfs.h index bf4b405..d6c7dc5 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -30,6 +30,7 @@ */ #include +#include #include /* The current cryptfs version */ @@ -235,7 +236,7 @@ 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, - int keysize, char* out_crypto_blkdev); + 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); @@ -245,4 +246,7 @@ 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(); + #endif /* ANDROID_VOLD_CRYPTFS_H */ diff --git a/model/Disk.cpp b/model/Disk.cpp index becf8b7..9fcf5e1 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -30,6 +30,8 @@ #include #include +#include "cryptfs.h" + #include #include #include @@ -480,7 +482,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; } diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index 48d041b..cf21577 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -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"; From 38723f23ff521e95ed295f500e6529c52a994c9f Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 16 Feb 2018 13:35:35 -0800 Subject: [PATCH 085/106] cryptfs: Optionally get crypto type as a property Instead of hardcoding to "aes-cbc-essiv:sha256" with a 16 byte key, we introduce a new property, "ro.crypto.fde_algorithm", to allow the use of different crypto types. The only other method we currently support is "speck128-xts-plain64" with a 32 byte key, although new crypto types are easily added. We intentionally derive things like the crypto name and the keysize from the given property name. This means the code must be changed for each new crypto type we want to support, but that's worth it to remove the exploit vector of crypto types with incorrect key sizes. Due to previous refactoring CLs, this has minimal impact on the current code other than changing what we return for cryptfs_get_{keysize,crypto_name}. Bug: 73079191 Test: Flashed onto a gobo device with the property set for SPECK, and confirmed via kernel debug output we were using SPECK on the device. Change-Id: I9c9df61590344c5f62114dfbf679031b0c2ceb1f --- cryptfs.cpp | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 62eb9a7..09e67af 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -72,7 +72,6 @@ extern "C" { #define DM_CRYPT_BUF_SIZE 4096 #define HASH_COUNT 2000 -#define DEFAULT_KEY_LEN_BYTES 16 constexpr size_t INTERMEDIATE_KEY_LEN_BYTES = 16; constexpr size_t INTERMEDIATE_IV_LEN_BYTES = 16; @@ -263,6 +262,122 @@ static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, u } } +namespace { + +struct CryptoType; + +// Use to get the CryptoType in use on this device. +const CryptoType &get_crypto_type(); + +struct CryptoType { + // We should only be constructing CryptoTypes as part of + // supported_crypto_types[]. We do it via this pseudo-builder pattern, + // which isn't pure or fully protected as a concession to being able to + // do it all at compile time. Add new CryptoTypes in + // supported_crypto_types[] below. + constexpr CryptoType() : CryptoType(nullptr, nullptr, 0xFFFFFFFF) {} + constexpr CryptoType set_keysize(uint32_t size) const { + return CryptoType(this->property_name, this->crypto_name, size); + } + constexpr CryptoType set_property_name(const char *property) const { + return CryptoType(property, this->crypto_name, this->keysize); + } + constexpr CryptoType set_crypto_name(const char *crypto) const { + return CryptoType(this->property_name, crypto, this->keysize); + } + + constexpr const char *get_property_name() const { return property_name; } + constexpr const char *get_crypto_name() const { return crypto_name; } + constexpr uint32_t get_keysize() const { return keysize; } + + private: + const char *property_name; + const char *crypto_name; + uint32_t keysize; + + constexpr CryptoType(const char *property, const char *crypto, + uint32_t ksize) + : property_name(property), crypto_name(crypto), keysize(ksize) {} + friend const CryptoType &get_crypto_type(); + static const CryptoType &get_device_crypto_algorithm(); +}; + +// We only want to parse this read-only property once. But we need to wait +// until the system is initialized before we can read it. So we use a static +// scoped within this function to get it only once. +const CryptoType &get_crypto_type() { + static CryptoType crypto_type = CryptoType::get_device_crypto_algorithm(); + return crypto_type; +} + +constexpr CryptoType default_crypto_type = CryptoType() + .set_property_name("AES-128-CBC") + .set_crypto_name("aes-cbc-essiv:sha256") + .set_keysize(16); + +constexpr CryptoType supported_crypto_types[] = { + default_crypto_type, + CryptoType() + .set_property_name("Speck128/128-XTS") + .set_crypto_name("speck128-xts-plain64") + .set_keysize(32), + // Add new CryptoTypes here. Order is not important. +}; + + +// ---------- START COMPILE-TIME SANITY CHECK BLOCK ------------------------- +// We confirm all supported_crypto_types have a small enough keysize and +// had both set_property_name() and set_crypto_name() called. + +template +constexpr size_t array_length(T (&)[N]) { return N; } + +constexpr bool indexOutOfBoundsForCryptoTypes(size_t index) { + return (index >= array_length(supported_crypto_types)); +} + +constexpr bool isValidCryptoType(const CryptoType &crypto_type) { + return ((crypto_type.get_property_name() != nullptr) && + (crypto_type.get_crypto_name() != nullptr) && + (crypto_type.get_keysize() <= MAX_KEY_LEN)); +} + +// Note in C++11 that constexpr functions can only have a single line. +// So our code is a bit convoluted (using recursion instead of a loop), +// but it's asserting at compile time that all of our key lengths are valid. +constexpr bool validateSupportedCryptoTypes(size_t index) { + return indexOutOfBoundsForCryptoTypes(index) || + (isValidCryptoType(supported_crypto_types[index]) && + validateSupportedCryptoTypes(index + 1)); +} + +static_assert(validateSupportedCryptoTypes(0), + "We have a CryptoType with keysize > MAX_KEY_LEN or which was " + "incompletely constructed."); +// ---------- END COMPILE-TIME SANITY CHECK BLOCK ------------------------- + + +// Don't call this directly, use get_crypto_type(), which caches this result. +const CryptoType &CryptoType::get_device_crypto_algorithm() { + constexpr char CRYPT_ALGO_PROP[] = "ro.crypto.fde_algorithm"; + char paramstr[PROPERTY_VALUE_MAX]; + + property_get(CRYPT_ALGO_PROP, paramstr, + default_crypto_type.get_property_name()); + for (auto const &ctype : supported_crypto_types) { + if (strcmp(paramstr, ctype.get_property_name()) == 0) { + return ctype; + } + } + ALOGE("Invalid name (%s) for %s. Defaulting to %s\n", paramstr, + CRYPT_ALGO_PROP, default_crypto_type.get_property_name()); + return default_crypto_type; +} + +} // namespace + + + /** * Gets the default device scrypt parameters for key derivation time tuning. * The parameters should lead to about one second derivation time for the @@ -283,11 +398,11 @@ static void get_device_scrypt_params(struct crypt_mnt_ftr *ftr) { } uint32_t cryptfs_get_keysize() { - return DEFAULT_KEY_LEN_BYTES; + return get_crypto_type().get_keysize(); } const char *cryptfs_get_crypto_name() { - return "aes-cbc-essiv:sha256"; + return get_crypto_type().get_crypto_name(); } static unsigned int get_fs_size(char *dev) From a6aae2f5a5949c49475c7ba603a0567b49cd00b6 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sat, 17 Feb 2018 06:02:30 -0800 Subject: [PATCH 086/106] vold: Idle-maint issues discards fully Change-Id: Ib20a55e8761aa740b530803f029ecb36256fe9aa Signed-off-by: Jaegeuk Kim --- IdleMaint.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IdleMaint.cpp b/IdleMaint.cpp index 62086cd..a2b5faa 100644 --- a/IdleMaint.cpp +++ b/IdleMaint.cpp @@ -225,6 +225,9 @@ static bool waitForGc(const std::list& paths) { static int startGc(const std::list& 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; } @@ -238,6 +241,9 @@ static int stopGc(const std::list& paths) { 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; } From ea2d2bb46c1bf14e6a2b262946c81d8e85272e33 Mon Sep 17 00:00:00 2001 From: Risan Date: Fri, 23 Feb 2018 08:12:37 +0900 Subject: [PATCH 087/106] Add ArcService AIDL in Vold This is needed to allow ARC++ Vold to interact with ArcBridgeService through SystemServer. Bug: 64500663 Test: Compiled, tested on device + cts in master-arc-dev (ag/3488659) Change-Id: I3b05b0f456ec99be9163877a2d83cdbf2bb94991 --- Android.bp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Android.bp b/Android.bp index 12d8b2d..a3072eb 100644 --- a/Android.bp +++ b/Android.bp @@ -134,6 +134,7 @@ cc_library_static { "model/ObbVolume.cpp", ], static_libs: [ + "arc_services_aidl", "libarcobbvolume", ], shared_libs: [ @@ -155,6 +156,7 @@ cc_binary { product_variables: { arc: { static_libs: [ + "arc_services_aidl", "libarcobbvolume", ], shared_libs: [ From 5540b4406c2ca9c5a3654cabc1ab7e88afde58b5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 24 Feb 2018 18:09:21 -0700 Subject: [PATCH 088/106] Use unique_ptr to safely release resources. Test: builds, boots Bug: 66995913 Change-Id: Ib580501fc979b63295b180250581dc7527de76b2 --- Loop.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Loop.cpp b/Loop.cpp index 3736d6a..335ca13 100644 --- a/Loop.cpp +++ b/Loop.cpp @@ -110,17 +110,16 @@ int Loop::destroyByDevice(const char *loopDevice) { int Loop::destroyAll() { ATRACE_NAME("Loop::destroyAll"); - DIR* dir; - struct dirent* de; - std::string root = "/dev/block/"; - if (!(dir = opendir(root.c_str()))) { + auto dirp = std::unique_ptr(opendir(root.c_str()), closedir); + if (!dirp) { PLOG(ERROR) << "Failed to opendir"; return -1; } // Poke through all devices looking for loops - while ((de = readdir(dir))) { + struct dirent* de; + while ((de = readdir(dirp.get()))) { auto test = std::string(de->d_name); if (!android::base::StartsWith(test, "loop")) continue; @@ -151,7 +150,6 @@ int Loop::destroyAll() { } } - closedir(dir); return 0; } From e50314d52b818f74d0f46b87ff6aebc74d037164 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 24 Feb 2018 18:23:35 -0700 Subject: [PATCH 089/106] Trim whitespace from sysfs values. Test: builds, boots Bug: 72740079 Change-Id: If364927ea762c7dee99bff5dc307e3b9b5355c2b --- model/Disk.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/model/Disk.cpp b/model/Disk.cpp index 9fcf5e1..d7b19ac 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -257,6 +257,7 @@ status_t Disk::readMetadata() { PLOG(WARNING) << "Failed to read vendor from " << path; return -errno; } + tmp = android::base::Trim(tmp); mLabel = tmp; break; } @@ -267,6 +268,7 @@ status_t Disk::readMetadata() { PLOG(WARNING) << "Failed to read manufacturer from " << path; return -errno; } + tmp = android::base::Trim(tmp); int64_t manfid; if (!android::base::ParseInt(tmp, &manfid)) { PLOG(WARNING) << "Failed to parse manufacturer " << tmp; From de787a847a45cb202ed1f9cfc666c336af6569a1 Mon Sep 17 00:00:00 2001 From: Risan Date: Thu, 1 Mar 2018 11:19:51 +0900 Subject: [PATCH 090/106] Remove libarcmounter dependency in Vold Due to rerouting ArcBridge call through System Server, Vold doesn't need to depend on ArcBridge-related C++ library anymore. Bug: 64500663 Test: Compiled. Change-Id: Ic93cbc8cec8496784960d5093fb7b12d43574ced --- Android.bp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Android.bp b/Android.bp index a3072eb..b18d7c4 100644 --- a/Android.bp +++ b/Android.bp @@ -137,9 +137,6 @@ cc_library_static { "arc_services_aidl", "libarcobbvolume", ], - shared_libs: [ - "libarcmounter", - ], }, }, } @@ -159,10 +156,6 @@ cc_binary { "arc_services_aidl", "libarcobbvolume", ], - shared_libs: [ - "libarcmounter", - ], - }, }, init_rc: ["vold.rc"], From eb850f93ab056c05cd949ada794c4dab42027a3c Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Thu, 1 Mar 2018 16:48:27 +0000 Subject: [PATCH 091/106] Remove secdiscard IPC call No longer used by the framework, hence removing. Bug: 62140539 Test: builds Change-Id: I17b9818ea6121d84223a502949186cf679a83a90 --- Ext4Crypt.cpp | 4 ---- Ext4Crypt.h | 2 -- VoldNativeService.cpp | 8 -------- VoldNativeService.h | 2 -- binder/android/os/IVold.aidl | 2 -- 5 files changed, 18 deletions(-) diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index 1b71365..67b7e90 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -835,7 +835,3 @@ bool e4crypt_destroy_volume_keys(const std::string& volume_uuid) { res &= destroy_volume_keys("/data/misc_de", volume_uuid); return res; } - -bool e4crypt_secdiscard(const std::string& path) { - return android::vold::runSecdiscardSingle(path); -} diff --git a/Ext4Crypt.h b/Ext4Crypt.h index 4226f15..a43a68a 100644 --- a/Ext4Crypt.h +++ b/Ext4Crypt.h @@ -36,5 +36,3 @@ bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags); bool e4crypt_destroy_volume_keys(const std::string& volume_uuid); - -bool e4crypt_secdiscard(const std::string& path); diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index f4961ce..81523c6 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -759,13 +759,5 @@ binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr& uuid, int32_t userId, int32_t flags); - - binder::Status secdiscard(const std::string& path); }; } // namespace vold diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index a664dfa..8300a8e 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -93,8 +93,6 @@ interface IVold { void prepareUserStorage(@nullable @utf8InCpp String uuid, int userId, int userSerial, int storageFlags); void destroyUserStorage(@nullable @utf8InCpp String uuid, int userId, int storageFlags); - void secdiscard(@utf8InCpp String path); - const int ENCRYPTION_FLAG_NO_UI = 4; const int ENCRYPTION_STATE_NONE = 1; From 385cb8c4d6766b36c52c3bf89128f5a16c88c395 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Thu, 29 Mar 2018 13:27:23 -0700 Subject: [PATCH 092/106] Gate use of allow_encrypt_override behind ro.crypto property Test: use adb set-virtual-disk to create a virtual partition Bug: 25861755 Change-Id: I6a227a083c82321c8d4d2d9188091a6f7f0451f0 --- cryptfs.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 09e67af..2ab3d09 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1900,10 +1900,12 @@ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, ext_crypt_ftr.keysize = cryptfs_get_keysize(); strlcpy((char*) ext_crypt_ftr.crypto_type_name, cryptfs_get_crypto_name(), MAX_CRYPTO_TYPE_NAME_LEN); + uint32_t flags = 0; + if (e4crypt_is_native() && + android::base::GetBoolProperty("ro.crypto.allow_encrypt_override", false)) + flags |= CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE; - return create_crypto_blk_dev( - &ext_crypt_ftr, key, real_blkdev, out_crypto_blkdev, label, - e4crypt_is_native() ? CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE : 0); + return create_crypto_blk_dev(&ext_crypt_ftr, key, real_blkdev, out_crypto_blkdev, label, flags); } /* From c1903ad3d65a04fab97268db3a2782697b0bbfc4 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Fri, 30 Mar 2018 17:06:14 -0600 Subject: [PATCH 093/106] Disable use of StrongBox for encryption Until VerificationTokens are wired up, StrongBox can't work. Also, this will reduce complications for early StrongBox testing. Bug: 77338527 Test: Boot the device Change-Id: I44a1577c388703aeecb2886e7db52084c17e2afd --- Keymaster.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Keymaster.cpp b/Keymaster.cpp index 7d061bb..7df27ec 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -25,6 +25,7 @@ namespace vold { using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; +using ::android::hardware::keymaster::V4_0::SecurityLevel; KeymasterOperation::~KeymasterOperation() { if (mDevice) mDevice->abort(mOpHandle); @@ -97,8 +98,15 @@ bool KeymasterOperation::finish(std::string* output) { Keymaster::Keymaster() { auto devices = KmDevice::enumerateAvailableDevices(); - if (devices.empty()) return; - mDevice = std::move(devices[0]); + for (auto& dev : devices) { + // Explicitly avoid using STRONGBOX for now. + // TODO: Re-enable STRONGBOX, since it's what we really want. b/77338527 + 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) From 7db02ab5d122501e8303cbde0ac868f02e9b1b86 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 5 Apr 2018 22:43:25 -0700 Subject: [PATCH 094/106] vold: set f2fs feature bit Bug: 74604441 Bug: 67380979 Change-Id: Ifcb43fb4f8fbdf79e70cfa208af73073d815e254 Signed-off-by: Jaegeuk Kim --- fs/F2fs.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp index 56369d5..f24fd91 100644 --- a/fs/F2fs.cpp +++ b/fs/F2fs.cpp @@ -86,6 +86,10 @@ status_t Format(const std::string& source) { cmd.push_back("-O"); cmd.push_back("encrypt"); } + + cmd.push_back("-O"); + cmd.push_back("verity"); + cmd.push_back(source); return ForkExecvp(cmd); } From eefc5eebc3f89d9a5e41cf51a7da2b972ff1abe7 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 12 Feb 2018 21:57:04 -0800 Subject: [PATCH 095/106] vold: Idle-maint calls device GC This activates device GCs in idle time. F2FS GC = 7 mins Trim = 1 mins Dev GC = 2 mins Bug: 63264275 Bug: 68721792 Change-Id: I843a742ef192ebe00d77c47a216d4200bc9ccb9d Signed-off-by: Jaegeuk Kim --- IdleMaint.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/IdleMaint.cpp b/IdleMaint.cpp index a2b5faa..7744024 100644 --- a/IdleMaint.cpp +++ b/IdleMaint.cpp @@ -59,7 +59,14 @@ enum class IdleMaintStats { static const char* kWakeLock = "IdleMaint"; static const int DIRTY_SEGMENTS_THRESHOLD = 100; -static const int GC_TIMEOUT_SEC = 480; +/* + * 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; @@ -248,6 +255,58 @@ static int stopGc(const std::list& paths) { return android::OK; } +static void runDevGc(void) { + std::unique_ptr 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& listener) { std::unique_lock lk(cv_m); if (idle_maint_stat != IdleMaintStats::kStopped) { @@ -283,6 +342,7 @@ int RunIdleMaint(const android::sp& listener) { if (!gc_aborted) { Trim(nullptr); + runDevGc(); } if (listener) { From bca5cd78fe14292079e2ffd63912f51e974c7fc3 Mon Sep 17 00:00:00 2001 From: Tri Vo Date: Mon, 16 Apr 2018 14:27:10 -0700 Subject: [PATCH 096/106] Exclude /mnt/vendor from vold's ownership. Addresses this selinux denial: avc: denied { search } for name="vendor" dev="tmpfs" ino=11069 scontext=u:r:vold:s0 tcontext=u:object_r:mnt_vendor_file:s0 tclass=dir permissive=0 Bug: 64905218 Test: fixes above denial. Change-Id: I670b2148e65c7e0fcabd1e11f5bace0c4f4e18bd --- VolumeManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 5e6e74f..8c32587 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -623,8 +623,9 @@ int VolumeManager::unmountAll() { mntent* mentry; while ((mentry = getmntent(fp)) != NULL) { auto test = std::string(mentry->mnt_dir); - if (android::base::StartsWith(test, "/mnt/") - || android::base::StartsWith(test, "/storage/")) { + if ((android::base::StartsWith(test, "/mnt/") && + !android::base::StartsWith(test, "/mnt/vendor")) || + android::base::StartsWith(test, "/storage/")) { toUnmount.push_front(test); } } From 0267ccf8a4c882a5b11dd6f658a56ba73f23c0d8 Mon Sep 17 00:00:00 2001 From: Logan Chien Date: Wed, 2 May 2018 10:57:56 +0800 Subject: [PATCH 097/106] Add linux/types.h to cryptfs.h This commit adds to cryptfs.h because cryptfs.h uses `__le16` and `__le32` which are defined in . The absence of will become an error after we sort the headers in the upcoming commits. Test: cd system/vold && mma Change-Id: I9930105ee86f80a29295b59596b21335c68a8e23 --- cryptfs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cryptfs.h b/cryptfs.h index d6c7dc5..dc7a8c3 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -29,8 +29,10 @@ * partition. */ +#include #include #include + #include /* The current cryptfs version */ From d557d76466040b529aaec16a902e405a83745489 Mon Sep 17 00:00:00 2001 From: Logan Chien Date: Wed, 2 May 2018 11:36:45 +0800 Subject: [PATCH 098/106] Reorder the include directives in cryptfs.cpp This commit reorders the include directives in cryptfs.cpp so that upcoming change can be obvious. Test: lunch aosp_walleye-userdebug && cd system/vold && mma Change-Id: I9d2ea66c15b7b68014a67ba7c1420075953459ba --- cryptfs.cpp | 77 ++++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 2ab3d09..18f6b83 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -20,49 +20,54 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define LOG_TAG "Cryptfs" + +#include "cryptfs.h" + +#include "EncryptInplace.h" +#include "Ext4Crypt.h" +#include "Keymaster.h" +#include "Process.h" +#include "ScryptParameters.h" +#include "VoldUtil.h" +#include "VolumeManager.h" +#include "secontext.h" + +#include #include #include -#include #include -#include -#include +#include +#include +#include #include -#include "cryptfs.h" -#include "secontext.h" -#define LOG_TAG "Cryptfs" +#include "android-base/properties.h" +#include "cutils/android_reboot.h" #include "cutils/log.h" #include "cutils/properties.h" -#include "cutils/android_reboot.h" -#include "hardware_legacy/power.h" -#include -#include "ScryptParameters.h" -#include "VolumeManager.h" -#include "VoldUtil.h" -#include "Ext4Crypt.h" #include "f2fs_sparseblock.h" -#include "EncryptInplace.h" -#include "Process.h" -#include "Keymaster.h" -#include "android-base/properties.h" -#include +#include "hardware_legacy/power.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + extern "C" { #include } From 3f2b122cd254bddf7bd4af9eb07126f48a6fbf45 Mon Sep 17 00:00:00 2001 From: Logan Chien Date: Wed, 2 May 2018 11:39:03 +0800 Subject: [PATCH 099/106] Replace library headers with angle quotations This commit replaces the double quotations for library headers with angle quotations. Test: cd system/vold && mma Change-Id: I3c14cfcf80f29173669409df548af84c1b39b96d --- cryptfs.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 18f6b83..5c2b3e8 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -33,20 +33,20 @@ #include "VolumeManager.h" #include "secontext.h" +#include #include +#include +#include +#include #include #include +#include #include +#include #include #include #include #include -#include "android-base/properties.h" -#include "cutils/android_reboot.h" -#include "cutils/log.h" -#include "cutils/properties.h" -#include "f2fs_sparseblock.h" -#include "hardware_legacy/power.h" #include #include From 188b0ab7b3759b8810413883833f7a1e66948743 Mon Sep 17 00:00:00 2001 From: Logan Chien Date: Mon, 23 Apr 2018 13:37:39 +0800 Subject: [PATCH 100/106] Deprecate and This commit replaces and with . Background: has been moved to for a while. Both and simply includes for backward compatibility. This commit is a part of the effort to remove and from the source tree eventually. Bug: 78370064 Test: lunch aosp_walleye-userdebug && cd system/vold && mma Change-Id: I1f9b7b132f9c35469e97556a30b521cc47e829d7 --- cryptfs.cpp | 2 +- fs/Ext4.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 5c2b3e8..b15306c 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -36,13 +36,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp index 89b8414..717c8b7 100644 --- a/fs/Ext4.cpp +++ b/fs/Ext4.cpp @@ -35,12 +35,9 @@ #include -#define LOG_TAG "Vold" - #include #include #include -#include #include #include #include @@ -102,7 +99,8 @@ status_t Check(const std::string& source, const std::string& target) { if (result == 0) { break; } - ALOGW("%s(): umount(%s)=%d: %s\n", __func__, c_target, result, strerror(errno)); + LOG(WARNING) << __func__ << "(): umount(" << c_target << ")=" << result << ": " + << strerror(errno); sleep(1); } } @@ -112,10 +110,10 @@ status_t Check(const std::string& source, const std::string& target) { * (e.g. recent SDK system images). Detect these and skip the check. */ if (access(kFsckPath, X_OK)) { - ALOGD("Not running %s on %s (executable not in system image)\n", - kFsckPath, c_source); + LOG(DEBUG) << "Not running " << kFsckPath << " on " << c_source + << " (executable not in system image)"; } else { - ALOGD("Running %s on %s\n", kFsckPath, c_source); + LOG(DEBUG) << "Running " << kFsckPath << " on " << c_source; std::vector cmd; cmd.push_back(kFsckPath); From 8f82879901968d9793705eb1d06c9b32607ced13 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Wed, 7 Feb 2018 14:41:26 -0800 Subject: [PATCH 101/106] add wait_for_keymaster Bug: 79228237 Test: boots with patch Change-Id: I581bcd4c4dd92c5b7be70eb351ecba20225e1eee --- Android.bp | 23 +++++++++++++++++++++++ wait_for_keymaster.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 wait_for_keymaster.cpp diff --git a/Android.bp b/Android.bp index b18d7c4..a8934fc 100644 --- a/Android.bp +++ b/Android.bp @@ -163,6 +163,7 @@ cc_binary { required: [ "mke2fs", "vold_prepare_subdirs", + "wait_for_keymaster", ], } @@ -183,6 +184,28 @@ cc_binary { 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"], diff --git a/wait_for_keymaster.cpp b/wait_for_keymaster.cpp new file mode 100644 index 0000000..bf26518 --- /dev/null +++ b/wait_for_keymaster.cpp @@ -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 + +#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; +} From 2807536fc4415e65b1c7950f7fb0f93ce1777292 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Wed, 9 May 2018 08:12:10 -0600 Subject: [PATCH 102/106] Do Keymaster HMAC key agreement in vold. Bug: 79307225 Test: Boot Change-Id: I6682e86076aa568907d94024ef175dbdede86557 --- Keymaster.cpp | 6 ++++++ Keymaster.h | 1 + 2 files changed, 7 insertions(+) diff --git a/Keymaster.cpp b/Keymaster.cpp index 7df27ec..4921448 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -96,8 +96,14 @@ bool KeymasterOperation::finish(std::string* output) { return true; } +/* static */ bool Keymaster::hmacKeyGenerated = false; + Keymaster::Keymaster() { auto devices = KmDevice::enumerateAvailableDevices(); + if (!hmacKeyGenerated) { + KmDevice::performHmacKeyAgreement(devices); + hmacKeyGenerated = true; + } for (auto& dev : devices) { // Explicitly avoid using STRONGBOX for now. // TODO: Re-enable STRONGBOX, since it's what we really want. b/77338527 diff --git a/Keymaster.h b/Keymaster.h index 7571402..fabe0f4 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -117,6 +117,7 @@ class Keymaster { private: std::unique_ptr mDevice; DISALLOW_COPY_AND_ASSIGN(Keymaster); + static bool hmacKeyGenerated; }; } // namespace vold From 98a23a19d123a4714c30f8892bc971ef84b59214 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Wed, 9 May 2018 13:01:16 -0700 Subject: [PATCH 103/106] Fix spurious error Bug: 79542247 Test: error no longer appears Change-Id: I2cf91c8cd937b81041a47e4b64a882445a80eb0b --- MetadataCrypt.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 4a847e3..c14b9a2 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -79,9 +79,10 @@ static bool read_key(struct fstab_rec const* data_rec, bool create_if_absent, Ke } std::string key_dir = data_rec->key_dir; auto dir = key_dir + "/key"; - LOG(DEBUG) << "key_dir/key: " << key; - if (!fs_mkdirs(dir.c_str(), 0700)) { + 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; From f5b085c13ae130b30fb11b35420c2dbdc1f9e4fa Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 15 May 2018 16:12:20 -0700 Subject: [PATCH 104/106] Add rc file for wait_for_keymaster Similar to update_verifier, define higher prio and use exec_start for this binary. Bug: 79492334 Test: Reboot test Change-Id: I8d3133cabcc8d4cee8bdead310f2c18d8d07e9dd --- Android.bp | 5 ++++- wait_for_keymaster.rc | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 wait_for_keymaster.rc diff --git a/Android.bp b/Android.bp index a8934fc..556784f 100644 --- a/Android.bp +++ b/Android.bp @@ -158,7 +158,10 @@ cc_binary { ], }, }, - init_rc: ["vold.rc"], + init_rc: [ + "vold.rc", + "wait_for_keymaster.rc", + ], required: [ "mke2fs", diff --git a/wait_for_keymaster.rc b/wait_for_keymaster.rc new file mode 100644 index 0000000..9e83a93 --- /dev/null +++ b/wait_for_keymaster.rc @@ -0,0 +1,5 @@ +service wait_for_keymaster /system/bin/wait_for_keymaster + user root + group root system + priority -20 + ioprio rt 0 From e763ed2aa3075a1fd699f09c06ba67dbfd946a6b Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Thu, 17 May 2018 15:24:56 -0600 Subject: [PATCH 105/106] Explain the rationale for not using StrongBox in vold. Bug: 77338527 Test: Comment-only change. Change-Id: I9f87e34854eabcc4c183553cf56a033970bb867e --- Keymaster.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Keymaster.cpp b/Keymaster.cpp index 4921448..aad4387 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -49,9 +49,6 @@ bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen, size_t toRead = static_cast(inputLen - inputConsumed); auto inputBlob = km::support::blob2hidlVec( reinterpret_cast(&input[inputConsumed]), toRead); - // TODO(swillden): Need to handle getting a VerificationToken from the TEE if mDevice is - // StrongBox, so we can provide it here. The VerificationToken will need to be - // requested/retrieved during Keymaster::begin(). auto error = mDevice->update(mOpHandle, hidl_vec(), inputBlob, km::HardwareAuthToken(), km::VerificationToken(), hidlCB); if (!error.isOk()) { @@ -105,8 +102,9 @@ Keymaster::Keymaster() { hmacKeyGenerated = true; } for (auto& dev : devices) { - // Explicitly avoid using STRONGBOX for now. - // TODO: Re-enable STRONGBOX, since it's what we really want. b/77338527 + // 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; From ee5c7318d70f61fc735f64ea28603550af54f8df Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 1 Jun 2018 11:31:39 -0600 Subject: [PATCH 106/106] Require quotes when searching for blkid keys. In combination with a blkid change, this prevents the parsing logic from getting confused by key names appearing inside values. (The blkid change suppresses any quotes that appear inside values.) Bug: 80436257 Test: manual Change-Id: I9480ef6eb78254b812c671950875d0b8918a27c6 --- Utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index e19c9df..5de4dbf 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -189,17 +189,17 @@ static status_t readMetadata(const std::string& path, std::string& fsType, for (auto line : output) { // Extract values from blkid output, if defined const char* cline = line.c_str(); - char* start = strstr(cline, "TYPE="); + char* start = strstr(cline, "TYPE=\""); if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) { fsType = value; } - start = strstr(cline, "UUID="); + start = strstr(cline, "UUID=\""); if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) { fsUuid = value; } - start = strstr(cline, "LABEL="); + start = strstr(cline, "LABEL=\""); if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) { fsLabel = value; }