diff --git a/Asec.h b/Asec.h new file mode 100644 index 0000000..136ad3b --- /dev/null +++ b/Asec.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008 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 _ASEC_H +#define _ASEC_H + +struct asec_superblock { +#define ASEC_SB_MAGIC 0xc0def00d + unsigned int magic; + +#define ASEC_SB_VER 1 + unsigned char ver; + +#define ASEC_SB_C_CIPHER_NONE 0 +#define ASEC_SB_C_CIPHER_TWOFISH 1 +#define ASEC_SB_C_CIPHER_AES 2 + unsigned char c_cipher; + +#define ASEC_SB_C_CHAIN_NONE 0 + unsigned char c_chain; + +#define ASEC_SB_C_OPTS_NONE 0 + unsigned char c_opts; + +#define ASEC_SB_C_MODE_NONE 0 + unsigned char c_mode; +} __attribute__((packed)); + +#endif diff --git a/Devmapper.cpp b/Devmapper.cpp index 02f7d98..c1aa713 100644 --- a/Devmapper.cpp +++ b/Devmapper.cpp @@ -136,8 +136,10 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key, ioctlInit(io, 4096, name, DM_STATUS_TABLE_FLAG); io->target_count = 1; tgt->status = 0; + tgt->sector_start = 0; tgt->length = numSectors; + strcpy(tgt->target_type, "crypt"); char *cryptParams = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); diff --git a/Fat.cpp b/Fat.cpp index f85bd8e..94b1039 100644 --- a/Fat.cpp +++ b/Fat.cpp @@ -148,24 +148,11 @@ int Fat::doMount(const char *fsPath, const char *mountPoint, return rc; } -int Fat::format(const char *fsPath) { - unsigned int nr_sec; +int Fat::format(const char *fsPath, unsigned int numSectors) { int fd; - - if ((fd = open(fsPath, O_RDWR)) < 0) { - LOGE("Error opening disk file (%s)", strerror(errno)); - return -1; - } - - if (ioctl(fd, BLKGETSIZE, &nr_sec)) { - LOGE("Unable to get device size (%s)", strerror(errno)); - close(fd); - return -1; - } - close(fd); - - const char *args[9]; + const char *args[11]; int rc; + args[0] = MKDOSFS_PATH; args[1] = "-F"; args[2] = "32"; @@ -173,9 +160,21 @@ int Fat::format(const char *fsPath) { args[4] = "android"; args[5] = "-c"; args[6] = "8"; - args[7] = fsPath; - args[8] = NULL; - rc = logwrap(9, args, 1); + + if (numSectors) { + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%u", numSectors); + const char *size = tmp; + args[7] = "-s"; + args[8] = size; + args[9] = fsPath; + args[10] = NULL; + rc = logwrap(11, args, 1); + } else { + args[7] = fsPath; + args[8] = NULL; + rc = logwrap(9, args, 1); + } if (rc == 0) { LOGI("Filesystem formatted OK"); diff --git a/Fat.h b/Fat.h index ab16a7f..f056090 100644 --- a/Fat.h +++ b/Fat.h @@ -25,7 +25,7 @@ public: static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount, int ownerUid, int ownerGid, int permMask, bool createLost); - static int format(const char *fsPath); + static int format(const char *fsPath, unsigned int numSectors); }; #endif diff --git a/Volume.cpp b/Volume.cpp index 83c1c0e..07b96a2 100644 --- a/Volume.cpp +++ b/Volume.cpp @@ -194,7 +194,7 @@ int Volume::formatVol() { sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(partNode), MINOR(partNode)); - if (Fat::format(devicePath)) { + if (Fat::format(devicePath, 0)) { LOGE("Failed to format (%s)", strerror(errno)); goto err; } diff --git a/VolumeManager.cpp b/VolumeManager.cpp index ce01275..8f1cb52 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -38,6 +38,7 @@ #include "Fat.h" #include "Devmapper.h" #include "Process.h" +#include "Asec.h" VolumeManager *VolumeManager::sInstance = NULL; @@ -168,6 +169,11 @@ int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) { int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype, const char *key, int ownerUid) { + struct asec_superblock sb; + memset(&sb, 0, sizeof(sb)); + + sb.magic = ASEC_SB_MAGIC; + sb.ver = ASEC_SB_VER; if (numSectors < ((1024*1024)/512)) { LOGE("Invalid container size specified (%d sectors)", numSectors); @@ -191,7 +197,18 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, return -1; } - if (Loop::createImageFile(asecFileName, numSectors)) { + /* + * Add some headroom + */ + unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2; + unsigned numImgSectors = numSectors + fatSize + 2; + + if (numImgSectors % 63) { + numImgSectors += (63 - (numImgSectors % 63)); + } + + // Add +1 for our superblock which is at the end + if (Loop::createImageFile(asecFileName, numImgSectors + 1)) { LOGE("ASEC image file creation failed (%s)", strerror(errno)); return -1; } @@ -207,7 +224,9 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, bool cleanupDm = false; if (strcmp(key, "none")) { - if (Devmapper::create(id, loopDevice, key, numSectors, dmDevice, + // XXX: This is all we support for now + sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH; + if (Devmapper::create(id, loopDevice, key, numImgSectors, dmDevice, sizeof(dmDevice))) { LOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); @@ -216,15 +235,54 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, } cleanupDm = true; } else { + sb.c_cipher = ASEC_SB_C_CIPHER_NONE; strcpy(dmDevice, loopDevice); } + /* + * Drop down the superblock at the end of the file + */ + + int sbfd = open(loopDevice, O_RDWR); + if (sbfd < 0) { + LOGE("Failed to open new DM device for superblock write (%s)", strerror(errno)); + if (cleanupDm) { + Devmapper::destroy(id); + } + Loop::destroyByDevice(loopDevice); + unlink(asecFileName); + return -1; + } + + if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) { + close(sbfd); + LOGE("Failed to lseek for superblock (%s)", strerror(errno)); + if (cleanupDm) { + Devmapper::destroy(id); + } + Loop::destroyByDevice(loopDevice); + unlink(asecFileName); + return -1; + } + + if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) { + close(sbfd); + LOGE("Failed to write superblock (%s)", strerror(errno)); + if (cleanupDm) { + Devmapper::destroy(id); + } + Loop::destroyByDevice(loopDevice); + unlink(asecFileName); + return -1; + } + close(sbfd); + if (strcmp(fstype, "none")) { if (strcmp(fstype, "fat")) { LOGW("Unknown fstype '%s' specified for container", fstype); } - if (Fat::format(dmDevice)) { + if (Fat::format(dmDevice, numImgSectors)) { LOGE("ASEC FAT format failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(id); @@ -467,24 +525,53 @@ int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) { char dmDevice[255]; bool cleanupDm = false; + int fd; + unsigned int nr_sec = 0; + + if ((fd = open(loopDevice, O_RDWR)) < 0) { + LOGE("Failed to open loopdevice (%s)", strerror(errno)); + Loop::destroyByDevice(loopDevice); + return -1; + } + + if (ioctl(fd, BLKGETSIZE, &nr_sec)) { + LOGE("Failed to get loop size (%s)", strerror(errno)); + Loop::destroyByDevice(loopDevice); + close(fd); + return -1; + } + + /* + * Validate superblock + */ + struct asec_superblock sb; + memset(&sb, 0, sizeof(sb)); + if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) { + LOGE("lseek failed (%s)", strerror(errno)); + close(fd); + Loop::destroyByDevice(loopDevice); + return -1; + } + if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { + LOGE("superblock read failed (%s)", strerror(errno)); + close(fd); + Loop::destroyByDevice(loopDevice); + return -1; + } + + close(fd); + + LOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); + if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { + LOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver); + Loop::destroyByDevice(loopDevice); + errno = EMEDIUMTYPE; + return -1; + } + nr_sec--; // We don't want the devmapping to extend onto our superblock + if (strcmp(key, "none")) { if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) { - unsigned int nr_sec = 0; - int fd; - - if ((fd = open(loopDevice, O_RDWR)) < 0) { - LOGE("Failed to open loopdevice (%s)", strerror(errno)); - Loop::destroyByDevice(loopDevice); - return -1; - } - - if (ioctl(fd, BLKGETSIZE, &nr_sec)) { - LOGE("Failed to get loop size (%s)", strerror(errno)); - Loop::destroyByDevice(loopDevice); - close(fd); - return -1; - } - close(fd); if (Devmapper::create(id, loopDevice, key, nr_sec, dmDevice, sizeof(dmDevice))) { LOGE("ASEC device mapping failed (%s)", strerror(errno));