From 2048a2865cfa1f8c794b94eb044854f130943f9c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 15 Jun 2017 09:59:43 -0600 Subject: [PATCH] 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);