1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "Disk.h" 18 #include "FsCrypt.h" 19 #include "PrivateVolume.h" 20 #include "PublicVolume.h" 21 #include "Utils.h" 22 #include "VolumeBase.h" 23 #include "VolumeEncryption.h" 24 #include "VolumeManager.h" 25 26 #include <android-base/file.h> 27 #include <android-base/logging.h> 28 #include <android-base/parseint.h> 29 #include <android-base/properties.h> 30 #include <android-base/stringprintf.h> 31 #include <android-base/strings.h> 32 #include <fscrypt/fscrypt.h> 33 34 #include <fcntl.h> 35 #include <inttypes.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <sys/mount.h> 39 #include <sys/stat.h> 40 #include <sys/sysmacros.h> 41 #include <sys/types.h> 42 #include <vector> 43 44 using android::base::ReadFileToString; 45 using android::base::StringPrintf; 46 using android::base::WriteStringToFile; 47 48 namespace android { 49 namespace vold { 50 51 static const char* kSgdiskPath = "/system/bin/sgdisk"; 52 static const char* kSgdiskToken = " \t\n"; 53 54 static const char* kSysfsLoopMaxMinors = "/sys/module/loop/parameters/max_part"; 55 static const char* kSysfsMmcMaxMinorsDeprecated = "/sys/module/mmcblk/parameters/perdev_minors"; 56 static const char* kSysfsMmcMaxMinors = "/sys/module/mmc_block/parameters/perdev_minors"; 57 58 static const unsigned int kMajorBlockLoop = 7; 59 static const unsigned int kMajorBlockScsiA = 8; 60 static const unsigned int kMajorBlockScsiB = 65; 61 static const unsigned int kMajorBlockScsiC = 66; 62 static const unsigned int kMajorBlockScsiD = 67; 63 static const unsigned int kMajorBlockScsiE = 68; 64 static const unsigned int kMajorBlockScsiF = 69; 65 static const unsigned int kMajorBlockScsiG = 70; 66 static const unsigned int kMajorBlockScsiH = 71; 67 static const unsigned int kMajorBlockScsiI = 128; 68 static const unsigned int kMajorBlockScsiJ = 129; 69 static const unsigned int kMajorBlockScsiK = 130; 70 static const unsigned int kMajorBlockScsiL = 131; 71 static const unsigned int kMajorBlockScsiM = 132; 72 static const unsigned int kMajorBlockScsiN = 133; 73 static const unsigned int kMajorBlockScsiO = 134; 74 static const unsigned int kMajorBlockScsiP = 135; 75 static const unsigned int kMajorBlockMmc = 179; 76 static const unsigned int kMajorBlockDynamicMin = 234; 77 static const unsigned int kMajorBlockDynamicMax = 512; 78 79 static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"; 80 static const char* kGptAndroidMeta = "19A710A2-B3CA-11E4-B026-10604B889DCF"; 81 static const char* kGptAndroidExpand = "193D1EA4-B3CA-11E4-B075-10604B889DCF"; 82 83 enum class Table { 84 kUnknown, 85 kMbr, 86 kGpt, 87 }; 88 89 static bool isNvmeBlkDevice(unsigned int major, const std::string& sysPath) { 90 return sysPath.find("nvme") != std::string::npos && major >= kMajorBlockDynamicMin && 91 major <= kMajorBlockDynamicMax; 92 } 93 94 Disk::Disk(const std::string& eventPath, dev_t device, const std::string& nickname, int flags) 95 : mDevice(device), 96 mSize(-1), 97 mNickname(nickname), 98 mFlags(flags), 99 mCreated(false), 100 mJustPartitioned(false) { 101 mId = StringPrintf("disk:%u,%u", major(device), minor(device)); 102 mEventPath = eventPath; 103 mSysPath = StringPrintf("/sys/%s", eventPath.c_str()); 104 mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str()); 105 CreateDeviceNode(mDevPath, mDevice); 106 } 107 108 Disk::~Disk() { 109 CHECK(!mCreated); 110 DestroyDeviceNode(mDevPath); 111 } 112 113 std::shared_ptr<VolumeBase> Disk::findVolume(const std::string& id) { 114 for (auto vol : mVolumes) { 115 if (vol->getId() == id) { 116 return vol; 117 } 118 auto stackedVol = vol->findVolume(id); 119 if (stackedVol != nullptr) { 120 return stackedVol; 121 } 122 } 123 return nullptr; 124 } 125 126 void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) const { 127 for (const auto& vol : mVolumes) { 128 if (vol->getType() == type) { 129 list.push_back(vol->getId()); 130 } 131 // TODO: consider looking at stacked volumes 132 } 133 } 134 135 std::vector<std::shared_ptr<VolumeBase>> Disk::getVolumes() const { 136 std::vector<std::shared_ptr<VolumeBase>> vols; 137 for (const auto& vol : mVolumes) { 138 vols.push_back(vol); 139 auto stackedVolumes = vol->getVolumes(); 140 vols.insert(vols.end(), stackedVolumes.begin(), stackedVolumes.end()); 141 } 142 143 return vols; 144 } 145 146 status_t Disk::create() { 147 CHECK(!mCreated); 148 mCreated = true; 149 150 auto listener = VolumeManager::Instance()->getListener(); 151 if (listener) listener->onDiskCreated(getId(), mFlags); 152 153 if (isStub()) { 154 createStubVolume(); 155 return OK; 156 } 157 readMetadata(); 158 readPartitions(); 159 return OK; 160 } 161 162 status_t Disk::destroy() { 163 CHECK(mCreated); 164 destroyAllVolumes(); 165 mCreated = false; 166 167 auto listener = VolumeManager::Instance()->getListener(); 168 if (listener) listener->onDiskDestroyed(getId()); 169 170 return OK; 171 } 172 173 void Disk::createPublicVolume(dev_t device) { 174 auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device)); 175 if (mJustPartitioned) { 176 LOG(DEBUG) << "Device just partitioned; silently formatting"; 177 vol->setSilent(true); 178 vol->create(); 179 vol->format("auto"); 180 vol->destroy(); 181 vol->setSilent(false); 182 } 183 184 mVolumes.push_back(vol); 185 vol->setDiskId(getId()); 186 vol->create(); 187 } 188 189 void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) { 190 std::string normalizedGuid; 191 if (NormalizeHex(partGuid, normalizedGuid)) { 192 LOG(WARNING) << "Invalid GUID " << partGuid; 193 return; 194 } 195 196 std::string keyRaw; 197 if (!ReadFileToString(BuildKeyPath(normalizedGuid), &keyRaw)) { 198 PLOG(ERROR) << "Failed to load key for GUID " << normalizedGuid; 199 return; 200 } 201 202 LOG(DEBUG) << "Found key for GUID " << normalizedGuid; 203 204 auto keyBuffer = KeyBuffer(keyRaw.begin(), keyRaw.end()); 205 auto vol = std::shared_ptr<VolumeBase>(new PrivateVolume(device, keyBuffer)); 206 if (mJustPartitioned) { 207 LOG(DEBUG) << "Device just partitioned; silently formatting"; 208 vol->setSilent(true); 209 vol->create(); 210 vol->format("auto"); 211 vol->destroy(); 212 vol->setSilent(false); 213 } 214 215 mVolumes.push_back(vol); 216 vol->setDiskId(getId()); 217 vol->setPartGuid(partGuid); 218 vol->create(); 219 } 220 221 void Disk::createStubVolume() { 222 CHECK(mVolumes.size() == 1); 223 auto listener = VolumeManager::Instance()->getListener(); 224 if (listener) listener->onDiskMetadataChanged(getId(), mSize, mLabel, mSysPath); 225 if (listener) listener->onDiskScanned(getId()); 226 mVolumes[0]->setDiskId(getId()); 227 mVolumes[0]->create(); 228 } 229 230 void Disk::destroyAllVolumes() { 231 for (const auto& vol : mVolumes) { 232 vol->destroy(); 233 } 234 mVolumes.clear(); 235 } 236 237 status_t Disk::readMetadata() { 238 mSize = -1; 239 mLabel.clear(); 240 241 if (GetBlockDevSize(mDevPath, &mSize) != OK) { 242 mSize = -1; 243 } 244 245 unsigned int majorId = major(mDevice); 246 switch (majorId) { 247 case kMajorBlockLoop: { 248 mLabel = "Virtual"; 249 break; 250 } 251 // clang-format off 252 case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: 253 case kMajorBlockScsiD: case kMajorBlockScsiE: case kMajorBlockScsiF: 254 case kMajorBlockScsiG: case kMajorBlockScsiH: case kMajorBlockScsiI: 255 case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL: 256 case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: 257 case kMajorBlockScsiP: { 258 // clang-format on 259 std::string path(mSysPath + "/device/vendor"); 260 std::string tmp; 261 if (!ReadFileToString(path, &tmp)) { 262 PLOG(WARNING) << "Failed to read vendor from " << path; 263 return -errno; 264 } 265 tmp = android::base::Trim(tmp); 266 mLabel = tmp; 267 break; 268 } 269 case kMajorBlockMmc: { 270 std::string path(mSysPath + "/device/manfid"); 271 std::string tmp; 272 if (!ReadFileToString(path, &tmp)) { 273 PLOG(WARNING) << "Failed to read manufacturer from " << path; 274 return -errno; 275 } 276 tmp = android::base::Trim(tmp); 277 int64_t manfid; 278 if (!android::base::ParseInt(tmp, &manfid)) { 279 PLOG(WARNING) << "Failed to parse manufacturer " << tmp; 280 return -EINVAL; 281 } 282 // Our goal here is to give the user a meaningful label, ideally 283 // matching whatever is silk-screened on the card. To reduce 284 // user confusion, this list doesn't contain white-label manfid. 285 switch (manfid) { 286 // clang-format off 287 case 0x000003: mLabel = "SanDisk"; break; 288 case 0x00001b: mLabel = "Samsung"; break; 289 case 0x000028: mLabel = "Lexar"; break; 290 case 0x000074: mLabel = "Transcend"; break; 291 // clang-format on 292 } 293 break; 294 } 295 default: { 296 if (IsVirtioBlkDevice(majorId)) { 297 LOG(DEBUG) << "Recognized experimental block major ID " << majorId 298 << " as virtio-blk (emulator's virtual SD card device)"; 299 mLabel = "Virtual"; 300 break; 301 } 302 if (isNvmeBlkDevice(majorId, mSysPath)) { 303 std::string path(mSysPath + "/device/model"); 304 std::string tmp; 305 if (!ReadFileToString(path, &tmp)) { 306 PLOG(WARNING) << "Failed to read vendor from " << path; 307 return -errno; 308 } 309 mLabel = tmp; 310 break; 311 } 312 LOG(WARNING) << "Unsupported block major type " << majorId; 313 return -ENOTSUP; 314 } 315 } 316 317 auto listener = VolumeManager::Instance()->getListener(); 318 if (listener) listener->onDiskMetadataChanged(getId(), mSize, mLabel, mSysPath); 319 320 return OK; 321 } 322 323 status_t Disk::readPartitions() { 324 int maxMinors = getMaxMinors(); 325 if (maxMinors < 0) { 326 return -ENOTSUP; 327 } 328 329 destroyAllVolumes(); 330 331 // Parse partition table 332 333 std::vector<std::string> cmd; 334 cmd.push_back(kSgdiskPath); 335 cmd.push_back("--android-dump"); 336 cmd.push_back(mDevPath); 337 338 std::vector<std::string> output; 339 status_t res = ForkExecvp(cmd, &output); 340 if (res != OK) { 341 LOG(WARNING) << "sgdisk failed to scan " << mDevPath; 342 343 auto listener = VolumeManager::Instance()->getListener(); 344 if (listener) listener->onDiskScanned(getId()); 345 346 mJustPartitioned = false; 347 return res; 348 } 349 350 Table table = Table::kUnknown; 351 bool foundParts = false; 352 for (const auto& line : output) { 353 auto split = android::base::Split(line, kSgdiskToken); 354 auto it = split.begin(); 355 if (it == split.end()) continue; 356 357 if (*it == "DISK") { 358 if (++it == split.end()) continue; 359 if (*it == "mbr") { 360 table = Table::kMbr; 361 } else if (*it == "gpt") { 362 table = Table::kGpt; 363 } else { 364 LOG(WARNING) << "Invalid partition table " << *it; 365 continue; 366 } 367 } else if (*it == "PART") { 368 foundParts = true; 369 370 if (++it == split.end()) continue; 371 int i = 0; 372 if (!android::base::ParseInt(*it, &i, 1, maxMinors)) { 373 LOG(WARNING) << "Invalid partition number " << *it; 374 continue; 375 } 376 dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i); 377 378 if (table == Table::kMbr) { 379 if (++it == split.end()) continue; 380 int type = 0; 381 if (!android::base::ParseInt("0x" + *it, &type)) { 382 LOG(WARNING) << "Invalid partition type " << *it; 383 continue; 384 } 385 386 switch (type) { 387 case 0x06: // FAT16 388 case 0x07: // HPFS/NTFS/exFAT 389 case 0x0b: // W95 FAT32 (LBA) 390 case 0x0c: // W95 FAT32 (LBA) 391 case 0x0e: // W95 FAT16 (LBA) 392 createPublicVolume(partDevice); 393 break; 394 } 395 } else if (table == Table::kGpt) { 396 if (++it == split.end()) continue; 397 auto typeGuid = *it; 398 if (++it == split.end()) continue; 399 auto partGuid = *it; 400 401 if (android::base::EqualsIgnoreCase(typeGuid, kGptBasicData)) { 402 createPublicVolume(partDevice); 403 } else if (android::base::EqualsIgnoreCase(typeGuid, kGptAndroidExpand)) { 404 createPrivateVolume(partDevice, partGuid); 405 } 406 } 407 } 408 } 409 410 // Ugly last ditch effort, treat entire disk as partition 411 if (table == Table::kUnknown || !foundParts) { 412 LOG(WARNING) << mId << " has unknown partition table; trying entire device"; 413 414 std::string fsType; 415 std::string unused; 416 if (ReadMetadataUntrusted(mDevPath, &fsType, &unused, &unused) == OK) { 417 createPublicVolume(mDevice); 418 } else { 419 LOG(WARNING) << mId << " failed to identify, giving up"; 420 } 421 } 422 423 auto listener = VolumeManager::Instance()->getListener(); 424 if (listener) listener->onDiskScanned(getId()); 425 426 mJustPartitioned = false; 427 return OK; 428 } 429 430 void Disk::initializePartition(std::shared_ptr<StubVolume> vol) { 431 CHECK(isStub()); 432 CHECK(mVolumes.empty()); 433 mVolumes.push_back(vol); 434 } 435 436 status_t Disk::unmountAll() { 437 for (const auto& vol : mVolumes) { 438 vol->unmount(); 439 } 440 return OK; 441 } 442 443 status_t Disk::partitionPublic() { 444 int res; 445 446 destroyAllVolumes(); 447 mJustPartitioned = true; 448 449 // First nuke any existing partition table 450 std::vector<std::string> cmd; 451 cmd.push_back(kSgdiskPath); 452 cmd.push_back("--zap-all"); 453 cmd.push_back(mDevPath); 454 455 // Zap sometimes returns an error when it actually succeeded, so 456 // just log as warning and keep rolling forward. 457 if ((res = ForkExecvp(cmd)) != 0) { 458 LOG(WARNING) << "Failed to zap; status " << res; 459 } 460 461 // Now let's build the new MBR table. We heavily rely on sgdisk to 462 // force optimal alignment on the created partitions. 463 cmd.clear(); 464 cmd.push_back(kSgdiskPath); 465 cmd.push_back("--new=0:0:-0"); 466 cmd.push_back("--typecode=0:0c00"); 467 cmd.push_back("--gpttombr=1"); 468 cmd.push_back(mDevPath); 469 470 if ((res = ForkExecvp(cmd)) != 0) { 471 LOG(ERROR) << "Failed to partition; status " << res; 472 return res; 473 } 474 475 return OK; 476 } 477 478 status_t Disk::partitionPrivate() { 479 return partitionMixed(0); 480 } 481 482 status_t Disk::partitionMixed(int8_t ratio) { 483 int res; 484 485 destroyAllVolumes(); 486 mJustPartitioned = true; 487 488 // First nuke any existing partition table 489 std::vector<std::string> cmd; 490 cmd.push_back(kSgdiskPath); 491 cmd.push_back("--zap-all"); 492 cmd.push_back(mDevPath); 493 494 // Zap sometimes returns an error when it actually succeeded, so 495 // just log as warning and keep rolling forward. 496 if ((res = ForkExecvp(cmd)) != 0) { 497 LOG(WARNING) << "Failed to zap; status " << res; 498 } 499 500 // We've had some success above, so generate both the private partition 501 // GUID and encryption key and persist them. 502 std::string partGuidRaw; 503 if (GenerateRandomUuid(partGuidRaw) != OK) { 504 LOG(ERROR) << "Failed to generate GUID"; 505 return -EIO; 506 } 507 508 KeyBuffer key; 509 if (!generate_volume_key(&key)) { 510 LOG(ERROR) << "Failed to generate key"; 511 return -EIO; 512 } 513 std::string keyRaw(key.begin(), key.end()); 514 515 std::string partGuid; 516 StrToHex(partGuidRaw, partGuid); 517 518 if (!WriteStringToFile(keyRaw, BuildKeyPath(partGuid))) { 519 LOG(ERROR) << "Failed to persist key"; 520 return -EIO; 521 } else { 522 LOG(DEBUG) << "Persisted key for GUID " << partGuid; 523 } 524 525 // Now let's build the new GPT table. We heavily rely on sgdisk to 526 // force optimal alignment on the created partitions. 527 cmd.clear(); 528 cmd.push_back(kSgdiskPath); 529 530 // If requested, create a public partition first. Mixed-mode partitioning 531 // like this is an experimental feature. 532 if (ratio > 0) { 533 if (ratio < 10 || ratio > 90) { 534 LOG(ERROR) << "Mixed partition ratio must be between 10-90%"; 535 return -EINVAL; 536 } 537 538 uint64_t splitMb = ((mSize / 100) * ratio) / 1024 / 1024; 539 cmd.push_back(StringPrintf("--new=0:0:+%" PRId64 "M", splitMb)); 540 cmd.push_back(StringPrintf("--typecode=0:%s", kGptBasicData)); 541 cmd.push_back("--change-name=0:shared"); 542 } 543 544 // Define a metadata partition which is designed for future use; there 545 // should only be one of these per physical device, even if there are 546 // multiple private volumes. 547 cmd.push_back("--new=0:0:+16M"); 548 cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidMeta)); 549 cmd.push_back("--change-name=0:android_meta"); 550 551 // Define a single private partition filling the rest of disk. 552 cmd.push_back("--new=0:0:-0"); 553 cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidExpand)); 554 cmd.push_back(StringPrintf("--partition-guid=0:%s", partGuid.c_str())); 555 cmd.push_back("--change-name=0:android_expand"); 556 557 cmd.push_back(mDevPath); 558 559 if ((res = ForkExecvp(cmd)) != 0) { 560 LOG(ERROR) << "Failed to partition; status " << res; 561 return res; 562 } 563 564 return OK; 565 } 566 567 int Disk::getMaxMinors() { 568 // Figure out maximum partition devices supported 569 unsigned int majorId = major(mDevice); 570 switch (majorId) { 571 case kMajorBlockLoop: { 572 std::string tmp; 573 if (!ReadFileToString(kSysfsLoopMaxMinors, &tmp)) { 574 LOG(ERROR) << "Failed to read max minors"; 575 return -errno; 576 } 577 return std::stoi(tmp); 578 } 579 // clang-format off 580 case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: 581 case kMajorBlockScsiD: case kMajorBlockScsiE: case kMajorBlockScsiF: 582 case kMajorBlockScsiG: case kMajorBlockScsiH: case kMajorBlockScsiI: 583 case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL: 584 case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: 585 case kMajorBlockScsiP: { 586 // clang-format on 587 // Per Documentation/devices.txt this is static 588 return 15; 589 } 590 case kMajorBlockMmc: { 591 // Per Documentation/devices.txt this is dynamic 592 std::string tmp; 593 if (!ReadFileToString(kSysfsMmcMaxMinors, &tmp) && 594 !ReadFileToString(kSysfsMmcMaxMinorsDeprecated, &tmp)) { 595 LOG(ERROR) << "Failed to read max minors"; 596 return -errno; 597 } 598 return std::stoi(tmp); 599 } 600 default: { 601 if (IsVirtioBlkDevice(majorId)) { 602 // drivers/block/virtio_blk.c has "#define PART_BITS 4", so max is 603 // 2^4 - 1 = 15 604 return 15; 605 } 606 if (isNvmeBlkDevice(majorId, mSysPath)) { 607 // despite kernel nvme driver supports up to 1M minors, 608 // #define NVME_MINORS (1U << MINORBITS) 609 // sgdisk can not support more than 127 partitions, due to 610 // #define MAX_MBR_PARTS 128 611 return 127; 612 } 613 } 614 } 615 616 LOG(ERROR) << "Unsupported block major type " << majorId; 617 return -ENOTSUP; 618 } 619 620 } // namespace vold 621 } // namespace android 622