9c48498f45
This adds support for private volumes which is just a filesystem wrapped in a dm-crypt layer. For now we're using the exact same configuration as internal encryption (aes-cbc-essiv:sha256), but we don't store any key material on the removable media. Instead, we store the key on internal storage, and use the GPT partition GUID to identify which key should be used. This means that private external storage is effectively as secure as the internal storage of the device. That is, if the internal storage is encrypted, then our external storage key is also encrypted. When partitioning disks, we now support a "private" mode which has a PrivateVolume partition, and a currently unused 16MB metadata partition reserved for future use. It also supports a "mixed" mode which creates both a PublicVolume and PrivateVolume on the same disk. Mixed mode is currently experimental. For now, just add ext4 support to PrivateVolume; we'll look at f2fs in a future change. Add VolumeBase lifecycle for setting up crypto mappings, and extract blkid logic into shared method. Sprinkle some more "static" around the cryptfs code to improve invariants. Bug: 19993667 Change-Id: Ibd1df6250735b706959a1eb9d9f7219ea85912a0
202 lines
4.8 KiB
C++
202 lines
4.8 KiB
C++
/*
|
|
* 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 "Utils.h"
|
|
#include "VolumeBase.h"
|
|
#include "VolumeManager.h"
|
|
#include "ResponseCode.h"
|
|
|
|
#include <base/stringprintf.h>
|
|
#include <base/logging.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
using android::base::StringPrintf;
|
|
|
|
#define DEBUG 1
|
|
|
|
namespace android {
|
|
namespace vold {
|
|
|
|
VolumeBase::VolumeBase(Type type) :
|
|
mType(type), mFlags(0), mUser(-1), mCreated(false), mState(State::kUnmounted) {
|
|
}
|
|
|
|
VolumeBase::~VolumeBase() {
|
|
CHECK(!mCreated);
|
|
}
|
|
|
|
void VolumeBase::setState(State state) {
|
|
mState = state;
|
|
|
|
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
|
|
ResponseCode::VolumeStateChanged,
|
|
StringPrintf("%s %d", getId().c_str(), mState).c_str(), false);
|
|
}
|
|
|
|
status_t VolumeBase::setFlags(int flags) {
|
|
if (mState != State::kUnmounted) {
|
|
LOG(WARNING) << getId() << " flags change requires state unmounted";
|
|
return -EBUSY;
|
|
}
|
|
|
|
mFlags = flags;
|
|
return OK;
|
|
}
|
|
|
|
status_t VolumeBase::setUser(userid_t user) {
|
|
if (mState != State::kUnmounted) {
|
|
LOG(WARNING) << getId() << " user change requires state unmounted";
|
|
return -EBUSY;
|
|
}
|
|
|
|
mUser = user;
|
|
return OK;
|
|
}
|
|
|
|
status_t VolumeBase::setId(const std::string& id) {
|
|
if (mCreated) {
|
|
LOG(WARNING) << getId() << " id change requires not created";
|
|
return -EBUSY;
|
|
}
|
|
|
|
mId = id;
|
|
return OK;
|
|
}
|
|
|
|
status_t VolumeBase::setPath(const std::string& path) {
|
|
if (mState != State::kMounting) {
|
|
LOG(WARNING) << getId() << " path change requires state mounting";
|
|
return -EBUSY;
|
|
}
|
|
|
|
mPath = path;
|
|
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
|
|
ResponseCode::VolumePathChanged,
|
|
StringPrintf("%s %s", getId().c_str(), mPath.c_str()).c_str(), false);
|
|
return OK;
|
|
}
|
|
|
|
void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
|
|
mVolumes.push_back(volume);
|
|
}
|
|
|
|
void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) {
|
|
mVolumes.remove(volume);
|
|
}
|
|
|
|
std::shared_ptr<VolumeBase> VolumeBase::findVolume(const std::string& id) {
|
|
for (auto vol : mVolumes) {
|
|
if (vol->getId() == id) {
|
|
return vol;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
status_t VolumeBase::create() {
|
|
CHECK(!mCreated);
|
|
|
|
mCreated = true;
|
|
status_t res = doCreate();
|
|
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
|
|
ResponseCode::VolumeCreated,
|
|
StringPrintf("%s %d", getId().c_str(), mType).c_str(), false);
|
|
return res;
|
|
}
|
|
|
|
status_t VolumeBase::doCreate() {
|
|
return OK;
|
|
}
|
|
|
|
status_t VolumeBase::destroy() {
|
|
CHECK(mCreated);
|
|
|
|
if (mState == State::kMounted) {
|
|
unmount();
|
|
}
|
|
|
|
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
|
|
ResponseCode::VolumeDestroyed, getId().c_str(), false);
|
|
status_t res = doDestroy();
|
|
mCreated = false;
|
|
return res;
|
|
}
|
|
|
|
status_t VolumeBase::doDestroy() {
|
|
return OK;
|
|
}
|
|
|
|
status_t VolumeBase::mount() {
|
|
if (mState != State::kUnmounted) {
|
|
LOG(WARNING) << getId() << " mount requires state unmounted";
|
|
return -EBUSY;
|
|
}
|
|
|
|
setState(State::kMounting);
|
|
status_t res = doMount();
|
|
if (res == OK) {
|
|
setState(State::kMounted);
|
|
} else {
|
|
setState(State::kUnmounted);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
status_t VolumeBase::unmount() {
|
|
if (mState != State::kMounted) {
|
|
LOG(WARNING) << getId() << " unmount requires state mounted";
|
|
return -EBUSY;
|
|
}
|
|
|
|
setState(State::kUnmounting);
|
|
|
|
for (auto vol : mVolumes) {
|
|
if (vol->unmount()) {
|
|
LOG(WARNING) << getId() << " failed to unmount " << vol->getId()
|
|
<< " stacked above";
|
|
}
|
|
}
|
|
mVolumes.clear();
|
|
|
|
status_t res = doUnmount();
|
|
setState(State::kUnmounted);
|
|
return res;
|
|
}
|
|
|
|
status_t VolumeBase::format() {
|
|
if (mState != State::kUnmounted) {
|
|
LOG(WARNING) << getId() << " format requires state unmounted";
|
|
return -EBUSY;
|
|
}
|
|
|
|
setState(State::kFormatting);
|
|
status_t res = doFormat();
|
|
setState(State::kUnmounted);
|
|
return res;
|
|
}
|
|
|
|
status_t VolumeBase::doFormat() {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
} // namespace vold
|
|
} // namespace android
|