int VolumeManager::unmountAsec(const char *id, bool force) { char asecFileName[255]; char mountPoint[255]; if (!isLegalAsecId(id)) { SLOGE("unmountAsec: Invalid asec id \"%s\"", id); errno = EINVAL; return -1; } if (findAsec(id, asecFileName, sizeof(asecFileName))) { SLOGE("Couldn't find ASEC %s", id); return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id); return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } return unmountLoopImage(id, idHash, asecFileName, mountPoint, force); }
int VolumeManager::finalizeAsec(const char *id) { char asecFileName[255]; char loopDevice[255]; char mountPoint[255]; snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id); char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { SLOGE("Unable to finalize %s (%s)", id, strerror(errno)); return -1; } snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); // XXX: if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) { SLOGE("ASEC finalize mount failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("ASEC %s finalized", id); } return 0; }
int VolumeManager::finalizeAsec(const char *id) { char asecFileName[255]; char loopDevice[255]; char mountPoint[255]; if (!isLegalAsecId(id)) { SLOGE("finalizeAsec: Invalid asec id \"%s\"", id); errno = EINVAL; return -1; } if (findAsec(id, asecFileName, sizeof(asecFileName))) { SLOGE("Couldn't find ASEC %s", id); return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { SLOGE("Unable to finalize %s (%s)", id, strerror(errno)); return -1; } unsigned int nr_sec = 0; struct asec_superblock sb; if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("ASEC finalize failed: couldn't construct mountPoint"); return -1; } int result = 0; if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { result = Ext4::doMount(loopDevice, mountPoint, true, true, true, false); } else { result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false); } if (result) { SLOGE("ASEC finalize mount failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("ASEC %s finalized", id); } return 0; }
int VolumeManager::unmountObb(const char *fileName, bool force) { char mountPoint[255]; char idHash[33]; if (!asecHash(fileName, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno)); return -1; } snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash); return unmountLoopImage(fileName, idHash, fileName, mountPoint, force); }
int VolumeManager::unmountAsec(const char *id, bool force) { char asecFileName[255]; char mountPoint[255]; snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id); snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } return unmountLoopImage(id, idHash, asecFileName, mountPoint, force); }
int VolumeManager::unmountObb(const char *fileName, bool force) { char mountPoint[255]; char idHash[33]; if (!asecHash(fileName, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno)); return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName); return -1; } return unmountLoopImage(fileName, idHash, fileName, mountPoint, force); }
int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) { char idHash[33]; if (!asecHash(sourceFile, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno)); return -1; } memset(mountPath, 0, mountPathLen); snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash); if (access(mountPath, F_OK)) { errno = ENOENT; return -1; } return 0; }
int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) { char asecFileName[255]; char loopDevice[255]; char mountPoint[255]; if (gid < AID_APP) { SLOGE("Group ID is not in application range"); return -1; } if (!isLegalAsecId(id)) { SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id); errno = EINVAL; return -1; } if (findAsec(id, asecFileName, sizeof(asecFileName))) { SLOGE("Couldn't find ASEC %s", id); return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno)); return -1; } unsigned int nr_sec = 0; struct asec_superblock sb; if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id); return -1; } int result = 0; if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) { return 0; } int ret = Ext4::doMount(loopDevice, mountPoint, false /* read-only */, true /* remount */, false /* executable */, false /* sdcard */); if (ret) { SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno)); return -1; } char *paths[] = { mountPoint, NULL }; FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL); if (fts) { // Traverse the entire hierarchy and chown to system UID. for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) { // We don't care about the lost+found directory. if (!strcmp(ftsent->fts_name, "lost+found")) { continue; } /* * There can only be one file marked as private right now. * This should be more robust, but it satisfies the requirements * we have for right now. */ const bool privateFile = !strcmp(ftsent->fts_name, filename); int fd = open(ftsent->fts_accpath, O_NOFOLLOW); if (fd < 0) { SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno)); result = -1; continue; } result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM); if (ftsent->fts_info & FTS_D) { result |= fchmod(fd, 0755); } else if (ftsent->fts_info & FTS_F) { result |= fchmod(fd, privateFile ? 0640 : 0644); } if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) { SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno)); result |= -1; } close(fd); } fts_close(fts); // Finally make the directory readable by everyone. int dirfd = open(mountPoint, O_DIRECTORY); if (dirfd < 0 || fchmod(dirfd, 0755)) { SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno)); result |= -1; } close(dirfd); } else { result |= -1; } result |= Ext4::doMount(loopDevice, mountPoint, true /* read-only */, true /* remount */, true /* execute */, false /* sdcard */); if (result) { SLOGE("ASEC fix permissions failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("ASEC %s permissions fixed", id); } return 0; }
int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype, const char *key, const int ownerUid, bool isExternal) { struct asec_superblock sb; memset(&sb, 0, sizeof(sb)); if (!isLegalAsecId(id)) { SLOGE("createAsec: Invalid asec id \"%s\"", id); errno = EINVAL; return -1; } const bool wantFilesystem = strcmp(fstype, "none"); bool usingExt4 = false; if (wantFilesystem) { usingExt4 = !strcmp(fstype, "ext4"); if (usingExt4) { sb.c_opts |= ASEC_SB_C_OPTS_EXT4; } else if (strcmp(fstype, "fat")) { SLOGE("Invalid filesystem type %s", fstype); errno = EINVAL; return -1; } } sb.magic = ASEC_SB_MAGIC; sb.ver = ASEC_SB_VER; if (numSectors < ((1024*1024)/512)) { SLOGE("Invalid container size specified (%d sectors)", numSectors); errno = EINVAL; return -1; } if (lookupVolume(id)) { SLOGE("ASEC id '%s' currently exists", id); errno = EADDRINUSE; return -1; } char asecFileName[255]; if (!findAsec(id, asecFileName, sizeof(asecFileName))) { SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)", asecFileName, strerror(errno)); errno = EADDRINUSE; return -1; } const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT; int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id); if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) { errno = EINVAL; return -1; } if (!access(asecFileName, F_OK)) { SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)", asecFileName, strerror(errno)); errno = EADDRINUSE; return -1; } /* * 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)) { SLOGE("ASEC image file creation failed (%s)", strerror(errno)); return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); unlink(asecFileName); return -1; } char loopDevice[255]; if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); unlink(asecFileName); return -1; } char dmDevice[255]; bool cleanupDm = false; if (strcmp(key, "none")) { // XXX: This is all we support for now sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH; if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice, sizeof(dmDevice))) { SLOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } 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) { SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) { close(sbfd); SLOGE("Failed to lseek for superblock (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) { close(sbfd); SLOGE("Failed to write superblock (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } close(sbfd); if (wantFilesystem) { int formatStatus; char mountPoint[255]; int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("ASEC fs format failed: couldn't construct mountPoint"); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } if (usingExt4) { formatStatus = Ext4::format(dmDevice, mountPoint); } else { formatStatus = Fat::format(dmDevice, numImgSectors, 0); } if (formatStatus < 0) { SLOGE("ASEC fs format failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } if (mkdir(mountPoint, 0000)) { if (errno != EEXIST) { SLOGE("Mountpoint creation failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } } int mountStatus; if (usingExt4) { mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false, false); } else { mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000, false); } if (mountStatus) { SLOGE("ASEC FAT mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } if (usingExt4) { int dirfd = open(mountPoint, O_DIRECTORY); if (dirfd >= 0) { if (fchown(dirfd, ownerUid, AID_SYSTEM) || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) { SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint); } close(dirfd); } } } else { SLOGI("Created raw secure container %s (no filesystem)", id); } mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); return 0; }
/** * Mounts an image file <code>img</code>. */ int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) { char mountPoint[255]; char idHash[33]; if (!asecHash(img, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", img, strerror(errno)); return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("OBB mount failed: couldn't construct mountpoint %s", img); return -1; } if (isMountpointMounted(mountPoint)) { SLOGE("Image %s already mounted", img); errno = EBUSY; return -1; } char loopDevice[255]; if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) { SLOGE("Image loop device creation failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("New loop device created at %s", loopDevice); } } else { if (mDebug) { SLOGD("Found active loopback for %s at %s", img, loopDevice); } } char dmDevice[255]; bool cleanupDm = false; int fd; unsigned int nr_sec = 0; if ((fd = open(loopDevice, O_RDWR)) < 0) { SLOGE("Failed to open loopdevice (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (ioctl(fd, BLKGETSIZE, &nr_sec)) { SLOGE("Failed to get loop size (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); close(fd); return -1; } close(fd); if (strcmp(key, "none")) { if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) { if (Devmapper::create(idHash, loopDevice, key, nr_sec, dmDevice, sizeof(dmDevice))) { SLOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (mDebug) { SLOGD("New devmapper instance created at %s", dmDevice); } } else { if (mDebug) { SLOGD("Found active devmapper for %s at %s", img, dmDevice); } } cleanupDm = true; } else { strcpy(dmDevice, loopDevice); } if (mkdir(mountPoint, 0755)) { if (errno != EEXIST) { SLOGE("Mountpoint creation failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } } if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid, 0227, false)) { SLOGE("Image mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } mActiveContainers->push_back(new ContainerData(strdup(img), OBB)); if (mDebug) { SLOGD("Image %s mounted", img); } return 0; }
int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) { char asecFileName[255]; char mountPoint[255]; if (!isLegalAsecId(id)) { SLOGE("mountAsec: Invalid asec id \"%s\"", id); errno = EINVAL; return -1; } if (findAsec(id, asecFileName, sizeof(asecFileName))) { SLOGE("Couldn't find ASEC %s", id); return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("ASEC mount failed: couldn't construct mountpoint %s", id); return -1; } if (isMountpointMounted(mountPoint)) { SLOGE("ASEC %s already mounted", id); errno = EBUSY; return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } char loopDevice[255]; if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("New loop device created at %s", loopDevice); } } else { if (mDebug) { SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice); } } char dmDevice[255]; bool cleanupDm = false; unsigned int nr_sec = 0; struct asec_superblock sb; if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { return -1; } if (mDebug) { SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); } if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { SLOGE("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(idHash, dmDevice, sizeof(dmDevice))) { if (Devmapper::create(idHash, loopDevice, key, nr_sec, dmDevice, sizeof(dmDevice))) { SLOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (mDebug) { SLOGD("New devmapper instance created at %s", dmDevice); } } else { if (mDebug) { SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice); } } cleanupDm = true; } else { strcpy(dmDevice, loopDevice); } if (mkdir(mountPoint, 0000)) { if (errno != EEXIST) { SLOGE("Mountpoint creation failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } } /* * The device mapper node needs to be created. Sometimes it takes a * while. Wait for up to 1 second. We could also inspect incoming uevents, * but that would take more effort. */ int tries = 25; while (tries--) { if (!access(dmDevice, F_OK) || errno != ENOENT) { break; } usleep(40 * 1000); } int result; if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { result = Ext4::doMount(dmDevice, mountPoint, true, false, true, false); } else { result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false); } if (result) { SLOGE("ASEC mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); if (mDebug) { SLOGD("ASEC %s mounted", id); } return 0; }
int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) { char asecFileName[255]; char mountPoint[255]; snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id); snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if (isMountpointMounted(mountPoint)) { SLOGE("ASEC %s already mounted", id); errno = EBUSY; return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } char loopDevice[255]; if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("New loop device created at %s", loopDevice); } } else { if (mDebug) { SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice); } } char dmDevice[255]; bool cleanupDm = false; int fd; unsigned int nr_sec = 0; if ((fd = open(loopDevice, O_RDWR)) < 0) { SLOGE("Failed to open loopdevice (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (ioctl(fd, BLKGETSIZE, &nr_sec)) { SLOGE("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) { SLOGE("lseek failed (%s)", strerror(errno)); close(fd); Loop::destroyByDevice(loopDevice); return -1; } if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { SLOGE("superblock read failed (%s)", strerror(errno)); close(fd); Loop::destroyByDevice(loopDevice); return -1; } close(fd); if (mDebug) { SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); } if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { SLOGE("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(idHash, dmDevice, sizeof(dmDevice))) { if (Devmapper::create(idHash, loopDevice, key, nr_sec, dmDevice, sizeof(dmDevice))) { SLOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (mDebug) { SLOGD("New devmapper instance created at %s", dmDevice); } } else { if (mDebug) { SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice); } } cleanupDm = true; } else { strcpy(dmDevice, loopDevice); } if (mkdir(mountPoint, 0777)) { if (errno != EEXIST) { SLOGE("Mountpoint creation failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } } if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false)) { // 0227, false)) { SLOGE("ASEC mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); if (mDebug) { SLOGD("ASEC %s mounted", id); } return 0; }
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)) { SLOGE("Invalid container size specified (%d sectors)", numSectors); errno = EINVAL; return -1; } if (lookupVolume(id)) { SLOGE("ASEC id '%s' currently exists", id); errno = EADDRINUSE; return -1; } char asecFileName[255]; snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id); if (!access(asecFileName, F_OK)) { SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)", asecFileName, strerror(errno)); errno = EADDRINUSE; return -1; } /* * 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)) { SLOGE("ASEC image file creation failed (%s)", strerror(errno)); return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); unlink(asecFileName); return -1; } char loopDevice[255]; if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); unlink(asecFileName); return -1; } char dmDevice[255]; bool cleanupDm = false; if (strcmp(key, "none")) { // XXX: This is all we support for now sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH; if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice, sizeof(dmDevice))) { SLOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } 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) { SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) { close(sbfd); SLOGE("Failed to lseek for superblock (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) { close(sbfd); SLOGE("Failed to write superblock (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } close(sbfd); if (strcmp(fstype, "none")) { if (strcmp(fstype, "fat")) { SLOGW("Unknown fstype '%s' specified for container", fstype); } if (Fat::format(dmDevice, numImgSectors)) { SLOGE("ASEC FAT format failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } char mountPoint[255]; snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if (mkdir(mountPoint, 0777)) { if (errno != EEXIST) { SLOGE("Mountpoint creation failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } } if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000, false)) { SLOGE("ASEC FAT mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); unlink(asecFileName); return -1; } } else { SLOGI("Created raw secure container %s (no filesystem)", id); } mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); return 0; }