Add image mounting commands for OBB files

Allow the mounting of OBB filesystem images if they're encrypted with
twofish and in FAT filesystem format.

Change-Id: I54804e598f46b1f3a784ffe517ebd9d7626de7aa
This commit is contained in:
Kenny Root 2010-06-30 18:48:41 -07:00
parent 99635f6c28
commit fb7c4d5a8a
6 changed files with 221 additions and 10 deletions

View file

@ -41,6 +41,7 @@ CommandListener::CommandListener() :
registerCmd(new DumpCmd()); registerCmd(new DumpCmd());
registerCmd(new VolumeCmd()); registerCmd(new VolumeCmd());
registerCmd(new AsecCmd()); registerCmd(new AsecCmd());
registerCmd(new ImageCmd());
registerCmd(new ShareCmd()); registerCmd(new ShareCmd());
registerCmd(new StorageCmd()); registerCmd(new StorageCmd());
registerCmd(new XwarpCmd()); registerCmd(new XwarpCmd());
@ -397,6 +398,54 @@ int CommandListener::AsecCmd::runCommand(SocketClient *cli,
return 0; return 0;
} }
CommandListener::ImageCmd::ImageCmd() :
VoldCommand("image") {
}
int CommandListener::ImageCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
int rc = 0;
if (!strcmp(argv[1], "mount")) {
dumpArgs(argc, argv, 3);
if (argc != 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: image mount <filename> <key> <ownerUid>", false);
return 0;
}
rc = vm->mountImage(argv[2], argv[3], atoi(argv[4]));
} else if (!strcmp(argv[1], "unmount")) {
dumpArgs(argc, argv, -1);
if (argc < 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: image unmount <container-id> [force]", false);
return 0;
}
bool force = false;
if (argc > 3 && !strcmp(argv[3], "force")) {
force = true;
}
rc = vm->unmountImage(argv[2], force);
} else {
dumpArgs(argc, argv, -1);
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown image cmd", false);
}
if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, "image operation succeeded", false);
} else {
rc = ResponseCode::convertFromErrno();
cli->sendMsg(rc, "image operation failed", true);
}
return 0;
}
CommandListener::XwarpCmd::XwarpCmd() : CommandListener::XwarpCmd::XwarpCmd() :
VoldCommand("xwarp") { VoldCommand("xwarp") {
} }

View file

@ -56,6 +56,13 @@ private:
int runCommand(SocketClient *c, int argc, char ** argv); int runCommand(SocketClient *c, int argc, char ** argv);
}; };
class ImageCmd : public VoldCommand {
public:
ImageCmd();
virtual ~ImageCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
};
class StorageCmd : public VoldCommand { class StorageCmd : public VoldCommand {
public: public:
StorageCmd(); StorageCmd();

View file

@ -73,6 +73,11 @@ const char *Volume::SEC_ASECDIR = "/mnt/secure/asec";
*/ */
const char *Volume::ASECDIR = "/mnt/asec"; const char *Volume::ASECDIR = "/mnt/asec";
/*
* Path to where loop devices are mounted
*/
const char *Volume::LOOPDIR = "/mnt/loop";
static const char *stateToStr(int state) { static const char *stateToStr(int state) {
if (state == Volume::State_Init) if (state == Volume::State_Init)
return "Initializing"; return "Initializing";

View file

@ -44,6 +44,8 @@ public:
static const char *SEC_ASECDIR; static const char *SEC_ASECDIR;
static const char *ASECDIR; static const char *ASECDIR;
static const char *LOOPDIR;
protected: protected:
char *mLabel; char *mLabel;
char *mMountpoint; char *mMountpoint;

View file

@ -505,7 +505,8 @@ out_err:
return -1; return -1;
} }
#define ASEC_UNMOUNT_RETRIES 5 #define UNMOUNT_RETRIES 5
#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
int VolumeManager::unmountAsec(const char *id, bool force) { int VolumeManager::unmountAsec(const char *id, bool force) {
char asecFileName[255]; char asecFileName[255];
char mountPoint[255]; char mountPoint[255];
@ -519,37 +520,56 @@ int VolumeManager::unmountAsec(const char *id, bool force) {
return -1; return -1;
} }
return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
}
int VolumeManager::unmountImage(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::unmountLoopImage(const char *id, const char *idHash,
const char *fileName, const char *mountPoint, bool force) {
if (!isMountpointMounted(mountPoint)) { if (!isMountpointMounted(mountPoint)) {
SLOGE("Unmount request for ASEC %s when not mounted", id); SLOGE("Unmount request for %s when not mounted", id);
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
int i, rc; int i, rc;
for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) { for (i = 1; i <= UNMOUNT_RETRIES; i++) {
rc = umount(mountPoint); rc = umount(mountPoint);
if (!rc) { if (!rc) {
break; break;
} }
if (rc && (errno == EINVAL || errno == ENOENT)) { if (rc && (errno == EINVAL || errno == ENOENT)) {
SLOGI("Secure container %s unmounted OK", id); SLOGI("Container %s unmounted OK", id);
rc = 0; rc = 0;
break; break;
} }
SLOGW("ASEC %s unmount attempt %d failed (%s)", SLOGW("%s unmount attempt %d failed (%s)",
id, i, strerror(errno)); id, i, strerror(errno));
int action = 0; // default is to just complain int action = 0; // default is to just complain
if (force) { if (force) {
if (i > (ASEC_UNMOUNT_RETRIES - 2)) if (i > (UNMOUNT_RETRIES - 2))
action = 2; // SIGKILL action = 2; // SIGKILL
else if (i > (ASEC_UNMOUNT_RETRIES - 3)) else if (i > (UNMOUNT_RETRIES - 3))
action = 1; // SIGHUP action = 1; // SIGHUP
} }
Process::killProcessesWithOpenFiles(mountPoint, action); Process::killProcessesWithOpenFiles(mountPoint, action);
usleep(1000 * 1000); usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
} }
if (rc) { if (rc) {
@ -566,7 +586,7 @@ int VolumeManager::unmountAsec(const char *id, bool force) {
} }
SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno)); SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
usleep(1000 * 1000); usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
} }
if (!retries) { if (!retries) {
@ -581,7 +601,7 @@ int VolumeManager::unmountAsec(const char *id, bool force) {
if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
Loop::destroyByDevice(loopDevice); Loop::destroyByDevice(loopDevice);
} else { } else {
SLOGW("Failed to find loop device for {%s} (%s)", asecFileName, strerror(errno)); SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
} }
AsecIdCollection::iterator it; AsecIdCollection::iterator it;
@ -759,6 +779,124 @@ int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
return 0; return 0;
} }
/**
* Mounts an image file <code>img</code>.
*/
int VolumeManager::mountImage(const char *img, const char *key, int ownerUid) {
char mountPoint[255];
#if 0
struct stat imgStat;
if (stat(img, &imgStat) != 0) {
SLOGE("Could not stat '%s': %s", img, strerror(errno));
return -1;
}
if (imgStat.st_uid != ownerUid) {
SLOGW("Image UID does not match requestor UID (%d != %d)",
imgStat.st_uid, ownerUid);
return -1;
}
#endif
char idHash[33];
if (!asecHash(img, idHash, sizeof(idHash))) {
SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
return -1;
}
snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
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, ownerUid, 0,
0227, false)) {
SLOGE("Image mount failed (%s)", strerror(errno));
if (cleanupDm) {
Devmapper::destroy(idHash);
}
Loop::destroyByDevice(loopDevice);
return -1;
}
mActiveContainers->push_back(strdup(img));
if (mDebug) {
SLOGD("Image %s mounted", img);
}
return 0;
}
int VolumeManager::mountVolume(const char *label) { int VolumeManager::mountVolume(const char *label) {
Volume *v = lookupVolume(label); Volume *v = lookupVolume(label);

View file

@ -63,6 +63,8 @@ public:
int shareEnabled(const char *path, const char *method, bool *enabled); int shareEnabled(const char *path, const char *method, bool *enabled);
int simulate(const char *cmd, const char *arg); int simulate(const char *cmd, const char *arg);
int formatVolume(const char *label); int formatVolume(const char *label);
/* ASEC */
int createAsec(const char *id, unsigned numSectors, const char *fstype, int createAsec(const char *id, unsigned numSectors, const char *fstype,
const char *key, int ownerUid); const char *key, int ownerUid);
int finalizeAsec(const char *id); int finalizeAsec(const char *id);
@ -72,6 +74,14 @@ public:
int renameAsec(const char *id1, const char *id2); int renameAsec(const char *id1, const char *id2);
int getAsecMountPath(const char *id, char *buffer, int maxlen); int getAsecMountPath(const char *id, char *buffer, int maxlen);
/* Loopback images */
int mountImage(const char *fileName, const char *key, int ownerUid);
int unmountImage(const char *fileName, bool force);
/* Shared between ASEC and Loopback images */
int unmountLoopImage(const char *containerId, const char *loopId,
const char *fileName, const char *mountPoint, bool force);
void setDebug(bool enable); void setDebug(bool enable);
// XXX: Post froyo this should be moved and cleaned up // XXX: Post froyo this should be moved and cleaned up