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 VolumeCmd());
|
||||
registerCmd(new AsecCmd());
|
||||
registerCmd(new ImageCmd());
|
||||
registerCmd(new ShareCmd());
|
||||
registerCmd(new StorageCmd());
|
||||
registerCmd(new XwarpCmd());
|
||||
|
@ -397,6 +398,54 @@ int CommandListener::AsecCmd::runCommand(SocketClient *cli,
|
|||
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() :
|
||||
VoldCommand("xwarp") {
|
||||
}
|
||||
|
|
|
@ -56,6 +56,13 @@ private:
|
|||
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 {
|
||||
public:
|
||||
StorageCmd();
|
||||
|
|
|
@ -73,6 +73,11 @@ const char *Volume::SEC_ASECDIR = "/mnt/secure/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) {
|
||||
if (state == Volume::State_Init)
|
||||
return "Initializing";
|
||||
|
|
2
Volume.h
2
Volume.h
|
@ -44,6 +44,8 @@ public:
|
|||
static const char *SEC_ASECDIR;
|
||||
static const char *ASECDIR;
|
||||
|
||||
static const char *LOOPDIR;
|
||||
|
||||
protected:
|
||||
char *mLabel;
|
||||
char *mMountpoint;
|
||||
|
|
|
@ -505,7 +505,8 @@ out_err:
|
|||
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) {
|
||||
char asecFileName[255];
|
||||
char mountPoint[255];
|
||||
|
@ -519,37 +520,56 @@ int VolumeManager::unmountAsec(const char *id, bool force) {
|
|||
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)) {
|
||||
SLOGE("Unmount request for ASEC %s when not mounted", id);
|
||||
SLOGE("Unmount request for %s when not mounted", id);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int i, rc;
|
||||
for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) {
|
||||
for (i = 1; i <= UNMOUNT_RETRIES; i++) {
|
||||
rc = umount(mountPoint);
|
||||
if (!rc) {
|
||||
break;
|
||||
}
|
||||
if (rc && (errno == EINVAL || errno == ENOENT)) {
|
||||
SLOGI("Secure container %s unmounted OK", id);
|
||||
SLOGI("Container %s unmounted OK", id);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
SLOGW("ASEC %s unmount attempt %d failed (%s)",
|
||||
SLOGW("%s unmount attempt %d failed (%s)",
|
||||
id, i, strerror(errno));
|
||||
|
||||
int action = 0; // default is to just complain
|
||||
|
||||
if (force) {
|
||||
if (i > (ASEC_UNMOUNT_RETRIES - 2))
|
||||
if (i > (UNMOUNT_RETRIES - 2))
|
||||
action = 2; // SIGKILL
|
||||
else if (i > (ASEC_UNMOUNT_RETRIES - 3))
|
||||
else if (i > (UNMOUNT_RETRIES - 3))
|
||||
action = 1; // SIGHUP
|
||||
}
|
||||
|
||||
Process::killProcessesWithOpenFiles(mountPoint, action);
|
||||
usleep(1000 * 1000);
|
||||
usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
|
@ -566,7 +586,7 @@ int VolumeManager::unmountAsec(const char *id, bool force) {
|
|||
}
|
||||
|
||||
SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
|
||||
usleep(1000 * 1000);
|
||||
usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
|
||||
}
|
||||
|
||||
if (!retries) {
|
||||
|
@ -581,7 +601,7 @@ int VolumeManager::unmountAsec(const char *id, bool force) {
|
|||
if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
|
||||
Loop::destroyByDevice(loopDevice);
|
||||
} 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;
|
||||
|
@ -759,6 +779,124 @@ int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
|
|||
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) {
|
||||
Volume *v = lookupVolume(label);
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ public:
|
|||
int shareEnabled(const char *path, const char *method, bool *enabled);
|
||||
int simulate(const char *cmd, const char *arg);
|
||||
int formatVolume(const char *label);
|
||||
|
||||
/* ASEC */
|
||||
int createAsec(const char *id, unsigned numSectors, const char *fstype,
|
||||
const char *key, int ownerUid);
|
||||
int finalizeAsec(const char *id);
|
||||
|
@ -72,6 +74,14 @@ public:
|
|||
int renameAsec(const char *id1, const char *id2);
|
||||
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);
|
||||
|
||||
// XXX: Post froyo this should be moved and cleaned up
|
||||
|
|
Loading…
Reference in a new issue