DO NOT MERGE: Merge Oreo MR1 into master

Exempt-From-Owner-Approval: Changes already landed internally
Change-Id: Ic7e2e2d1ef7bf17a9c81ea30d759fd9fe0a218c7
gugelfrei
Xin Li 7 years ago
commit 1843c887d4

@ -26,6 +26,7 @@ common_src_files := \
MoveTask.cpp \
Benchmark.cpp \
TrimTask.cpp \
KeyBuffer.cpp \
Keymaster.cpp \
KeyStorage.cpp \
KeyUtil.cpp \
@ -86,6 +87,8 @@ ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
vold_cflags += -DTARGET_USES_MKE2FS
required_modules += mke2fs
else
# Adoptable storage has fully moved to mke2fs, so we need both tools
required_modules += mke2fs
required_modules += make_ext4fs
endif
endif
@ -156,7 +159,10 @@ LOCAL_CLANG := true
LOCAL_TIDY := true
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES:= secdiscard.cpp
LOCAL_SRC_FILES:= \
FileDeviceUtils.cpp \
secdiscard.cpp \
LOCAL_MODULE:= secdiscard
LOCAL_SHARED_LIBRARIES := libbase
LOCAL_CFLAGS := $(vold_cflags)

@ -1,50 +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 <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <android-base/logging.h>
// File descriptor which is automatically closed when this object is destroyed.
// Cannot be copied, since that would cause double-closes.
class AutoCloseFD {
public:
AutoCloseFD(const char *path, int flags = O_RDONLY, int mode = 0):
fd{TEMP_FAILURE_RETRY(open(path, flags | O_CLOEXEC, mode))} {}
AutoCloseFD(const std::string &path, int flags = O_RDONLY, int mode = 0):
AutoCloseFD(path.c_str(), flags, mode) {}
~AutoCloseFD() {
if (fd != -1) {
int preserve_errno = errno;
if (close(fd) == -1) {
PLOG(ERROR) << "close(2) failed";
};
errno = preserve_errno;
}
}
AutoCloseFD(const AutoCloseFD&) = delete;
AutoCloseFD& operator=(const AutoCloseFD&) = delete;
explicit operator bool() {return fd != -1;}
int get() const {return fd;}
private:
const int fd;
};

@ -24,6 +24,7 @@
#include "Ext4Crypt.h"
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <diskconfig/diskconfig.h>
@ -447,7 +448,8 @@ status_t Disk::partitionPrivate() {
status_t Disk::partitionMixed(int8_t ratio) {
int res;
if (e4crypt_is_native()) {
if (e4crypt_is_native()
&& !android::base::GetBoolProperty("persist.sys.adoptable_fbe", false)) {
LOG(ERROR) << "Private volumes not yet supported on FBE devices";
return -EINVAL;
}
@ -470,9 +472,14 @@ status_t Disk::partitionMixed(int8_t ratio) {
// We've had some success above, so generate both the private partition
// GUID and encryption key and persist them.
std::string partGuidRaw;
if (GenerateRandomUuid(partGuidRaw) != OK) {
LOG(ERROR) << "Failed to generate GUID";
return -EIO;
}
std::string keyRaw;
if (ReadRandomBytes(16, partGuidRaw) || ReadRandomBytes(16, keyRaw)) {
LOG(ERROR) << "Failed to generate GUID or key";
if (ReadRandomBytes(16, keyRaw) != OK) {
LOG(ERROR) << "Failed to generate key";
return -EIO;
}

@ -84,6 +84,7 @@ status_t EmulatedVolume::doMount() {
"-g", "1023", // AID_MEDIA_RW
"-m",
"-w",
"-G",
mRawPath.c_str(),
label.c_str(),
NULL)) {
@ -103,6 +104,8 @@ status_t EmulatedVolume::doMount() {
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
usleep(50000); // 50ms
}
/* sdcardfs will have exited already. FUSE will still be running */
TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
return OK;
}

@ -30,6 +30,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <selinux/android.h>
#include <sys/mount.h>
@ -54,7 +55,9 @@
#include <android-base/stringprintf.h>
using android::base::StringPrintf;
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;
@ -78,7 +81,7 @@ std::set<userid_t> s_ephemeral_users;
std::map<userid_t, std::string> s_de_key_raw_refs;
std::map<userid_t, std::string> s_ce_key_raw_refs;
// TODO abolish this map, per b/26948053
std::map<userid_t, std::string> s_ce_keys;
std::map<userid_t, KeyBuffer> s_ce_keys;
}
@ -168,7 +171,7 @@ static void fixate_user_ce_key(const std::string& directory_path, const std::str
static bool read_and_fixate_user_ce_key(userid_t user_id,
const android::vold::KeyAuthentication& auth,
std::string *ce_key) {
KeyBuffer *ce_key) {
auto const directory_path = get_ce_key_directory_path(user_id);
auto const paths = get_ce_key_paths(directory_path);
for (auto const ce_key_path: paths) {
@ -186,11 +189,11 @@ static bool read_and_fixate_user_ce_key(userid_t user_id,
static bool read_and_install_user_ce_key(userid_t user_id,
const android::vold::KeyAuthentication& auth) {
if (s_ce_key_raw_refs.count(user_id) != 0) return true;
std::string ce_key;
KeyBuffer ce_key;
if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false;
std::string ce_raw_ref;
if (!android::vold::installKey(ce_key, &ce_raw_ref)) return false;
s_ce_keys[user_id] = ce_key;
s_ce_keys[user_id] = std::move(ce_key);
s_ce_key_raw_refs[user_id] = ce_raw_ref;
LOG(DEBUG) << "Installed ce key for user " << user_id;
return true;
@ -217,7 +220,7 @@ static bool destroy_dir(const std::string& dir) {
// NB this assumes that there is only one thread listening for crypt commands, because
// it creates keys in a fixed location.
static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
std::string de_key, ce_key;
KeyBuffer de_key, ce_key;
if (!android::vold::randomKey(&de_key)) return false;
if (!android::vold::randomKey(&ce_key)) return false;
if (create_ephemeral) {
@ -304,7 +307,7 @@ static bool load_all_de_keys() {
userid_t user_id = atoi(entry->d_name);
if (s_de_key_raw_refs.count(user_id) == 0) {
auto key_path = de_dir + "/" + entry->d_name;
std::string key;
KeyBuffer key;
if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
std::string raw_ref;
if (!android::vold::installKey(key, &raw_ref)) return false;
@ -399,13 +402,23 @@ bool e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral)
return true;
}
static void drop_caches() {
// Clean any dirty pages (otherwise they won't be dropped).
sync();
// Drop inode and page caches.
if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
PLOG(ERROR) << "Failed to drop caches during key eviction";
}
}
static bool evict_ce_key(userid_t user_id) {
s_ce_keys.erase(user_id);
s_ce_keys.erase(user_id);
bool success = true;
std::string raw_ref;
// If we haven't loaded the CE key, no need to evict it.
if (lookup_key_ref(s_ce_key_raw_refs, user_id, &raw_ref)) {
success &= android::vold::evictKey(raw_ref);
drop_caches();
}
s_ce_key_raw_refs.erase(user_id);
return success;
@ -497,7 +510,7 @@ bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const char* token_h
LOG(ERROR) << "Key not loaded into memory, can't change for user " << user_id;
return false;
}
auto ce_key = it->second;
const auto &ce_key = it->second;
auto const directory_path = get_ce_key_directory_path(user_id);
auto const paths = get_ce_key_paths(directory_path);
std::string ce_key_path;
@ -599,8 +612,7 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int
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;
// For now, FBE is only supported on internal storage
if (e4crypt_is_native() && volume_uuid == nullptr) {
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;
@ -621,8 +633,7 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int
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;
// For now, FBE is only supported on internal storage
if (e4crypt_is_native() && volume_uuid == nullptr) {
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;

@ -0,0 +1,115 @@
/*
* 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 "FileDeviceUtils.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/fiemap.h>
#include <mntent.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
namespace {
std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count);
}
namespace android {
namespace vold {
// Given a file path, look for the corresponding block device in /proc/mount
std::string BlockDeviceForPath(const std::string &path)
{
std::unique_ptr<FILE, int(*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
if (!mnts) {
PLOG(ERROR) << "Unable to open /proc/mounts";
return "";
}
std::string result;
size_t best_length = 0;
struct mntent *mnt; // getmntent returns a thread local, so it's safe.
while ((mnt = getmntent(mnts.get())) != nullptr) {
auto l = strlen(mnt->mnt_dir);
if (l > best_length &&
path.size() > l &&
path[l] == '/' &&
path.compare(0, l, mnt->mnt_dir) == 0) {
result = mnt->mnt_fsname;
best_length = l;
}
}
if (result.empty()) {
LOG(ERROR) <<"Didn't find a mountpoint to match path " << path;
return "";
}
LOG(DEBUG) << "For path " << path << " block device is " << result;
return result;
}
std::unique_ptr<struct fiemap> PathFiemap(const std::string &path, uint32_t extent_count)
{
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(
path.c_str(), O_RDONLY | O_CLOEXEC, 0)));
if (fd == -1) {
if (errno == ENOENT) {
PLOG(DEBUG) << "Unable to open " << path;
} else {
PLOG(ERROR) << "Unable to open " << path;
}
return nullptr;
}
auto fiemap = alloc_fiemap(extent_count);
if (ioctl(fd.get(), FS_IOC_FIEMAP, fiemap.get()) != 0) {
PLOG(ERROR) << "Unable to FIEMAP " << path;
return nullptr;
}
auto mapped = fiemap->fm_mapped_extents;
if (mapped < 1 || mapped > extent_count) {
LOG(ERROR) << "Extent count not in bounds 1 <= " << mapped << " <= " << extent_count
<< " in " << path;
return nullptr;
}
return fiemap;
}
} // namespace vold
} // namespace android
namespace {
std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count)
{
size_t allocsize = offsetof(struct fiemap, fm_extents[extent_count]);
std::unique_ptr<struct fiemap> res(new (::operator new (allocsize)) struct fiemap);
memset(res.get(), 0, allocsize);
res->fm_start = 0;
res->fm_length = UINT64_MAX;
res->fm_flags = 0;
res->fm_extent_count = extent_count;
res->fm_mapped_extents = 0;
return res;
}
}

@ -0,0 +1,35 @@
/*
* 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_FILEDEVICEUTILS_H
#define ANDROID_VOLD_FILEDEVICEUTILS_H
#include <string>
#include <linux/fiemap.h>
namespace android {
namespace vold {
// Given a file path, look for the corresponding block device in /proc/mount
std::string BlockDeviceForPath(const std::string &path);
// Read the file's FIEMAP
std::unique_ptr<struct fiemap> PathFiemap(const std::string &path, uint32_t extent_count);
} // namespace vold
} // namespace android
#endif

@ -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.
*/
#include "KeyBuffer.h"
#include <algorithm>
#include <cstring>
namespace android {
namespace vold {
KeyBuffer operator+(KeyBuffer&& lhs, const KeyBuffer& rhs) {
std::copy(rhs.begin(), rhs.end(), std::back_inserter(lhs));
return std::move(lhs);
}
KeyBuffer operator+(KeyBuffer&& lhs, const char* rhs) {
std::copy(rhs, rhs + strlen(rhs), std::back_inserter(lhs));
return std::move(lhs);
}
} // namespace vold
} // namespace android

@ -0,0 +1,63 @@
/*
* 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_KEYBUFFER_H
#define ANDROID_VOLD_KEYBUFFER_H
#include <cstring>
#include <memory>
#include <vector>
namespace android {
namespace vold {
/**
* Variant of memset() that should never be optimized away. Borrowed from keymaster code.
*/
#ifdef __clang__
#define OPTNONE __attribute__((optnone))
#else // not __clang__
#define OPTNONE __attribute__((optimize("O0")))
#endif // not __clang__
inline OPTNONE void* memset_s(void* s, int c, size_t n) {
if (!s)
return s;
return memset(s, c, n);
}
#undef OPTNONE
// Allocator that delegates useful work to standard one but zeroes data before deallocating.
class ZeroingAllocator : public std::allocator<char> {
public:
void deallocate(pointer p, size_type n)
{
memset_s(p, 0, n);
std::allocator<char>::deallocate(p, n);
}
};
// Char vector that zeroes memory when deallocating.
using KeyBuffer = std::vector<char, ZeroingAllocator>;
// Convenience methods to concatenate key buffers.
KeyBuffer operator+(KeyBuffer&& lhs, const KeyBuffer& rhs);
KeyBuffer operator+(KeyBuffer&& lhs, const char* rhs);
} // namespace vold
} // namespace android
#endif

@ -195,7 +195,7 @@ static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir,
static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
const AuthorizationSet &keyParams,
const std::string& message, std::string* ciphertext) {
const KeyBuffer& message, std::string* ciphertext) {
AuthorizationSet opParams;
AuthorizationSet outParams;
auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams);
@ -220,7 +220,7 @@ static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir
static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
const AuthorizationSet &keyParams,
const std::string& ciphertext, std::string* message) {
const std::string& ciphertext, KeyBuffer* message) {
auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES);
auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES);
auto opParams = AuthorizationSetBuilder()
@ -305,7 +305,7 @@ static void logOpensslError() {
}
static bool encryptWithoutKeymaster(const std::string& preKey,
const std::string& plaintext, std::string* ciphertext) {
const KeyBuffer& plaintext, std::string* ciphertext) {
auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
key.resize(AES_KEY_BYTES);
if (!readRandomBytesOrLog(GCM_NONCE_BYTES, ciphertext)) return false;
@ -351,7 +351,7 @@ static bool encryptWithoutKeymaster(const std::string& preKey,
}
static bool decryptWithoutKeymaster(const std::string& preKey,
const std::string& ciphertext, std::string* plaintext) {
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;
@ -370,7 +370,7 @@ static bool decryptWithoutKeymaster(const std::string& preKey,
logOpensslError();
return false;
}
plaintext->resize(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES);
*plaintext = KeyBuffer(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES);
int outlen;
if (1 != EVP_DecryptUpdate(ctx.get(),
reinterpret_cast<uint8_t*>(&(*plaintext)[0]), &outlen,
@ -404,7 +404,7 @@ bool pathExists(const std::string& path) {
return access(path.c_str(), F_OK) == 0;
}
bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key) {
bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBuffer& key) {
if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), 0700)) == -1) {
PLOG(ERROR) << "key mkdir " << dir;
return false;
@ -442,7 +442,7 @@ bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::
}
bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path,
const KeyAuthentication& auth, const std::string& key) {
const KeyAuthentication& auth, const KeyBuffer& key) {
if (pathExists(key_path)) {
LOG(ERROR) << "Already exists, cannot create key at: " << key_path;
return false;
@ -460,7 +460,7 @@ bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path
return true;
}
bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key) {
bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key) {
std::string version;
if (!readFileToString(dir + "/" + kFn_version, &version)) return false;
if (version != kCurrentVersion) {

@ -17,6 +17,8 @@
#ifndef ANDROID_VOLD_KEYSTORAGE_H
#define ANDROID_VOLD_KEYSTORAGE_H
#include "KeyBuffer.h"
#include <string>
namespace android {
@ -46,17 +48,17 @@ bool pathExists(const std::string& path);
// in such a way that it can only be retrieved via Keymaster and
// can be securely deleted.
// It's safe to move/rename the directory after creation.
bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key);
bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBuffer& key);
// Create a directory at the named path, and store "key" in it as storeKey
// This version creates the key in "tmp_path" then atomically renames "tmp_path"
// to "key_path" thereby ensuring that the key is either stored entirely or
// not at all.
bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path,
const KeyAuthentication& auth, const std::string& key);
const KeyAuthentication& auth, const KeyBuffer& key);
// Retrieve the key from the named directory.
bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key);
bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key);
// Securely destroy the key stored in the named directory and delete the directory.
bool destroyKey(const std::string& dir);

@ -32,8 +32,23 @@
namespace android {
namespace vold {
bool randomKey(std::string* key) {
if (ReadRandomBytes(EXT4_AES_256_XTS_KEY_SIZE, *key) != 0) {
// ext4enc:TODO get this const from somewhere good
const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
// ext4enc:TODO Include structure from somewhere sensible
// MUST be in sync with ext4_crypto.c in kernel
constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64;
constexpr int EXT4_MAX_KEY_SIZE = 64;
struct ext4_encryption_key {
uint32_t mode;
char raw[EXT4_MAX_KEY_SIZE];
uint32_t size;
};
bool randomKey(KeyBuffer* key) {
*key = KeyBuffer(EXT4_AES_256_XTS_KEY_SIZE);
if (ReadRandomBytes(key->size(), key->data()) != 0) {
// TODO status_t plays badly with PLOG, fix it.
LOG(ERROR) << "Random read failed";
return false;
@ -60,7 +75,7 @@ static std::string generateKeyRef(const char* key, int length) {
return std::string((char*)key_ref2, EXT4_KEY_DESCRIPTOR_SIZE);
}
static bool fillKey(const std::string& key, ext4_encryption_key* ext4_key) {
static bool fillKey(const KeyBuffer& key, ext4_encryption_key* ext4_key) {
if (key.size() != EXT4_AES_256_XTS_KEY_SIZE) {
LOG(ERROR) << "Wrong size key " << key.size();
return false;
@ -83,7 +98,7 @@ static char const* const NAME_PREFIXES[] = {
static std::string keyname(const std::string& prefix, const std::string& raw_ref) {
std::ostringstream o;
o << prefix << ":";
for (auto i : raw_ref) {
for (unsigned char i : raw_ref) {
o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
}
return o.str();
@ -101,8 +116,11 @@ static bool e4cryptKeyring(key_serial_t* device_keyring) {
// Install password into global keyring
// Return raw key reference for use in policy
bool installKey(const std::string& key, std::string* raw_ref) {
ext4_encryption_key ext4_key;
bool installKey(const KeyBuffer& key, std::string* raw_ref) {
// Place ext4_encryption_key into automatically zeroing buffer.
KeyBuffer ext4KeyBuffer(sizeof(ext4_encryption_key));
ext4_encryption_key &ext4_key = *reinterpret_cast<ext4_encryption_key*>(ext4KeyBuffer.data());
if (!fillKey(key, &ext4_key)) return false;
*raw_ref = generateKeyRef(ext4_key.raw, ext4_key.size);
key_serial_t device_keyring;
@ -145,7 +163,7 @@ 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) {
std::string key;
KeyBuffer key;
if (pathExists(key_path)) {
LOG(DEBUG) << "Key exists, using: " << key_path;
if (!retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
@ -168,7 +186,7 @@ bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
}
bool retrieveKey(bool create_if_absent, const std::string& key_path,
const std::string& tmp_path, std::string* key) {
const std::string& tmp_path, KeyBuffer* key) {
if (pathExists(key_path)) {
LOG(DEBUG) << "Key exists, using: " << key_path;
if (!retrieveKey(key_path, kEmptyAuthentication, key)) return false;

@ -17,32 +17,21 @@
#ifndef ANDROID_VOLD_KEYUTIL_H
#define ANDROID_VOLD_KEYUTIL_H
#include "KeyBuffer.h"
#include <string>
#include <memory>
namespace android {
namespace vold {
// ext4enc:TODO get this const from somewhere good
const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
// ext4enc:TODO Include structure from somewhere sensible
// MUST be in sync with ext4_crypto.c in kernel
constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64;
constexpr int EXT4_MAX_KEY_SIZE = 64;
struct ext4_encryption_key {
uint32_t mode;
char raw[EXT4_MAX_KEY_SIZE];
uint32_t size;
};
bool randomKey(std::string* key);
bool installKey(const std::string& key, std::string* raw_ref);
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 retrieveKey(bool create_if_absent, const std::string& key_path,
const std::string& tmp_path, std::string* key);
const std::string& tmp_path, KeyBuffer* key);
} // namespace vold
} // namespace android

@ -31,25 +31,23 @@ KeymasterOperation::~KeymasterOperation() {
if (mDevice.get()) mDevice->abort(mOpHandle);
}
bool KeymasterOperation::updateCompletely(const std::string& input, std::string* output) {
if (output)
output->clear();
auto it = input.begin();
uint32_t inputConsumed;
bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen,
const std::function<void(const char*, size_t)> consumer) {
uint32_t inputConsumed = 0;
ErrorCode km_error;
auto hidlCB = [&] (ErrorCode ret, uint32_t _inputConsumed,
auto hidlCB = [&] (ErrorCode ret, uint32_t inputConsumedDelta,
const hidl_vec<KeyParameter>& /*ignored*/, const hidl_vec<uint8_t>& _output) {
km_error = ret;
if (km_error != ErrorCode::OK) return;
inputConsumed = _inputConsumed;
if (output)
output->append(reinterpret_cast<const char*>(&_output[0]), _output.size());
inputConsumed += inputConsumedDelta;
consumer(reinterpret_cast<const char*>(&_output[0]), _output.size());
};
while (it != input.end()) {
size_t toRead = static_cast<size_t>(input.end() - it);
auto inputBlob = blob2hidlVec(reinterpret_cast<const uint8_t*>(&*it), toRead);
while (inputConsumed != inputLen) {
size_t toRead = static_cast<size_t>(inputLen - inputConsumed);
auto inputBlob =
blob2hidlVec(reinterpret_cast<const uint8_t*>(&input[inputConsumed]), toRead);
auto error = mDevice->update(mOpHandle, hidl_vec<KeyParameter>(), inputBlob, hidlCB);
if (!error.isOk()) {
LOG(ERROR) << "update failed: " << error.description();
@ -61,12 +59,11 @@ bool KeymasterOperation::updateCompletely(const std::string& input, std::string*
mDevice = nullptr;
return false;
}
if (inputConsumed > toRead) {
if (inputConsumed > inputLen) {
LOG(ERROR) << "update reported too much input consumed";
mDevice = nullptr;
return false;
}
it += inputConsumed;
}
return true;
}

@ -19,6 +19,8 @@
#ifdef __cplusplus
#include "KeyBuffer.h"
#include <memory>
#include <string>
#include <utility>
@ -51,7 +53,14 @@ class KeymasterOperation {
ErrorCode errorCode() { return mError; }
// Call "update" repeatedly until all of the input is consumed, and
// concatenate the output. Return true on success.
bool updateCompletely(const std::string& input, std::string* output);
template <class TI, class TO>
bool updateCompletely(TI& input, TO* output) {
if (output) output->clear();
return updateCompletely(input.data(), input.size(), [&](const char* b, size_t n) {
if (output) std::copy(b, b+n, std::back_inserter(*output));
});
}
// Finish and write the output to this string, unless pointer is null.
bool finish(std::string* output);
// Move constructor
@ -80,6 +89,10 @@ class KeymasterOperation {
KeymasterOperation(ErrorCode error)
: mDevice{nullptr}, mOpHandle{0},
mError {error} {}
bool updateCompletely(const char* input, size_t inputLen,
const std::function<void(const char*, size_t)> consumer);
sp<IKeymasterDevice> mDevice;
uint64_t mOpHandle;
ErrorCode mError;

@ -14,11 +14,13 @@
* limitations under the License.
*/
#include "KeyBuffer.h"
#include "MetadataCrypt.h"
#include <string>
#include <thread>
#include <vector>
#include <algorithm>
#include <fcntl.h>
#include <sys/ioctl.h>
@ -29,10 +31,10 @@
#include <linux/dm-ioctl.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
#include <fs_mgr.h>
#include "AutoCloseFD.h"
#include "EncryptInplace.h"
#include "KeyStorage.h"
#include "KeyUtil.h"
@ -45,6 +47,8 @@ extern struct fstab *fstab;
#define TABLE_LOAD_RETRIES 10
#define DEFAULT_KEY_TARGET_TYPE "default-key"
using android::vold::KeyBuffer;
static const std::string kDmNameUserdata = "userdata";
static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
@ -68,7 +72,7 @@ static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
return true;
}
static bool read_key(bool create_if_absent, std::string* key) {
static bool read_key(bool create_if_absent, KeyBuffer* key) {
auto data_rec = fs_mgr_get_crypt_entry(fstab);
if (!data_rec) {
LOG(ERROR) << "Failed to get data_rec";
@ -93,20 +97,21 @@ static bool read_key(bool create_if_absent, std::string* key) {
return true;
}
static std::string default_key_params(const std::string& real_blkdev, const std::string& key) {
std::string hex_key;
static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuffer& key) {
KeyBuffer hex_key;
if (android::vold::StrToHex(key, hex_key) != android::OK) {
LOG(ERROR) << "Failed to turn key to hex";
return "";
return KeyBuffer();
}
auto res = std::string() + "AES-256-XTS " + hex_key + " " + real_blkdev + " 0";
LOG(DEBUG) << "crypt_params: " << res;
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;
}
static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t *nr_sec) {
AutoCloseFD dev_fd(real_blkdev, O_RDONLY);
if (!dev_fd) {
android::base::unique_fd dev_fd(TEMP_FAILURE_RETRY(open(
real_blkdev.c_str(), O_RDONLY | O_CLOEXEC, 0)));
if (dev_fd == -1) {
PLOG(ERROR) << "Unable to open " << real_blkdev << " to measure size";
return false;
}
@ -141,10 +146,11 @@ static struct dm_ioctl* dm_ioctl_init(char *buffer, size_t buffer_size,
}
static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec,
const std::string& target_type, const std::string& crypt_params,
const std::string& target_type, const KeyBuffer& crypt_params,
std::string* crypto_blkdev) {
AutoCloseFD dm_fd("/dev/device-mapper", O_RDWR);
if (!dm_fd) {
android::base::unique_fd dm_fd(TEMP_FAILURE_RETRY(open(
"/dev/device-mapper", O_RDWR | O_CLOEXEC, 0)));
if (dm_fd == -1) {
PLOG(ERROR) << "Cannot open device-mapper";
return false;
}
@ -165,9 +171,9 @@ static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec,
(io->dev & 0xff) | ((io->dev >> 12) & 0xfff00));
io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
unsigned long paramix = io->data_start + sizeof(struct dm_target_spec);
unsigned long nullix = paramix + crypt_params.size();
unsigned long endix = (nullix + 1 + 7) & 8; // Add room for \0 and align to 8 byte boundary
size_t paramix = io->data_start + sizeof(struct dm_target_spec);
size_t nullix = paramix + crypt_params.size();
size_t endix = (nullix + 1 + 7) & 8; // Add room for \0 and align to 8 byte boundary
if (endix > sizeof(buffer)) {
LOG(ERROR) << "crypt_params too big for DM_CRYPT_BUF_SIZE";
@ -180,7 +186,8 @@ static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec,
tgt->sector_start = 0;
tgt->length = nr_sec;
target_type.copy(tgt->target_type, sizeof(tgt->target_type));
crypt_params.copy(buffer + paramix, sizeof(buffer) - paramix);
memcpy(buffer + paramix, crypt_params.data(),
std::min(crypt_params.size(), sizeof(buffer) - paramix));
buffer[nullix] = '\0';
tgt->next = endix;
@ -244,7 +251,7 @@ static void async_kick_off() {
bool e4crypt_mount_metadata_encrypted() {
LOG(DEBUG) << "e4crypt_mount_default_encrypted";
std::string key;
KeyBuffer key;
if (!read_key(false, &key)) return false;
auto data_rec = fs_mgr_get_crypt_entry(fstab);
if (!data_rec) {
@ -273,7 +280,7 @@ bool e4crypt_enable_crypto() {
return false;
}
std::string key_ref;
KeyBuffer key_ref;
if (!read_key(true, &key_ref)) return false;
auto data_rec = fs_mgr_get_crypt_entry(fstab);

@ -62,7 +62,8 @@ static void notifyProgress(int progress) {
StringPrintf("%d", progress).c_str(), false);
}
static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd) {
static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd,
bool addWildcard) {
DIR* dir = opendir(path.c_str());
if (dir == NULL) {
return -1;
@ -73,7 +74,11 @@ static status_t pushBackContents(const std::string& path, std::vector<std::strin
if ((!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, ".."))) {
continue;
}
cmd.push_back(StringPrintf("%s/%s", path.c_str(), ent->d_name));
if (addWildcard) {
cmd.push_back(StringPrintf("%s/%s/*", path.c_str(), ent->d_name));
} else {
cmd.push_back(StringPrintf("%s/%s", path.c_str(), ent->d_name));
}
found = true;
}
closedir(dir);
@ -90,7 +95,7 @@ static status_t execRm(const std::string& path, int startProgress, int stepProgr
cmd.push_back(kRmPath);
cmd.push_back("-f"); /* force: remove without confirmation, no error if it doesn't exist */
cmd.push_back("-R"); /* recursive: remove directory contents */
if (pushBackContents(path, cmd) != OK) {
if (pushBackContents(path, cmd, true) != OK) {
LOG(WARNING) << "No contents in " << path;
return OK;
}
@ -140,7 +145,7 @@ static status_t execCp(const std::string& fromPath, const std::string& toPath,
cmd.push_back("-R"); /* recurse into subdirectories (DEST must be a directory) */
cmd.push_back("-P"); /* Do not follow symlinks [default] */
cmd.push_back("-d"); /* don't dereference symlinks */
if (pushBackContents(fromPath, cmd) != OK) {
if (pushBackContents(fromPath, cmd, false) != OK) {
LOG(WARNING) << "No contents in " << fromPath;
return OK;
}

@ -190,6 +190,8 @@ status_t PublicVolume::doMount() {
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
usleep(50000); // 50ms
}
/* sdcardfs will have exited already. FUSE will still be running */
TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
return OK;
}

@ -351,18 +351,20 @@ pid_t ForkExecvpAsync(const std::vector<std::string>& args) {
}
status_t ReadRandomBytes(size_t bytes, std::string& out) {
out.clear();
out.resize(bytes);
return ReadRandomBytes(bytes, &out[0]);
}
status_t ReadRandomBytes(size_t bytes, char* buf) {
int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
if (fd == -1) {
return -errno;
}
char buf[BUFSIZ];
size_t n;
while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], std::min(sizeof(buf), bytes)))) > 0) {
out.append(buf, n);
while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], bytes))) > 0) {
bytes -= n;
buf += n;
}
close(fd);
@ -373,6 +375,17 @@ status_t ReadRandomBytes(size_t bytes, std::string& out) {
}
}
status_t GenerateRandomUuid(std::string& out) {
status_t res = ReadRandomBytes(16, out);
if (res == OK) {
out[6] &= 0x0f; /* clear version */
out[6] |= 0x40; /* set to version 4 */
out[8] &= 0x3f; /* clear variant */
out[8] |= 0x80; /* set to IETF variant */
}
return res;
}
status_t HexToStr(const std::string& hex, std::string& str) {
str.clear();
bool even = true;
@ -423,6 +436,15 @@ status_t StrToHex(const std::string& str, std::string& hex) {
return OK;
}
status_t StrToHex(const KeyBuffer& str, KeyBuffer& hex) {
hex.clear();
for (size_t i = 0; i < str.size(); i++) {
hex.push_back(kLookup[(str.data()[i] & 0xF0) >> 4]);
hex.push_back(kLookup[str.data()[i] & 0x0F]);
}
return OK;
}
status_t NormalizeHex(const std::string& in, std::string& out) {
std::string tmp;
if (HexToStr(in, tmp)) {

@ -17,6 +17,8 @@
#ifndef ANDROID_VOLD_UTILS_H
#define ANDROID_VOLD_UTILS_H
#include "KeyBuffer.h"
#include <utils/Errors.h>
#include <cutils/multiuser.h>
#include <selinux/selinux.h>
@ -78,11 +80,15 @@ status_t ForkExecvp(const std::vector<std::string>& args,
pid_t ForkExecvpAsync(const std::vector<std::string>& args);
status_t ReadRandomBytes(size_t bytes, std::string& out);
status_t ReadRandomBytes(size_t bytes, char* buffer);
status_t GenerateRandomUuid(std::string& out);
/* Converts hex string to raw bytes, ignoring [ :-] */
status_t HexToStr(const std::string& hex, std::string& str);
/* Converts raw bytes to hex string */
status_t StrToHex(const std::string& str, std::string& hex);
/* Converts raw key bytes to hex string */
status_t StrToHex(const KeyBuffer& str, KeyBuffer& hex);
/* Normalize given hex string into consistent format */
status_t NormalizeHex(const std::string& in, std::string& out);

@ -1326,29 +1326,24 @@ int wait_and_unmount(const char *mountpoint, bool kill)
return rc;
}
static int prep_data_fs(void)
static void prep_data_fs(void)
{
int i;
// 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");
SLOGD("Just triggered post_fs_data\n");
SLOGD("Just triggered post_fs_data");
/* Wait a max of 50 seconds, hopefully it takes much less */
if (!android::base::WaitForProperty("vold.post_fs_data_done",
while (!android::base::WaitForProperty("vold.post_fs_data_done",
"1",
std::chrono::seconds(50))) {
/* Ugh, we failed to prep /data in time. Bail. */
SLOGE("post_fs_data timed out!\n");
return -1;
} else {
SLOGD("post_fs_data done\n");
return 0;
std::chrono::seconds(15))) {
/* We timed out to prep /data in time. Continue wait. */
SLOGE("waited 15s for vold.post_fs_data_done, still waiting...");
}
SLOGD("post_fs_data done");
}
static void cryptfs_set_corrupt()
@ -1499,9 +1494,7 @@ static int cryptfs_restart_internal(int restart_main)
}
/* Create necessary paths on /data */
if (prep_data_fs()) {
return -1;
}
prep_data_fs();
property_set("vold.decrypt", "trigger_load_persist_props");
/* startup service classes main and late_start */
@ -2240,9 +2233,7 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, const char *passwd,
/* restart the framework. */
/* Create necessary paths on /data */
if (prep_data_fs()) {
goto error_shutting_down;
}
prep_data_fs();
/* Ugh, shutting down the framework is not synchronous, so until it
* can be fixed, this horrible hack will wait a moment for it all to

@ -38,6 +38,7 @@
#define LOG_TAG "Vold"
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <cutils/log.h>
#include <cutils/properties.h>
@ -45,6 +46,7 @@
#include <selinux/selinux.h>
#include "Ext4.h"
#include "Ext4Crypt.h"
#include "Utils.h"
#include "VoldUtil.h"
@ -55,11 +57,7 @@ namespace vold {
namespace ext4 {
static const char* kResizefsPath = "/system/bin/resize2fs";
#ifdef TARGET_USES_MKE2FS
static const char* kMkfsPath = "/system/bin/mke2fs";
#else
static const char* kMkfsPath = "/system/bin/make_ext4fs";
#endif
static const char* kFsckPath = "/system/bin/e2fsck";
bool IsSupported() {
@ -170,7 +168,6 @@ status_t Format(const std::string& source, unsigned long numSectors,
std::vector<std::string> cmd;
cmd.push_back(kMkfsPath);
#ifdef TARGET_USES_MKE2FS
cmd.push_back("-b");
cmd.push_back("4096");
@ -180,29 +177,23 @@ status_t Format(const std::string& source, unsigned long numSectors,
cmd.push_back("-M");
cmd.push_back(target);
std::string options("has_journal");
if (android::base::GetBoolProperty("vold.has_quota", false)) {
options += ",quota";
}
if (e4crypt_is_native()) {
options += ",encrypt";
}
cmd.push_back("-O");
cmd.push_back("^has_journal");
cmd.push_back(options);
cmd.push_back(source);
if (numSectors)
cmd.push_back(StringPrintf("%lu", numSectors * (4096 / 512)));
#else
cmd.push_back("-J");
cmd.push_back("-a");
cmd.push_back(target);
if (numSectors) {
cmd.push_back("-l");
cmd.push_back(StringPrintf("%lu", numSectors * 512));
cmd.push_back(StringPrintf("%lu", numSectors * (4096 / 512)));
}
// Always generate a real UUID
cmd.push_back("-u");
cmd.push_back(source);
#endif
return ForkExecvp(cmd);
}

@ -133,7 +133,7 @@ status_t Mount(const std::string& source, const std::string& target, bool ro,
const char* c_source = source.c_str();
const char* c_target = target.c_str();
flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC;
flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC | MS_NOATIME;
flags |= (executable ? 0 : MS_NOEXEC);
flags |= (ro ? MS_RDONLY : 0);

@ -39,7 +39,7 @@
#include <dirent.h>
#include <fs_mgr.h>
static int process_config(VolumeManager *vm, bool* has_adoptable);
static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota);
static void coldboot(const char *path);
static void parse_args(int argc, char** argv);
@ -107,8 +107,9 @@ int main(int argc, char** argv) {
}
bool has_adoptable;
bool has_quota;
if (process_config(vm, &has_adoptable)) {
if (process_config(vm, &has_adoptable, &has_quota)) {
PLOG(ERROR) << "Error reading configuration... continuing anyways";
}
@ -133,6 +134,7 @@ 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");
// Do coldboot here so it won't block booting,
// also the cold boot is needed in case we have flash drive
@ -214,7 +216,7 @@ static void coldboot(const char *path) {
}
}
static int process_config(VolumeManager *vm, bool* has_adoptable) {
static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota) {
fstab = fs_mgr_read_fstab_default();
if (!fstab) {
PLOG(ERROR) << "Failed to open default fstab";
@ -223,7 +225,12 @@ static int process_config(VolumeManager *vm, bool* has_adoptable) {
/* Loop through entries looking for ones that vold manages */
*has_adoptable = false;
*has_quota = false;
for (int i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_is_quota(&fstab->recs[i])) {
*has_quota = true;
}
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
LOG(WARNING) << "nonremovable no longer supported; ignoring volume";

@ -29,8 +29,9 @@
#include <mntent.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <AutoCloseFD.h>
#include "FileDeviceUtils.h"
namespace {
@ -44,10 +45,7 @@ constexpr uint32_t max_extents = 32;
bool read_command_line(int argc, const char * const argv[], Options &options);
void usage(const char *progname);
bool secdiscard_path(const std::string &path);
std::unique_ptr<struct fiemap> path_fiemap(const std::string &path, uint32_t extent_count);
bool check_fiemap(const struct fiemap &fiemap, const std::string &path);
std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count);
std::string block_device_for_path(const std::string &path);
bool overwrite_with_zeros(int fd, off64_t start, off64_t length);
}
@ -99,16 +97,17 @@ void usage(const char *progname) {
// BLKSECDISCARD all content in "path", if it's small enough.
bool secdiscard_path(const std::string &path) {
auto fiemap = path_fiemap(path, max_extents);
auto fiemap = android::vold::PathFiemap(path, max_extents);
if (!fiemap || !check_fiemap(*fiemap, path)) {
return false;
}
auto block_device = block_device_for_path(path);
auto block_device = android::vold::BlockDeviceForPath(path);
if (block_device.empty()) {
return false;
}
AutoCloseFD fs_fd(block_device, O_RDWR | O_LARGEFILE);
if (!fs_fd) {
android::base::unique_fd fs_fd(TEMP_FAILURE_RETRY(open(
block_device.c_str(), O_RDWR | O_LARGEFILE | O_CLOEXEC, 0)));
if (fs_fd == -1) {
PLOG(ERROR) << "Failed to open device " << block_device;
return false;
}
@ -125,32 +124,6 @@ bool secdiscard_path(const std::string &path) {
return true;
}
// Read the file's FIEMAP
std::unique_ptr<struct fiemap> path_fiemap(const std::string &path, uint32_t extent_count)
{
AutoCloseFD fd(path);
if (!fd) {
if (errno == ENOENT) {
PLOG(DEBUG) << "Unable to open " << path;
} else {
PLOG(ERROR) << "Unable to open " << path;
}
return nullptr;
}
auto fiemap = alloc_fiemap(extent_count);
if (ioctl(fd.get(), FS_IOC_FIEMAP, fiemap.get()) != 0) {
PLOG(ERROR) << "Unable to FIEMAP " << path;
return nullptr;
}
auto mapped = fiemap->fm_mapped_extents;
if (mapped < 1 || mapped > extent_count) {
LOG(ERROR) << "Extent count not in bounds 1 <= " << mapped << " <= " << extent_count
<< " in " << path;
return nullptr;
}
return fiemap;
}
// Ensure that the FIEMAP covers the file and is OK to discard
bool check_fiemap(const struct fiemap &fiemap, const std::string &path) {
auto mapped = fiemap.fm_mapped_extents;
@ -168,48 +141,6 @@ bool check_fiemap(const struct fiemap &fiemap, const std::string &path) {
return true;
}
std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count)
{
size_t allocsize = offsetof(struct fiemap, fm_extents[extent_count]);
std::unique_ptr<struct fiemap> res(new (::operator new (allocsize)) struct fiemap);
memset(res.get(), 0, allocsize);
res->fm_start = 0;
res->fm_length = UINT64_MAX;
res->fm_flags = 0;
res->fm_extent_count = extent_count;
res->fm_mapped_extents = 0;
return res;
}
// Given a file path, look for the corresponding block device in /proc/mount
std::string block_device_for_path(const std::string &path)
{
std::unique_ptr<FILE, int(*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
if (!mnts) {
PLOG(ERROR) << "Unable to open /proc/mounts";
return "";
}
std::string result;
size_t best_length = 0;
struct mntent *mnt; // getmntent returns a thread local, so it's safe.
while ((mnt = getmntent(mnts.get())) != nullptr) {
auto l = strlen(mnt->mnt_dir);
if (l > best_length &&
path.size() > l &&
path[l] == '/' &&
path.compare(0, l, mnt->mnt_dir) == 0) {
result = mnt->mnt_fsname;
best_length = l;
}
}
if (result.empty()) {
LOG(ERROR) <<"Didn't find a mountpoint to match path " << path;
return "";
}
LOG(DEBUG) << "For path " << path << " block device is " << result;
return result;
}
bool overwrite_with_zeros(int fd, off64_t start, off64_t length) {
if (lseek64(fd, start, SEEK_SET) != start) {
PLOG(ERROR) << "Seek failed for zero overwrite";

Loading…
Cancel
Save