summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk7
-rw-r--r--Asec.h1
-rw-r--r--CommandListener.cpp84
-rw-r--r--CommandListener.h2
-rw-r--r--Ext4.cpp90
-rw-r--r--Ext4.h29
-rw-r--r--Loop.cpp44
-rw-r--r--Loop.h1
-rw-r--r--Volume.cpp18
-rw-r--r--Volume.h3
-rw-r--r--VolumeManager.cpp353
-rw-r--r--VolumeManager.h17
-rw-r--r--cryptfs.c158
-rw-r--r--logwrapper.c45
-rw-r--r--vdc.c2
15 files changed, 657 insertions, 197 deletions
diff --git a/Android.mk b/Android.mk
index bba6122..b7a4905 100644
--- a/Android.mk
+++ b/Android.mk
@@ -10,6 +10,7 @@ common_src_files := \
DirectVolume.cpp \
logwrapper.c \
Process.cpp \
+ Ext4.cpp \
Fat.cpp \
Loop.cpp \
Devmapper.cpp \
@@ -39,6 +40,8 @@ LOCAL_C_INCLUDES := $(common_c_includes)
LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
+LOCAL_STATIC_LIBRARIES := libfs_mgr
+
LOCAL_MODULE_TAGS := eng tests
include $(BUILD_STATIC_LIBRARY)
@@ -53,10 +56,12 @@ LOCAL_SRC_FILES := \
LOCAL_C_INCLUDES := $(common_c_includes)
-LOCAL_CFLAGS :=
+LOCAL_CFLAGS := -Werror=format
LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
+LOCAL_STATIC_LIBRARIES := libfs_mgr
+
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
diff --git a/Asec.h b/Asec.h
index 136ad3b..dd64fd0 100644
--- a/Asec.h
+++ b/Asec.h
@@ -33,6 +33,7 @@ struct asec_superblock {
unsigned char c_chain;
#define ASEC_SB_C_OPTS_NONE 0
+#define ASEC_SB_C_OPTS_EXT4 1
unsigned char c_opts;
#define ASEC_SB_C_MODE_NONE 0
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 97ed2ce..dff4625 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -40,7 +40,7 @@
#include "cryptfs.h"
CommandListener::CommandListener() :
- FrameworkListener("vold") {
+ FrameworkListener("vold", true) {
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
@@ -261,6 +261,44 @@ CommandListener::AsecCmd::AsecCmd() :
VoldCommand("asec") {
}
+void CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
+ DIR *d = opendir(directory);
+
+ if (!d) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
+ return;
+ }
+
+ size_t dirent_len = offsetof(struct dirent, d_name) +
+ pathconf(directory, _PC_NAME_MAX) + 1;
+
+ struct dirent *dent = (struct dirent *) malloc(dirent_len);
+ if (dent == NULL) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", true);
+ return;
+ }
+
+ struct dirent *result;
+
+ while (!readdir_r(d, dent, &result) && result != NULL) {
+ if (dent->d_name[0] == '.')
+ continue;
+ if (dent->d_type != DT_REG)
+ continue;
+ size_t name_len = strlen(dent->d_name);
+ if (name_len > 5 && name_len < 260 &&
+ !strcmp(&dent->d_name[name_len - 5], ".asec")) {
+ char id[255];
+ memset(id, 0, sizeof(id));
+ strlcpy(id, dent->d_name, name_len - 4);
+ cli->sendMsg(ResponseCode::AsecListResult, id, false);
+ }
+ }
+ closedir(d);
+
+ free(dent);
+}
+
int CommandListener::AsecCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
if (argc < 2) {
@@ -273,35 +311,21 @@ int CommandListener::AsecCmd::runCommand(SocketClient *cli,
if (!strcmp(argv[1], "list")) {
dumpArgs(argc, argv, -1);
- DIR *d = opendir(Volume::SEC_ASECDIR);
- if (!d) {
- cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
- return 0;
- }
-
- struct dirent *dent;
- while ((dent = readdir(d))) {
- if (dent->d_name[0] == '.')
- continue;
- if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
- char id[255];
- memset(id, 0, sizeof(id));
- strncpy(id, dent->d_name, strlen(dent->d_name) -5);
- cli->sendMsg(ResponseCode::AsecListResult, id, false);
- }
- }
- closedir(d);
+ listAsecsInDirectory(cli, Volume::SEC_ASECDIR_EXT);
+ listAsecsInDirectory(cli, Volume::SEC_ASECDIR_INT);
} else if (!strcmp(argv[1], "create")) {
dumpArgs(argc, argv, 5);
- if (argc != 7) {
+ if (argc != 8) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
+ "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
+ "<isExternal>", false);
return 0;
}
unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
- rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]));
+ const bool isExternal = (atoi(argv[7]) == 1);
+ rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
} else if (!strcmp(argv[1], "finalize")) {
dumpArgs(argc, argv, -1);
if (argc != 3) {
@@ -309,6 +333,21 @@ int CommandListener::AsecCmd::runCommand(SocketClient *cli,
return 0;
}
rc = vm->finalizeAsec(argv[2]);
+ } else if (!strcmp(argv[1], "fixperms")) {
+ dumpArgs(argc, argv, -1);
+ if (argc != 5) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
+ return 0;
+ }
+
+ char *endptr;
+ gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
+ if (*endptr != '\0') {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
+ return 0;
+ }
+
+ rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
} else if (!strcmp(argv[1], "destroy")) {
dumpArgs(argc, argv, -1);
if (argc < 3) {
@@ -566,4 +605,3 @@ int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
return 0;
}
-
diff --git a/CommandListener.h b/CommandListener.h
index baf7760..4ef4a0c 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -47,6 +47,8 @@ private:
AsecCmd();
virtual ~AsecCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
+ private:
+ void listAsecsInDirectory(SocketClient *c, const char *directory);
};
class ObbCmd : public VoldCommand {
diff --git a/Ext4.cpp b/Ext4.cpp
new file mode 100644
index 0000000..290489e
--- /dev/null
+++ b/Ext4.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+
+#define LOG_TAG "Vold"
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "Ext4.h"
+
+#define MKEXT4FS_PATH "/system/bin/make_ext4fs";
+
+extern "C" int logwrap(int argc, const char **argv, int background);
+
+
+int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
+ bool executable) {
+ int rc;
+ unsigned long flags;
+
+ flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC;
+
+ flags |= (executable ? 0 : MS_NOEXEC);
+ flags |= (ro ? MS_RDONLY : 0);
+ flags |= (remount ? MS_REMOUNT : 0);
+
+ rc = mount(fsPath, mountPoint, "ext4", flags, NULL);
+
+ if (rc && errno == EROFS) {
+ SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath);
+ flags |= MS_RDONLY;
+ rc = mount(fsPath, mountPoint, "ext4", flags, NULL);
+ }
+
+ return rc;
+}
+
+int Ext4::format(const char *fsPath) {
+ int fd;
+ const char *args[4];
+ int rc;
+
+ args[0] = MKEXT4FS_PATH;
+ args[1] = "-J";
+ args[2] = fsPath;
+ args[3] = NULL;
+ rc = logwrap(3, args, 1);
+
+ if (rc == 0) {
+ SLOGI("Filesystem (ext4) formatted OK");
+ return 0;
+ } else {
+ SLOGE("Format (ext4) failed (unknown exit code %d)", rc);
+ errno = EIO;
+ return -1;
+ }
+ return 0;
+}
diff --git a/Ext4.h b/Ext4.h
new file mode 100644
index 0000000..a09b576
--- /dev/null
+++ b/Ext4.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 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 _EXT4_H
+#define _EXT4_H
+
+#include <unistd.h>
+
+class Ext4 {
+public:
+ static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
+ bool executable);
+ static int format(const char *fsPath);
+};
+
+#endif
diff --git a/Loop.cpp b/Loop.cpp
index dad2c3f..78df132 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -21,6 +21,7 @@
#include <errno.h>
#include <string.h>
+#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
@@ -33,6 +34,7 @@
#include <sysutils/SocketClient.h>
#include "Loop.h"
+#include "Asec.h"
int Loop::dumpState(SocketClient *c) {
int i;
@@ -246,3 +248,45 @@ int Loop::createImageFile(const char *file, unsigned int numSectors) {
close(fd);
return 0;
}
+
+int Loop::lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigned int *nr_sec) {
+ int fd;
+ struct asec_superblock buffer;
+
+ if ((fd = open(loopDevice, O_RDONLY)) < 0) {
+ SLOGE("Failed to open loopdevice (%s)", strerror(errno));
+ destroyByDevice(loopDevice);
+ return -1;
+ }
+
+ if (ioctl(fd, BLKGETSIZE, nr_sec)) {
+ SLOGE("Failed to get loop size (%s)", strerror(errno));
+ destroyByDevice(loopDevice);
+ close(fd);
+ return -1;
+ }
+
+ /*
+ * Try to read superblock.
+ */
+ memset(&buffer, 0, sizeof(struct asec_superblock));
+ if (lseek(fd, ((*nr_sec - 1) * 512), SEEK_SET) < 0) {
+ SLOGE("lseek failed (%s)", strerror(errno));
+ close(fd);
+ destroyByDevice(loopDevice);
+ return -1;
+ }
+ if (read(fd, &buffer, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
+ SLOGE("superblock read failed (%s)", strerror(errno));
+ close(fd);
+ destroyByDevice(loopDevice);
+ return -1;
+ }
+ close(fd);
+
+ /*
+ * Superblock successfully read. Copy to caller's struct.
+ */
+ memcpy(sb, &buffer, sizeof(struct asec_superblock));
+ return 0;
+}
diff --git a/Loop.h b/Loop.h
index e48536b..d717cf0 100644
--- a/Loop.h
+++ b/Loop.h
@@ -27,6 +27,7 @@ public:
static const int LOOP_MAX = 4096;
public:
static int lookupActive(const char *id, char *buffer, size_t len);
+ static int lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigned int *nr_sec);
static int create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len);
static int destroyByDevice(const char *loopDevice);
static int destroyByFile(const char *loopFile);
diff --git a/Volume.cpp b/Volume.cpp
index e70a590..a71000e 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -69,11 +69,15 @@ const char *Volume::SEC_STGDIR = "/mnt/secure/staging";
const char *Volume::SEC_STG_SECIMGDIR = "/mnt/secure/staging/.android_secure";
/*
- * Path to where *only* root can access asec imagefiles
+ * Path to external storage where *only* root can access ASEC image files
*/
-const char *Volume::SEC_ASECDIR = "/mnt/secure/asec";
+const char *Volume::SEC_ASECDIR_EXT = "/mnt/secure/asec";
/*
+ * Path to internal storage where *only* root can access ASEC image files
+ */
+const char *Volume::SEC_ASECDIR_INT = "/data/app-asec";
+/*
* Path to where secure containers are mounted
*/
const char *Volume::ASECDIR = "/mnt/asec";
@@ -504,9 +508,9 @@ int Volume::createBindMounts() {
* Bind mount /mnt/secure/staging/android_secure -> /mnt/secure/asec so we'll
* have a root only accessable mountpoint for it.
*/
- if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) {
+ if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
SLOGE("Failed to bind mount points %s -> %s (%s)",
- SEC_STG_SECIMGDIR, SEC_ASECDIR, strerror(errno));
+ SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, strerror(errno));
return -1;
}
@@ -630,8 +634,8 @@ int Volume::unmountVol(bool force, bool revert) {
* the previously obscured directory.
*/
- if (doUnmount(Volume::SEC_ASECDIR, force)) {
- SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR, strerror(errno));
+ if (doUnmount(Volume::SEC_ASECDIR_EXT, force)) {
+ SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR_EXT, strerror(errno));
goto fail_remount_tmpfs;
}
@@ -663,7 +667,7 @@ int Volume::unmountVol(bool force, bool revert) {
* Failure handling - try to restore everything back the way it was
*/
fail_recreate_bindmount:
- if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) {
+ if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
SLOGE("Failed to restore bindmount after failure! - Storage will appear offline!");
goto out_nomedia;
}
diff --git a/Volume.h b/Volume.h
index 274fb54..c717d4d 100644
--- a/Volume.h
+++ b/Volume.h
@@ -41,7 +41,8 @@ public:
static const char *SECDIR;
static const char *SEC_STGDIR;
static const char *SEC_STG_SECIMGDIR;
- static const char *SEC_ASECDIR;
+ static const char *SEC_ASECDIR_EXT;
+ static const char *SEC_ASECDIR_INT;
static const char *ASECDIR;
static const char *LOOPDIR;
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 0eb72a1..3a63a19 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -19,6 +19,8 @@
#include <string.h>
#include <errno.h>
#include <fcntl.h>
+#include <fts.h>
+#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
@@ -33,10 +35,13 @@
#include <sysutils/NetlinkEvent.h>
+#include <private/android_filesystem_config.h>
+
#include "VolumeManager.h"
#include "DirectVolume.h"
#include "ResponseCode.h"
#include "Loop.h"
+#include "Ext4.h"
#include "Fat.h"
#include "Devmapper.h"
#include "Process.h"
@@ -197,7 +202,11 @@ int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int
int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
char asecFileName[255];
- snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+
+ if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+ SLOGE("Couldn't find ASEC %s", id);
+ return -1;
+ }
memset(buffer, 0, maxlen);
if (access(asecFileName, F_OK)) {
@@ -211,7 +220,11 @@ int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
char asecFileName[255];
- snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+
+ if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+ SLOGE("Couldn't find ASEC %s", id);
+ return -1;
+ }
memset(buffer, 0, maxlen);
if (access(asecFileName, F_OK)) {
@@ -223,11 +236,24 @@ int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxle
return 0;
}
-int VolumeManager::createAsec(const char *id, unsigned int numSectors,
- const char *fstype, const char *key, int ownerUid) {
+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));
+ 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;
@@ -244,11 +270,21 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors,
}
char asecFileName[255];
- snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+
+ 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;
+
+ snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
if (!access(asecFileName, F_OK)) {
SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
- asecFileName, strerror(errno));
+ asecFileName, strerror(errno));
errno = EADDRINUSE;
return -1;
}
@@ -340,13 +376,16 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors,
}
close(sbfd);
- if (strcmp(fstype, "none")) {
- if (strcmp(fstype, "fat")) {
- SLOGW("Unknown fstype '%s' specified for container", fstype);
+ if (wantFilesystem) {
+ int formatStatus;
+ if (usingExt4) {
+ formatStatus = Ext4::format(dmDevice);
+ } else {
+ formatStatus = Fat::format(dmDevice, numImgSectors);
}
- if (Fat::format(dmDevice, numImgSectors)) {
- SLOGE("ASEC FAT format failed (%s)", strerror(errno));
+ if (formatStatus < 0) {
+ SLOGE("ASEC fs format failed (%s)", strerror(errno));
if (cleanupDm) {
Devmapper::destroy(idHash);
}
@@ -354,10 +393,11 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors,
unlink(asecFileName);
return -1;
}
+
char mountPoint[255];
snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
- if (mkdir(mountPoint, 0777)) {
+ if (mkdir(mountPoint, 0000)) {
if (errno != EEXIST) {
SLOGE("Mountpoint creation failed (%s)", strerror(errno));
if (cleanupDm) {
@@ -369,8 +409,15 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors,
}
}
- if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
- 0, 0000, false)) {
+ int mountStatus;
+ if (usingExt4) {
+ mountStatus = Ext4::doMount(dmDevice, mountPoint, 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);
@@ -379,6 +426,17 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors,
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);
}
@@ -392,7 +450,10 @@ int VolumeManager::finalizeAsec(const char *id) {
char loopDevice[255];
char mountPoint[255];
- snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+ if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+ SLOGE("Couldn't find ASEC %s", id);
+ return -1;
+ }
char idHash[33];
if (!asecHash(id, idHash, sizeof(idHash))) {
@@ -405,9 +466,23 @@ int VolumeManager::finalizeAsec(const char *id) {
return -1;
}
+ unsigned int nr_sec = 0;
+ struct asec_superblock sb;
+
+ if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
+ return -1;
+ }
+
snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
- // XXX:
- if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
+
+ int result = 0;
+ if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
+ result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
+ } 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;
}
@@ -418,13 +493,131 @@ int VolumeManager::finalizeAsec(const char *id) {
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 (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;
+ }
+
+ snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
+
+ 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 */);
+ 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, 0711);
+ } else {
+ result |= fchmod(fd, privateFile ? 0640 : 0644);
+ }
+ 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 */);
+
+ if (result) {
+ SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
+ return -1;
+ }
+
+ if (mDebug) {
+ SLOGD("ASEC %s permissions fixed", id);
+ }
+ return 0;
+}
+
int VolumeManager::renameAsec(const char *id1, const char *id2) {
- char *asecFilename1;
+ char asecFilename1[255];
char *asecFilename2;
char mountPoint[255];
- asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
- asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
+ const char *dir;
+
+ if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
+ SLOGE("Couldn't find ASEC %s", id1);
+ return -1;
+ }
+
+ asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
if (isMountpointMounted(mountPoint)) {
@@ -451,12 +644,10 @@ int VolumeManager::renameAsec(const char *id1, const char *id2) {
goto out_err;
}
- free(asecFilename1);
free(asecFilename2);
return 0;
out_err:
- free(asecFilename1);
free(asecFilename2);
return -1;
}
@@ -467,7 +658,11 @@ 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);
+ if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+ SLOGE("Couldn't find ASEC %s", id);
+ return -1;
+ }
+
snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
char idHash[33];
@@ -579,7 +774,11 @@ int VolumeManager::destroyAsec(const char *id, bool force) {
char asecFileName[255];
char mountPoint[255];
- snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
+ if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+ SLOGE("Couldn't find ASEC %s", id);
+ return -1;
+ }
+
snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
if (isMountpointMounted(mountPoint)) {
@@ -603,11 +802,70 @@ int VolumeManager::destroyAsec(const char *id, bool force) {
return 0;
}
+bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
+ int dirfd = open(dir, O_DIRECTORY);
+ if (dirfd < 0) {
+ SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
+ return -1;
+ }
+
+ bool ret = false;
+
+ if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
+ ret = true;
+ }
+
+ close(dirfd);
+
+ return ret;
+}
+
+int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
+ const char **directory) const {
+ int dirfd, fd;
+ const int idLen = strlen(id);
+ char *asecName;
+
+ if (asprintf(&asecName, "%s.asec", id) < 0) {
+ SLOGE("Couldn't allocate string to write ASEC name");
+ return -1;
+ }
+
+ const char *dir;
+ if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
+ dir = Volume::SEC_ASECDIR_INT;
+ } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
+ dir = Volume::SEC_ASECDIR_EXT;
+ } else {
+ free(asecName);
+ return -1;
+ }
+
+ if (directory != NULL) {
+ *directory = dir;
+ }
+
+ if (asecPath != NULL) {
+ int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
+ if (written < 0 || static_cast<size_t>(written) >= asecPathLen) {
+ free(asecName);
+ return -1;
+ }
+ }
+
+ free(asecName);
+ 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);
+ if (findAsec(id, asecFileName, sizeof(asecFileName))) {
+ SLOGE("Couldn't find ASEC %s", id);
+ return -1;
+ }
+
snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
if (isMountpointMounted(mountPoint)) {
@@ -641,40 +899,12 @@ int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
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);
+
+ if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
return -1;
}
- close(fd);
-
if (mDebug) {
SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
}
@@ -707,7 +937,7 @@ int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
strcpy(dmDevice, loopDevice);
}
- if (mkdir(mountPoint, 0777)) {
+ if (mkdir(mountPoint, 0000)) {
if (errno != EEXIST) {
SLOGE("Mountpoint creation failed (%s)", strerror(errno));
if (cleanupDm) {
@@ -718,9 +948,14 @@ int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
}
}
- if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
- 0222, false)) {
-// 0227, false)) {
+ int result;
+ if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
+ result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
+ } 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);
diff --git a/VolumeManager.h b/VolumeManager.h
index a000556..3802503 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -87,9 +87,23 @@ public:
void disableVolumeManager(void) { mVolManagerDisabled = 1; }
/* ASEC */
+ int findAsec(const char *id, char *asecPath = NULL, size_t asecPathLen = 0,
+ const char **directory = NULL) const;
int createAsec(const char *id, unsigned numSectors, const char *fstype,
- const char *key, int ownerUid);
+ const char *key, const int ownerUid, bool isExternal);
int finalizeAsec(const char *id);
+
+ /**
+ * Fixes ASEC permissions on a filesystem that has owners and permissions.
+ * This currently means EXT4-based ASEC containers.
+ *
+ * There is a single file that can be marked as "private" and will not have
+ * world-readable permission. The group for that file will be set to the gid
+ * supplied.
+ *
+ * Returns 0 on success.
+ */
+ int fixupAsecPermissions(const char *id, gid_t gid, const char* privateFilename);
int destroyAsec(const char *id, bool force);
int mountAsec(const char *id, const char *key, int ownerUid);
int unmountAsec(const char *id, bool force);
@@ -127,6 +141,7 @@ private:
VolumeManager();
void readInitialState();
bool isMountpointMounted(const char *mp);
+ bool isAsecInDirectory(const char *dir, const char *asec) const;
};
extern "C" {
diff --git a/cryptfs.c b/cryptfs.c
index 052c033..cc7797a 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -38,8 +38,10 @@
#include <cutils/android_reboot.h>
#include <ext4.h>
#include <linux/kdev_t.h>
+#include <fs_mgr.h>
#include "cryptfs.h"
#define LOG_TAG "Cryptfs"
+#include "cutils/android_reboot.h"
#include "cutils/log.h"
#include "cutils/properties.h"
#include "hardware_legacy/power.h"
@@ -52,7 +54,6 @@
#define KEY_LEN_BYTES 16
#define IV_LEN_BYTES 16
-#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
#define KEY_IN_FOOTER "footer"
#define EXT4_FS 1
@@ -64,6 +65,8 @@ static unsigned char saved_master_key[KEY_LEN_BYTES];
static char *saved_data_blkdev;
static char *saved_mount_point;
static int master_key_saved = 0;
+#define FSTAB_PREFIX "/fstab."
+static char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
{
@@ -121,6 +124,19 @@ static unsigned int get_blkdev_size(int fd)
return nr_sec;
}
+/* Get and cache the name of the fstab file so we don't
+ * keep talking over the socket to the property service.
+ */
+static char *get_fstab_filename(void)
+{
+ if (fstab_filename[0] == 0) {
+ strcpy(fstab_filename, FSTAB_PREFIX);
+ property_get("ro.hardware", fstab_filename + sizeof(FSTAB_PREFIX) - 1, "");
+ }
+
+ return fstab_filename;
+}
+
/* key or salt can be NULL, in which case just skip writing that value. Useful to
* update the failed mount count but not change the key.
*/
@@ -135,7 +151,7 @@ static int put_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *cryp
char key_loc[PROPERTY_VALUE_MAX];
struct stat statbuf;
- property_get(KEY_LOC_PROP, key_loc, KEY_IN_FOOTER);
+ fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
fname = real_blk_name;
@@ -166,7 +182,7 @@ static int put_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *cryp
return -1;
}
} else {
- SLOGE("Unexpected value for" KEY_LOC_PROP "\n");
+ SLOGE("Unexpected value for crypto key location\n");
return -1;;
}
@@ -234,7 +250,7 @@ static int get_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *cryp
char *fname;
struct stat statbuf;
- property_get(KEY_LOC_PROP, key_loc, KEY_IN_FOOTER);
+ fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
fname = real_blk_name;
@@ -272,7 +288,7 @@ static int get_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *cryp
goto errout;
}
} else {
- SLOGE("Unexpected value for" KEY_LOC_PROP "\n");
+ SLOGE("Unexpected value for crypto key location\n");
return -1;;
}
@@ -556,27 +572,6 @@ static int create_encrypted_random_key(char *passwd, unsigned char *master_key,
return encrypt_master_key(passwd, salt, key_buf, master_key);
}
-static int get_orig_mount_parms(char *mount_point, char *fs_type, char *real_blkdev,
- unsigned long *mnt_flags, char *fs_options)
-{
- char mount_point2[PROPERTY_VALUE_MAX];
- char fs_flags[PROPERTY_VALUE_MAX];
-
- property_get("ro.crypto.fs_type", fs_type, "");
- property_get("ro.crypto.fs_real_blkdev", real_blkdev, "");
- property_get("ro.crypto.fs_mnt_point", mount_point2, "");
- property_get("ro.crypto.fs_options", fs_options, "");
- property_get("ro.crypto.fs_flags", fs_flags, "");
- *mnt_flags = strtol(fs_flags, 0, 0);
-
- if (strcmp(mount_point, mount_point2)) {
- /* Consistency check. These should match. If not, something odd happened. */
- return -1;
- }
-
- return 0;
-}
-
static int wait_and_unmount(char *mountpoint)
{
int i, rc;
@@ -691,26 +686,22 @@ int cryptfs_restart(void)
return -1;
}
- if (! get_orig_mount_parms(DATA_MNT_POINT, fs_type, real_blkdev, &mnt_flags, fs_options)) {
- SLOGD("Just got orig mount parms\n");
+ if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
+ /* If that succeeded, then mount the decrypted filesystem */
+ fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, 0);
- if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
- /* If that succeeded, then mount the decrypted filesystem */
- mount(crypto_blkdev, DATA_MNT_POINT, fs_type, mnt_flags, fs_options);
-
- property_set("vold.decrypt", "trigger_load_persist_props");
- /* Create necessary paths on /data */
- if (prep_data_fs()) {
- return -1;
- }
+ property_set("vold.decrypt", "trigger_load_persist_props");
+ /* Create necessary paths on /data */
+ if (prep_data_fs()) {
+ return -1;
+ }
- /* startup service classes main and late_start */
- property_set("vold.decrypt", "trigger_restart_framework");
- SLOGD("Just triggered restart_framework\n");
+ /* startup service classes main and late_start */
+ property_set("vold.decrypt", "trigger_restart_framework");
+ SLOGD("Just triggered restart_framework\n");
- /* Give it a few moments to get started */
- sleep(1);
- }
+ /* Give it a few moments to get started */
+ sleep(1);
}
if (rc == 0) {
@@ -726,10 +717,8 @@ static int do_crypto_complete(char *mount_point)
unsigned char encrypted_master_key[32];
unsigned char salt[SALT_LEN];
char real_blkdev[MAXPATHLEN];
- char fs_type[PROPERTY_VALUE_MAX];
- char fs_options[PROPERTY_VALUE_MAX];
- unsigned long mnt_flags;
char encrypted_state[PROPERTY_VALUE_MAX];
+ char key_loc[PROPERTY_VALUE_MAX];
property_get("ro.crypto.state", encrypted_state, "");
if (strcmp(encrypted_state, "encrypted") ) {
@@ -737,14 +726,25 @@ static int do_crypto_complete(char *mount_point)
return 1;
}
- if (get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options)) {
- SLOGE("Error reading original mount parms for mount point %s\n", mount_point);
- return -1;
- }
+ fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
- SLOGE("Error getting crypt footer and key\n");
- return -1;
+ fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+
+ /*
+ * Only report this error if key_loc is a file and it exists.
+ * If the device was never encrypted, and /data is not mountable for
+ * some reason, returning 1 should prevent the UI from presenting the
+ * a "enter password" screen, or worse, a "press button to wipe the
+ * device" screen.
+ */
+ if ((key_loc[0] == '/') && (access("key_loc", F_OK) == -1)) {
+ SLOGE("master key file does not exist, aborting");
+ return 1;
+ } else {
+ SLOGE("Error getting crypt footer and key\n");
+ return -1;
+ }
}
if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) {
@@ -765,10 +765,7 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
unsigned char salt[SALT_LEN];
char crypto_blkdev[MAXPATHLEN];
char real_blkdev[MAXPATHLEN];
- char fs_type[PROPERTY_VALUE_MAX];
- char fs_options[PROPERTY_VALUE_MAX];
char tmp_mount_point[64];
- unsigned long mnt_flags;
unsigned int orig_failed_decrypt_count;
char encrypted_state[PROPERTY_VALUE_MAX];
int rc;
@@ -779,10 +776,7 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
return -1;
}
- if (get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options)) {
- SLOGE("Error reading original mount parms for mount point %s\n", mount_point);
- return -1;
- }
+ fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
SLOGE("Error getting crypt footer and key\n");
@@ -811,7 +805,7 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
*/
sprintf(tmp_mount_point, "%s/tmp_mnt", mount_point);
mkdir(tmp_mount_point, 0755);
- if ( mount(crypto_blkdev, tmp_mount_point, "ext4", MS_RDONLY, "") ) {
+ if (fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
SLOGE("Error temp mounting decrypted block device\n");
delete_crypto_blk_dev(label);
crypt_ftr.failed_decrypt_count++;
@@ -923,9 +917,6 @@ int cryptfs_verify_passwd(char *passwd)
unsigned char encrypted_master_key[32], decrypted_master_key[32];
unsigned char salt[SALT_LEN];
char real_blkdev[MAXPATHLEN];
- char fs_type[PROPERTY_VALUE_MAX];
- char fs_options[PROPERTY_VALUE_MAX];
- unsigned long mnt_flags;
char encrypted_state[PROPERTY_VALUE_MAX];
int rc;
@@ -945,10 +936,7 @@ int cryptfs_verify_passwd(char *passwd)
return -1;
}
- if (get_orig_mount_parms(saved_mount_point, fs_type, real_blkdev, &mnt_flags, fs_options)) {
- SLOGE("Error reading original mount parms for mount point %s\n", saved_mount_point);
- return -1;
- }
+ fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
SLOGE("Error getting crypt footer and key\n");
@@ -1128,9 +1116,7 @@ int cryptfs_enable(char *howarg, char *passwd)
{
int how = 0;
char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN], sd_crypto_blkdev[MAXPATHLEN];
- char fs_type[PROPERTY_VALUE_MAX], fs_options[PROPERTY_VALUE_MAX],
- mount_point[PROPERTY_VALUE_MAX];
- unsigned long mnt_flags, nr_sec;
+ unsigned long nr_sec;
unsigned char master_key[KEY_LEN_BYTES], decrypted_master_key[KEY_LEN_BYTES];
unsigned char salt[SALT_LEN];
int rc=-1, fd, i, ret;
@@ -1152,7 +1138,7 @@ int cryptfs_enable(char *howarg, char *passwd)
goto error_unencrypted;
}
- property_get(KEY_LOC_PROP, key_loc, KEY_IN_FOOTER);
+ fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
if (!strcmp(howarg, "wipe")) {
how = CRYPTO_ENABLE_WIPE;
@@ -1163,7 +1149,7 @@ int cryptfs_enable(char *howarg, char *passwd)
goto error_unencrypted;
}
- get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options);
+ fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
/* Get the size of the real block device */
fd = open(real_blkdev, O_RDONLY);
@@ -1252,9 +1238,7 @@ int cryptfs_enable(char *howarg, char *passwd)
* /data, set a property saying we're doing inplace encryption,
* and restart the framework.
*/
- property_get("ro.crypto.tmpfs_options", tmpfs_options, "");
- if (mount("tmpfs", DATA_MNT_POINT, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
- tmpfs_options) < 0) {
+ if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) {
goto error_shutting_down;
}
/* Tells the framework that inplace encryption is starting */
@@ -1372,8 +1356,26 @@ int cryptfs_enable(char *howarg, char *passwd)
sleep(2); /* Give the UI a chance to show 100% progress */
android_reboot(ANDROID_RB_RESTART, 0, 0);
} else {
- property_set("vold.encrypt_progress", "error_partially_encrypted");
- release_wake_lock(lockid);
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("ro.vold.wipe_on_cyrypt_fail", value, "0");
+ if (!strcmp(value, "1")) {
+ /* wipe data if encryption failed */
+ SLOGE("encryption failed - rebooting into recovery to wipe data\n");
+ mkdir("/cache/recovery", 0700);
+ int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC);
+ if (fd >= 0) {
+ write(fd, "--wipe_data", strlen("--wipe_data") + 1);
+ close(fd);
+ } else {
+ SLOGE("could not open /cache/recovery/command\n");
+ }
+ android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+ } else {
+ /* set property to trigger dialog */
+ property_set("vold.encrypt_progress", "error_partially_encrypted");
+ release_wake_lock(lockid);
+ }
return -1;
}
@@ -1423,7 +1425,7 @@ int cryptfs_changepw(char *newpw)
return -1;
}
- property_get("ro.crypto.fs_real_blkdev", real_blkdev, "");
+ fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
if (strlen(real_blkdev) == 0) {
SLOGE("Can't find real blkdev");
return -1;
diff --git a/logwrapper.c b/logwrapper.c
index 13c076d..34a1e5a 100644
--- a/logwrapper.c
+++ b/logwrapper.c
@@ -25,6 +25,7 @@
#include "private/android_filesystem_config.h"
#include "cutils/log.h"
+#include "cutils/sched_policy.h"
int parent(const char *tag, int parent_read) {
int status;
@@ -43,7 +44,7 @@ int parent(const char *tag, int parent_read) {
} else if (buffer[b] == '\n') {
buffer[b] = '\0';
- LOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, tag, "%s", &buffer[a]);
a = b + 1;
}
}
@@ -51,7 +52,7 @@ int parent(const char *tag, int parent_read) {
if (a == 0 && b == sizeof(buffer) - 1) {
// buffer is full, flush
buffer[b] = '\0';
- LOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, tag, "%s", &buffer[a]);
b = 0;
} else if (a != b) {
// Keep left-overs
@@ -67,24 +68,24 @@ int parent(const char *tag, int parent_read) {
// Flush remaining data
if (a != b) {
buffer[b] = '\0';
- LOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, tag, "%s", &buffer[a]);
}
status = 0xAAAA;
if (wait(&status) != -1) { // Wait for child
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
- LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
+ ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
WEXITSTATUS(status));
}
return WEXITSTATUS(status);
} else if (WIFSIGNALED(status))
- LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
+ ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
WTERMSIG(status));
else if (WIFSTOPPED(status))
- LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
+ ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
WSTOPSIG(status));
} else
- LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
+ ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
strerror(errno), errno);
return -EAGAIN;
}
@@ -97,7 +98,7 @@ void child(int argc, const char**argv) {
// XXX: PROTECT FROM VIKING KILLER
if (execv(argv_child[0], argv_child)) {
- LOG(LOG_ERROR, "logwrapper",
+ ALOG(LOG_ERROR, "logwrapper",
"executing %s failed: %s", argv_child[0], strerror(errno));
exit(-1);
}
@@ -114,21 +115,21 @@ int logwrap(int argc, const char* argv[], int background)
/* Use ptty instead of socketpair so that STDOUT is not buffered */
parent_ptty = open("/dev/ptmx", O_RDWR);
if (parent_ptty < 0) {
- LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
- return -errno;
+ ALOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
+ return -errno;
}
if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
close(parent_ptty);
- LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
- return -1;
+ ALOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
+ return -1;
}
pid = fork();
if (pid < 0) {
close(parent_ptty);
- LOG(LOG_ERROR, "logwrapper", "Failed to fork");
+ ALOG(LOG_ERROR, "logwrapper", "Failed to fork");
return -errno;
} else if (pid == 0) {
/*
@@ -137,7 +138,7 @@ int logwrap(int argc, const char* argv[], int background)
child_ptty = open(child_devname, O_RDWR);
if (child_ptty < 0) {
close(parent_ptty);
- LOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
+ ALOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
return -errno;
}
@@ -148,18 +149,10 @@ int logwrap(int argc, const char* argv[], int background)
close(child_ptty);
if (background) {
- int fd = open("/dev/cpuctl/bg_non_interactive/tasks", O_WRONLY);
- if (fd >= 0) {
- char text[64];
- sprintf(text, "%d", getpid());
- if (write(fd, text, strlen(text)) < 0) {
- LOG(LOG_WARN, "logwrapper",
- "Unable to background process (%s)", strerror(errno));
- }
- close(fd);
- } else {
- LOG(LOG_WARN, "logwrapper",
- "Unable to background process (%s)", strerror(errno));
+ int err = set_sched_policy(getpid(), SP_BACKGROUND);
+ if (err < 0) {
+ ALOG(LOG_WARN, "logwrapper",
+ "Unable to background process (%s)", strerror(-err));
}
}
diff --git a/vdc.c b/vdc.c
index 1eb674c..7dad143 100644
--- a/vdc.c
+++ b/vdc.c
@@ -55,7 +55,7 @@ int main(int argc, char **argv) {
}
static int do_cmd(int sock, int argc, char **argv) {
- char final_cmd[255] = { '\0' };
+ char final_cmd[255] = "0 "; /* 0 is a (now required) sequence number */
int i;
int ret;