2015-03-03 06:01:40 +01:00
|
|
|
/*
|
|
|
|
* 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 "Disk.h"
|
2018-10-23 22:06:55 +02:00
|
|
|
#include "FsCrypt.h"
|
2015-03-31 19:35:33 +02:00
|
|
|
#include "PrivateVolume.h"
|
2018-09-18 22:30:21 +02:00
|
|
|
#include "PublicVolume.h"
|
2015-03-03 06:01:40 +01:00
|
|
|
#include "Utils.h"
|
|
|
|
#include "VolumeBase.h"
|
2015-03-14 00:09:20 +01:00
|
|
|
#include "VolumeManager.h"
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2015-12-05 00:50:53 +01:00
|
|
|
#include <android-base/file.h>
|
2017-10-09 19:55:21 +02:00
|
|
|
#include <android-base/logging.h>
|
2018-09-18 22:30:21 +02:00
|
|
|
#include <android-base/parseint.h>
|
Progress towards FBE and adoptable storage.
Offer to adopt storage devices on FBE devices, but keep it guarded
behind a system property for now, since we still need to work out key
storage details.
When migrating shared storage, leave user-specific /data/media
directories in place, since they already have the needed crypto
policies defined.
Enable journaling, quotas, and encrypt options when formatting
newly adopted devices. installd already gracefully handles older
partitions without quota enabled.
Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest
Bug: 62290006, 36757864, 29117062, 37395736
Bug: 29923055, 25861755, 30230655, 37436961
Change-Id: Ibbeb6ec9db2394a279bbac221a2b20711d65494e
2017-06-21 21:52:23 +02:00
|
|
|
#include <android-base/properties.h>
|
2015-12-05 00:50:53 +01:00
|
|
|
#include <android-base/stringprintf.h>
|
2017-10-07 02:02:53 +02:00
|
|
|
#include <android-base/strings.h>
|
2018-10-23 22:06:55 +02:00
|
|
|
#include <fscrypt/fscrypt.h>
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2018-02-16 22:13:58 +01:00
|
|
|
#include "cryptfs.h"
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
#include <fcntl.h>
|
2015-03-31 06:22:07 +02:00
|
|
|
#include <inttypes.h>
|
2015-03-03 06:01:40 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2018-09-18 22:30:21 +02:00
|
|
|
#include <sys/mount.h>
|
2015-03-03 06:01:40 +01:00
|
|
|
#include <sys/stat.h>
|
2017-05-18 18:08:24 +02:00
|
|
|
#include <sys/sysmacros.h>
|
2018-09-18 22:30:21 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <vector>
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2015-03-16 18:35:17 +01:00
|
|
|
using android::base::ReadFileToString;
|
|
|
|
using android::base::StringPrintf;
|
2018-09-18 22:30:21 +02:00
|
|
|
using android::base::WriteStringToFile;
|
2015-03-16 18:35:17 +01:00
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
namespace android {
|
|
|
|
namespace vold {
|
|
|
|
|
|
|
|
static const char* kSgdiskPath = "/system/bin/sgdisk";
|
|
|
|
static const char* kSgdiskToken = " \t\n";
|
|
|
|
|
2017-03-26 06:49:13 +02:00
|
|
|
static const char* kSysfsLoopMaxMinors = "/sys/module/loop/parameters/max_part";
|
2017-11-28 15:42:56 +01:00
|
|
|
static const char* kSysfsMmcMaxMinorsDeprecated = "/sys/module/mmcblk/parameters/perdev_minors";
|
|
|
|
static const char* kSysfsMmcMaxMinors = "/sys/module/mmc_block/parameters/perdev_minors";
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2017-03-26 06:49:13 +02:00
|
|
|
static const unsigned int kMajorBlockLoop = 7;
|
2015-04-20 00:55:42 +02:00
|
|
|
static const unsigned int kMajorBlockScsiA = 8;
|
|
|
|
static const unsigned int kMajorBlockScsiB = 65;
|
|
|
|
static const unsigned int kMajorBlockScsiC = 66;
|
|
|
|
static const unsigned int kMajorBlockScsiD = 67;
|
|
|
|
static const unsigned int kMajorBlockScsiE = 68;
|
|
|
|
static const unsigned int kMajorBlockScsiF = 69;
|
|
|
|
static const unsigned int kMajorBlockScsiG = 70;
|
|
|
|
static const unsigned int kMajorBlockScsiH = 71;
|
|
|
|
static const unsigned int kMajorBlockScsiI = 128;
|
|
|
|
static const unsigned int kMajorBlockScsiJ = 129;
|
|
|
|
static const unsigned int kMajorBlockScsiK = 130;
|
|
|
|
static const unsigned int kMajorBlockScsiL = 131;
|
|
|
|
static const unsigned int kMajorBlockScsiM = 132;
|
|
|
|
static const unsigned int kMajorBlockScsiN = 133;
|
|
|
|
static const unsigned int kMajorBlockScsiO = 134;
|
|
|
|
static const unsigned int kMajorBlockScsiP = 135;
|
2015-03-03 06:01:40 +01:00
|
|
|
static const unsigned int kMajorBlockMmc = 179;
|
2016-01-08 10:36:47 +01:00
|
|
|
static const unsigned int kMajorBlockExperimentalMin = 240;
|
|
|
|
static const unsigned int kMajorBlockExperimentalMax = 254;
|
2018-05-12 02:22:42 +02:00
|
|
|
static const unsigned int kMajorBlockDynamicMin = 234;
|
|
|
|
static const unsigned int kMajorBlockDynamicMax = 512;
|
2015-03-03 06:01:40 +01:00
|
|
|
|
|
|
|
static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7";
|
|
|
|
static const char* kGptAndroidMeta = "19A710A2-B3CA-11E4-B026-10604B889DCF";
|
2015-04-09 06:07:21 +02:00
|
|
|
static const char* kGptAndroidExpand = "193D1EA4-B3CA-11E4-B075-10604B889DCF";
|
2015-03-03 06:01:40 +01:00
|
|
|
|
|
|
|
enum class Table {
|
|
|
|
kUnknown,
|
|
|
|
kMbr,
|
|
|
|
kGpt,
|
|
|
|
};
|
|
|
|
|
2016-01-08 10:36:47 +01:00
|
|
|
static bool isVirtioBlkDevice(unsigned int major) {
|
|
|
|
/*
|
|
|
|
* The new emulator's "ranchu" virtual board no longer includes a goldfish
|
|
|
|
* MMC-based SD card device; instead, it emulates SD cards with virtio-blk,
|
|
|
|
* which has been supported by upstream kernel and QEMU for quite a while.
|
|
|
|
* Unfortunately, the virtio-blk block device driver does not use a fixed
|
|
|
|
* major number, but relies on the kernel to assign one from a specific
|
|
|
|
* range of block majors, which are allocated for "LOCAL/EXPERIMENAL USE"
|
|
|
|
* per Documentation/devices.txt. This is true even for the latest Linux
|
|
|
|
* kernel (4.4; see init() in drivers/block/virtio_blk.c).
|
|
|
|
*
|
|
|
|
* This makes it difficult for vold to detect a virtio-blk based SD card.
|
|
|
|
* The current solution checks two conditions (both must be met):
|
|
|
|
*
|
|
|
|
* a) If the running environment is the emulator;
|
|
|
|
* b) If the major number is an experimental block device major number (for
|
|
|
|
* x86/x86_64 3.10 ranchu kernels, virtio-blk always gets major number
|
|
|
|
* 253, but it is safer to match the range than just one value).
|
|
|
|
*
|
|
|
|
* Other conditions could be used, too, e.g. the hardware name should be
|
|
|
|
* "ranchu", the device's sysfs path should end with "/block/vd[d-z]", etc.
|
|
|
|
* But just having a) and b) is enough for now.
|
|
|
|
*/
|
2018-09-18 22:30:21 +02:00
|
|
|
return IsRunningInEmulator() && major >= kMajorBlockExperimentalMin &&
|
|
|
|
major <= kMajorBlockExperimentalMax;
|
2016-01-08 10:36:47 +01:00
|
|
|
}
|
|
|
|
|
2018-05-12 02:22:42 +02:00
|
|
|
static bool isNvmeBlkDevice(unsigned int major, const std::string& sysPath) {
|
2018-09-18 22:30:21 +02:00
|
|
|
return sysPath.find("nvme") != std::string::npos && major >= kMajorBlockDynamicMin &&
|
|
|
|
major <= kMajorBlockDynamicMax;
|
2018-05-12 02:22:42 +02:00
|
|
|
}
|
|
|
|
|
2018-09-18 22:30:21 +02:00
|
|
|
Disk::Disk(const std::string& eventPath, dev_t device, const std::string& nickname, int flags)
|
|
|
|
: mDevice(device),
|
|
|
|
mSize(-1),
|
|
|
|
mNickname(nickname),
|
|
|
|
mFlags(flags),
|
|
|
|
mCreated(false),
|
|
|
|
mJustPartitioned(false) {
|
2015-03-14 00:09:20 +01:00
|
|
|
mId = StringPrintf("disk:%u,%u", major(device), minor(device));
|
|
|
|
mEventPath = eventPath;
|
2015-03-03 06:01:40 +01:00
|
|
|
mSysPath = StringPrintf("/sys/%s", eventPath.c_str());
|
2015-03-14 00:09:20 +01:00
|
|
|
mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());
|
2015-03-03 06:01:40 +01:00
|
|
|
CreateDeviceNode(mDevPath, mDevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
Disk::~Disk() {
|
2015-03-14 00:09:20 +01:00
|
|
|
CHECK(!mCreated);
|
2015-03-03 06:01:40 +01:00
|
|
|
DestroyDeviceNode(mDevPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<VolumeBase> Disk::findVolume(const std::string& id) {
|
2015-03-14 00:09:20 +01:00
|
|
|
for (auto vol : mVolumes) {
|
|
|
|
if (vol->getId() == id) {
|
|
|
|
return vol;
|
|
|
|
}
|
|
|
|
auto stackedVol = vol->findVolume(id);
|
|
|
|
if (stackedVol != nullptr) {
|
|
|
|
return stackedVol;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-12-18 17:42:08 +01:00
|
|
|
void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) const {
|
2016-07-27 23:11:02 +02:00
|
|
|
for (const auto& vol : mVolumes) {
|
2015-06-26 23:02:09 +02:00
|
|
|
if (vol->getType() == type) {
|
|
|
|
list.push_back(vol->getId());
|
|
|
|
}
|
|
|
|
// TODO: consider looking at stacked volumes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
status_t Disk::create() {
|
|
|
|
CHECK(!mCreated);
|
|
|
|
mCreated = true;
|
2017-09-16 00:50:28 +02:00
|
|
|
|
2017-09-13 19:49:44 +02:00
|
|
|
auto listener = VolumeManager::Instance()->getListener();
|
|
|
|
if (listener) listener->onDiskCreated(getId(), mFlags);
|
2017-09-16 00:50:28 +02:00
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
readMetadata();
|
|
|
|
readPartitions();
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t Disk::destroy() {
|
|
|
|
CHECK(mCreated);
|
|
|
|
destroyAllVolumes();
|
|
|
|
mCreated = false;
|
2017-09-16 00:50:28 +02:00
|
|
|
|
2017-09-13 19:49:44 +02:00
|
|
|
auto listener = VolumeManager::Instance()->getListener();
|
|
|
|
if (listener) listener->onDiskDestroyed(getId());
|
2017-09-16 00:50:28 +02:00
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Disk::createPublicVolume(dev_t device) {
|
2015-03-31 19:35:33 +02:00
|
|
|
auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));
|
2015-04-09 06:07:21 +02:00
|
|
|
if (mJustPartitioned) {
|
|
|
|
LOG(DEBUG) << "Device just partitioned; silently formatting";
|
|
|
|
vol->setSilent(true);
|
|
|
|
vol->create();
|
2015-05-22 07:35:42 +02:00
|
|
|
vol->format("auto");
|
2015-04-09 06:07:21 +02:00
|
|
|
vol->destroy();
|
|
|
|
vol->setSilent(false);
|
|
|
|
}
|
2015-03-14 00:09:20 +01:00
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
mVolumes.push_back(vol);
|
2015-04-18 02:35:20 +02:00
|
|
|
vol->setDiskId(getId());
|
2015-04-09 06:07:21 +02:00
|
|
|
vol->create();
|
2015-03-14 00:09:20 +01:00
|
|
|
}
|
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
|
|
|
|
std::string normalizedGuid;
|
2015-06-18 23:25:08 +02:00
|
|
|
if (NormalizeHex(partGuid, normalizedGuid)) {
|
2015-03-31 19:35:33 +02:00
|
|
|
LOG(WARNING) << "Invalid GUID " << partGuid;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string keyRaw;
|
|
|
|
if (!ReadFileToString(BuildKeyPath(normalizedGuid), &keyRaw)) {
|
|
|
|
PLOG(ERROR) << "Failed to load key for GUID " << normalizedGuid;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG(DEBUG) << "Found key for GUID " << normalizedGuid;
|
|
|
|
|
2020-02-07 20:49:09 +01:00
|
|
|
auto keyBuffer = KeyBuffer(keyRaw.begin(), keyRaw.end());
|
|
|
|
auto vol = std::shared_ptr<VolumeBase>(new PrivateVolume(device, keyBuffer));
|
2015-04-09 06:07:21 +02:00
|
|
|
if (mJustPartitioned) {
|
|
|
|
LOG(DEBUG) << "Device just partitioned; silently formatting";
|
|
|
|
vol->setSilent(true);
|
|
|
|
vol->create();
|
2015-05-22 07:35:42 +02:00
|
|
|
vol->format("auto");
|
2015-04-09 06:07:21 +02:00
|
|
|
vol->destroy();
|
|
|
|
vol->setSilent(false);
|
|
|
|
}
|
2015-03-31 19:35:33 +02:00
|
|
|
|
|
|
|
mVolumes.push_back(vol);
|
2015-04-18 02:35:20 +02:00
|
|
|
vol->setDiskId(getId());
|
2015-06-18 23:25:08 +02:00
|
|
|
vol->setPartGuid(partGuid);
|
2015-04-09 06:07:21 +02:00
|
|
|
vol->create();
|
2015-03-14 00:09:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Disk::destroyAllVolumes() {
|
2016-07-27 23:11:02 +02:00
|
|
|
for (const auto& vol : mVolumes) {
|
2015-03-14 00:09:20 +01:00
|
|
|
vol->destroy();
|
|
|
|
}
|
|
|
|
mVolumes.clear();
|
|
|
|
}
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
status_t Disk::readMetadata() {
|
|
|
|
mSize = -1;
|
2015-03-14 00:09:20 +01:00
|
|
|
mLabel.clear();
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2018-05-23 10:50:46 +02:00
|
|
|
if (GetBlockDevSize(mDevPath, &mSize) != OK) {
|
|
|
|
mSize = -1;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2016-01-08 10:36:47 +01:00
|
|
|
unsigned int majorId = major(mDevice);
|
|
|
|
switch (majorId) {
|
2018-09-18 22:30:21 +02:00
|
|
|
case kMajorBlockLoop: {
|
2016-01-08 10:36:47 +01:00
|
|
|
mLabel = "Virtual";
|
|
|
|
break;
|
|
|
|
}
|
2018-09-18 22:30:21 +02:00
|
|
|
// clang-format off
|
|
|
|
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC:
|
|
|
|
case kMajorBlockScsiD: case kMajorBlockScsiE: case kMajorBlockScsiF:
|
|
|
|
case kMajorBlockScsiG: case kMajorBlockScsiH: case kMajorBlockScsiI:
|
|
|
|
case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
|
|
|
|
case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO:
|
|
|
|
case kMajorBlockScsiP: {
|
|
|
|
// clang-format on
|
|
|
|
std::string path(mSysPath + "/device/vendor");
|
2018-05-12 02:22:42 +02:00
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(path, &tmp)) {
|
|
|
|
PLOG(WARNING) << "Failed to read vendor from " << path;
|
|
|
|
return -errno;
|
|
|
|
}
|
2018-09-18 22:30:21 +02:00
|
|
|
tmp = android::base::Trim(tmp);
|
2018-05-12 02:22:42 +02:00
|
|
|
mLabel = tmp;
|
|
|
|
break;
|
|
|
|
}
|
2018-09-18 22:30:21 +02:00
|
|
|
case kMajorBlockMmc: {
|
|
|
|
std::string path(mSysPath + "/device/manfid");
|
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(path, &tmp)) {
|
|
|
|
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;
|
|
|
|
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.
|
|
|
|
switch (manfid) {
|
|
|
|
// clang-format off
|
|
|
|
case 0x000003: mLabel = "SanDisk"; break;
|
|
|
|
case 0x00001b: mLabel = "Samsung"; break;
|
|
|
|
case 0x000028: mLabel = "Lexar"; break;
|
|
|
|
case 0x000074: mLabel = "Transcend"; break;
|
|
|
|
// clang-format on
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
if (isVirtioBlkDevice(majorId)) {
|
|
|
|
LOG(DEBUG) << "Recognized experimental block major ID " << majorId
|
|
|
|
<< " as virtio-blk (emulator's virtual SD card device)";
|
|
|
|
mLabel = "Virtual";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (isNvmeBlkDevice(majorId, mSysPath)) {
|
|
|
|
std::string path(mSysPath + "/device/model");
|
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(path, &tmp)) {
|
|
|
|
PLOG(WARNING) << "Failed to read vendor from " << path;
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
mLabel = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
LOG(WARNING) << "Unsupported block major type " << majorId;
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2017-09-13 19:49:44 +02:00
|
|
|
auto listener = VolumeManager::Instance()->getListener();
|
2018-09-18 22:30:21 +02:00
|
|
|
if (listener) listener->onDiskMetadataChanged(getId(), mSize, mLabel, mSysPath);
|
2017-09-16 00:50:28 +02:00
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t Disk::readPartitions() {
|
2017-10-07 02:02:53 +02:00
|
|
|
int maxMinors = getMaxMinors();
|
2015-03-03 06:01:40 +01:00
|
|
|
if (maxMinors < 0) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
destroyAllVolumes();
|
2015-03-03 06:01:40 +01:00
|
|
|
|
|
|
|
// Parse partition table
|
2015-04-09 06:07:21 +02:00
|
|
|
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
cmd.push_back(kSgdiskPath);
|
|
|
|
cmd.push_back("--android-dump");
|
|
|
|
cmd.push_back(mDevPath);
|
|
|
|
|
|
|
|
std::vector<std::string> output;
|
2018-11-30 20:43:47 +01:00
|
|
|
status_t res = ForkExecvp(cmd, &output);
|
2015-04-09 06:07:21 +02:00
|
|
|
if (res != OK) {
|
|
|
|
LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
|
2017-09-16 00:50:28 +02:00
|
|
|
|
2017-09-13 19:49:44 +02:00
|
|
|
auto listener = VolumeManager::Instance()->getListener();
|
|
|
|
if (listener) listener->onDiskScanned(getId());
|
2017-09-16 00:50:28 +02:00
|
|
|
|
2015-04-09 06:07:21 +02:00
|
|
|
mJustPartitioned = false;
|
|
|
|
return res;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Table table = Table::kUnknown;
|
2015-03-14 00:09:20 +01:00
|
|
|
bool foundParts = false;
|
2016-07-27 23:11:02 +02:00
|
|
|
for (const auto& line : output) {
|
2017-10-07 02:02:53 +02:00
|
|
|
auto split = android::base::Split(line, kSgdiskToken);
|
|
|
|
auto it = split.begin();
|
|
|
|
if (it == split.end()) continue;
|
2015-03-14 00:09:20 +01:00
|
|
|
|
2017-10-07 02:02:53 +02:00
|
|
|
if (*it == "DISK") {
|
|
|
|
if (++it == split.end()) continue;
|
|
|
|
if (*it == "mbr") {
|
2015-03-03 06:01:40 +01:00
|
|
|
table = Table::kMbr;
|
2017-10-07 02:02:53 +02:00
|
|
|
} else if (*it == "gpt") {
|
2015-03-03 06:01:40 +01:00
|
|
|
table = Table::kGpt;
|
2017-10-07 02:02:53 +02:00
|
|
|
} else {
|
|
|
|
LOG(WARNING) << "Invalid partition table " << *it;
|
|
|
|
continue;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
2017-10-07 02:02:53 +02:00
|
|
|
} else if (*it == "PART") {
|
2015-03-14 00:09:20 +01:00
|
|
|
foundParts = true;
|
2017-10-07 02:02:53 +02:00
|
|
|
|
|
|
|
if (++it == split.end()) continue;
|
|
|
|
int i = 0;
|
|
|
|
if (!android::base::ParseInt(*it, &i, 1, maxMinors)) {
|
|
|
|
LOG(WARNING) << "Invalid partition number " << *it;
|
2015-03-03 06:01:40 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);
|
|
|
|
|
|
|
|
if (table == Table::kMbr) {
|
2017-10-07 02:02:53 +02:00
|
|
|
if (++it == split.end()) continue;
|
|
|
|
int type = 0;
|
|
|
|
if (!android::base::ParseInt("0x" + *it, &type)) {
|
|
|
|
LOG(WARNING) << "Invalid partition type " << *it;
|
|
|
|
continue;
|
|
|
|
}
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2017-10-07 02:02:53 +02:00
|
|
|
switch (type) {
|
2018-01-19 02:55:18 +01:00
|
|
|
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;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
} else if (table == Table::kGpt) {
|
2017-10-07 02:02:53 +02:00
|
|
|
if (++it == split.end()) continue;
|
|
|
|
auto typeGuid = *it;
|
|
|
|
if (++it == split.end()) continue;
|
|
|
|
auto partGuid = *it;
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2017-10-07 02:02:53 +02:00
|
|
|
if (android::base::EqualsIgnoreCase(typeGuid, kGptBasicData)) {
|
2015-03-14 00:09:20 +01:00
|
|
|
createPublicVolume(partDevice);
|
2017-10-07 02:02:53 +02:00
|
|
|
} else if (android::base::EqualsIgnoreCase(typeGuid, kGptAndroidExpand)) {
|
2015-03-31 19:35:33 +02:00
|
|
|
createPrivateVolume(partDevice, partGuid);
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ugly last ditch effort, treat entire disk as partition
|
2015-03-14 00:09:20 +01:00
|
|
|
if (table == Table::kUnknown || !foundParts) {
|
|
|
|
LOG(WARNING) << mId << " has unknown partition table; trying entire device";
|
2015-06-26 20:16:14 +02:00
|
|
|
|
|
|
|
std::string fsType;
|
|
|
|
std::string unused;
|
2017-10-07 02:02:53 +02:00
|
|
|
if (ReadMetadataUntrusted(mDevPath, &fsType, &unused, &unused) == OK) {
|
2015-06-26 20:16:14 +02:00
|
|
|
createPublicVolume(mDevice);
|
|
|
|
} else {
|
|
|
|
LOG(WARNING) << mId << " failed to identify, giving up";
|
|
|
|
}
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
2015-04-18 02:35:20 +02:00
|
|
|
|
2017-09-13 19:49:44 +02:00
|
|
|
auto listener = VolumeManager::Instance()->getListener();
|
|
|
|
if (listener) listener->onDiskScanned(getId());
|
2017-09-16 00:50:28 +02:00
|
|
|
|
2015-04-09 06:07:21 +02:00
|
|
|
mJustPartitioned = false;
|
2015-03-03 06:01:40 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
status_t Disk::unmountAll() {
|
2016-07-27 23:11:02 +02:00
|
|
|
for (const auto& vol : mVolumes) {
|
2015-03-31 19:35:33 +02:00
|
|
|
vol->unmount();
|
|
|
|
}
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
status_t Disk::partitionPublic() {
|
2015-09-23 23:13:45 +02:00
|
|
|
int res;
|
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
destroyAllVolumes();
|
2015-04-09 06:07:21 +02:00
|
|
|
mJustPartitioned = true;
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2015-09-23 23:13:45 +02:00
|
|
|
// First nuke any existing partition table
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
cmd.push_back(kSgdiskPath);
|
|
|
|
cmd.push_back("--zap-all");
|
|
|
|
cmd.push_back(mDevPath);
|
|
|
|
|
|
|
|
// Zap sometimes returns an error when it actually succeeded, so
|
|
|
|
// just log as warning and keep rolling forward.
|
|
|
|
if ((res = ForkExecvp(cmd)) != 0) {
|
|
|
|
LOG(WARNING) << "Failed to zap; status " << res;
|
|
|
|
}
|
|
|
|
|
2017-10-18 22:09:52 +02:00
|
|
|
// 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);
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2017-10-18 22:09:52 +02:00
|
|
|
if ((res = ForkExecvp(cmd)) != 0) {
|
|
|
|
LOG(ERROR) << "Failed to partition; status " << res;
|
|
|
|
return res;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2017-10-18 22:09:52 +02:00
|
|
|
return OK;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t Disk::partitionPrivate() {
|
2015-03-31 19:35:33 +02:00
|
|
|
return partitionMixed(0);
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t Disk::partitionMixed(int8_t ratio) {
|
2015-04-09 06:07:21 +02:00
|
|
|
int res;
|
2015-03-31 19:35:33 +02:00
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
destroyAllVolumes();
|
2015-04-09 06:07:21 +02:00
|
|
|
mJustPartitioned = true;
|
2015-03-31 19:35:33 +02:00
|
|
|
|
|
|
|
// First nuke any existing partition table
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
cmd.push_back(kSgdiskPath);
|
|
|
|
cmd.push_back("--zap-all");
|
|
|
|
cmd.push_back(mDevPath);
|
|
|
|
|
2015-04-15 07:22:34 +02:00
|
|
|
// Zap sometimes returns an error when it actually succeeded, so
|
|
|
|
// just log as warning and keep rolling forward.
|
2015-04-09 06:07:21 +02:00
|
|
|
if ((res = ForkExecvp(cmd)) != 0) {
|
2015-04-15 07:22:34 +02:00
|
|
|
LOG(WARNING) << "Failed to zap; status " << res;
|
2015-03-31 19:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// We've had some success above, so generate both the private partition
|
|
|
|
// GUID and encryption key and persist them.
|
|
|
|
std::string partGuidRaw;
|
Progress towards FBE and adoptable storage.
Offer to adopt storage devices on FBE devices, but keep it guarded
behind a system property for now, since we still need to work out key
storage details.
When migrating shared storage, leave user-specific /data/media
directories in place, since they already have the needed crypto
policies defined.
Enable journaling, quotas, and encrypt options when formatting
newly adopted devices. installd already gracefully handles older
partitions without quota enabled.
Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest
Bug: 62290006, 36757864, 29117062, 37395736
Bug: 29923055, 25861755, 30230655, 37436961
Change-Id: Ibbeb6ec9db2394a279bbac221a2b20711d65494e
2017-06-21 21:52:23 +02:00
|
|
|
if (GenerateRandomUuid(partGuidRaw) != OK) {
|
|
|
|
LOG(ERROR) << "Failed to generate GUID";
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
std::string keyRaw;
|
2018-02-16 22:13:58 +01:00
|
|
|
if (ReadRandomBytes(cryptfs_get_keysize(), keyRaw) != OK) {
|
Progress towards FBE and adoptable storage.
Offer to adopt storage devices on FBE devices, but keep it guarded
behind a system property for now, since we still need to work out key
storage details.
When migrating shared storage, leave user-specific /data/media
directories in place, since they already have the needed crypto
policies defined.
Enable journaling, quotas, and encrypt options when formatting
newly adopted devices. installd already gracefully handles older
partitions without quota enabled.
Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest
Bug: 62290006, 36757864, 29117062, 37395736
Bug: 29923055, 25861755, 30230655, 37436961
Change-Id: Ibbeb6ec9db2394a279bbac221a2b20711d65494e
2017-06-21 21:52:23 +02:00
|
|
|
LOG(ERROR) << "Failed to generate key";
|
2015-03-31 19:35:33 +02:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string partGuid;
|
|
|
|
StrToHex(partGuidRaw, partGuid);
|
|
|
|
|
|
|
|
if (!WriteStringToFile(keyRaw, BuildKeyPath(partGuid))) {
|
|
|
|
LOG(ERROR) << "Failed to persist key";
|
|
|
|
return -EIO;
|
|
|
|
} else {
|
|
|
|
LOG(DEBUG) << "Persisted key for GUID " << partGuid;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now let's build the new GPT table. We heavily rely on sgdisk to
|
|
|
|
// force optimal alignment on the created partitions.
|
|
|
|
cmd.clear();
|
|
|
|
cmd.push_back(kSgdiskPath);
|
|
|
|
|
|
|
|
// If requested, create a public partition first. Mixed-mode partitioning
|
|
|
|
// like this is an experimental feature.
|
|
|
|
if (ratio > 0) {
|
|
|
|
if (ratio < 10 || ratio > 90) {
|
|
|
|
LOG(ERROR) << "Mixed partition ratio must be between 10-90%";
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t splitMb = ((mSize / 100) * ratio) / 1024 / 1024;
|
|
|
|
cmd.push_back(StringPrintf("--new=0:0:+%" PRId64 "M", splitMb));
|
|
|
|
cmd.push_back(StringPrintf("--typecode=0:%s", kGptBasicData));
|
|
|
|
cmd.push_back("--change-name=0:shared");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Define a metadata partition which is designed for future use; there
|
|
|
|
// should only be one of these per physical device, even if there are
|
|
|
|
// multiple private volumes.
|
|
|
|
cmd.push_back("--new=0:0:+16M");
|
|
|
|
cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidMeta));
|
|
|
|
cmd.push_back("--change-name=0:android_meta");
|
|
|
|
|
|
|
|
// Define a single private partition filling the rest of disk.
|
|
|
|
cmd.push_back("--new=0:0:-0");
|
2015-04-09 06:07:21 +02:00
|
|
|
cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidExpand));
|
2015-03-31 19:35:33 +02:00
|
|
|
cmd.push_back(StringPrintf("--partition-guid=0:%s", partGuid.c_str()));
|
2015-04-09 06:07:21 +02:00
|
|
|
cmd.push_back("--change-name=0:android_expand");
|
2015-03-31 19:35:33 +02:00
|
|
|
|
|
|
|
cmd.push_back(mDevPath);
|
|
|
|
|
2015-04-09 06:07:21 +02:00
|
|
|
if ((res = ForkExecvp(cmd)) != 0) {
|
|
|
|
LOG(ERROR) << "Failed to partition; status " << res;
|
|
|
|
return res;
|
2015-03-31 19:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int Disk::getMaxMinors() {
|
|
|
|
// Figure out maximum partition devices supported
|
2016-01-08 10:36:47 +01:00
|
|
|
unsigned int majorId = major(mDevice);
|
|
|
|
switch (majorId) {
|
2018-09-18 22:30:21 +02:00
|
|
|
case kMajorBlockLoop: {
|
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(kSysfsLoopMaxMinors, &tmp)) {
|
|
|
|
LOG(ERROR) << "Failed to read max minors";
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
return std::stoi(tmp);
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
2018-09-18 22:30:21 +02:00
|
|
|
// clang-format off
|
|
|
|
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC:
|
|
|
|
case kMajorBlockScsiD: case kMajorBlockScsiE: case kMajorBlockScsiF:
|
|
|
|
case kMajorBlockScsiG: case kMajorBlockScsiH: case kMajorBlockScsiI:
|
|
|
|
case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
|
|
|
|
case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO:
|
|
|
|
case kMajorBlockScsiP: {
|
|
|
|
// clang-format on
|
|
|
|
// Per Documentation/devices.txt this is static
|
2016-01-08 10:36:47 +01:00
|
|
|
return 15;
|
|
|
|
}
|
2018-09-18 22:30:21 +02:00
|
|
|
case kMajorBlockMmc: {
|
|
|
|
// Per Documentation/devices.txt this is dynamic
|
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(kSysfsMmcMaxMinors, &tmp) &&
|
|
|
|
!ReadFileToString(kSysfsMmcMaxMinorsDeprecated, &tmp)) {
|
|
|
|
LOG(ERROR) << "Failed to read max minors";
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
return std::stoi(tmp);
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
if (isVirtioBlkDevice(majorId)) {
|
|
|
|
// drivers/block/virtio_blk.c has "#define PART_BITS 4", so max is
|
|
|
|
// 2^4 - 1 = 15
|
|
|
|
return 15;
|
|
|
|
}
|
|
|
|
if (isNvmeBlkDevice(majorId, mSysPath)) {
|
|
|
|
// despite kernel nvme driver supports up to 1M minors,
|
|
|
|
// #define NVME_MINORS (1U << MINORBITS)
|
|
|
|
// sgdisk can not support more than 127 partitions, due to
|
|
|
|
// #define MAX_MBR_PARTS 128
|
|
|
|
return 127;
|
|
|
|
}
|
2018-05-12 02:22:42 +02:00
|
|
|
}
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2016-01-08 10:36:47 +01:00
|
|
|
LOG(ERROR) << "Unsupported block major type " << majorId;
|
2015-03-03 06:01:40 +01:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vold
|
|
|
|
} // namespace android
|