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:
parent
99635f6c28
commit
fb7c4d5a8a
6 changed files with 221 additions and 10 deletions
|
@ -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") {
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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";
|
||||||
|
|
2
Volume.h
2
Volume.h
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue