diff options
-rw-r--r-- | Android.mk | 7 | ||||
-rw-r--r-- | Asec.h | 1 | ||||
-rw-r--r-- | CommandListener.cpp | 84 | ||||
-rw-r--r-- | CommandListener.h | 2 | ||||
-rw-r--r-- | Ext4.cpp | 90 | ||||
-rw-r--r-- | Ext4.h | 29 | ||||
-rw-r--r-- | Loop.cpp | 44 | ||||
-rw-r--r-- | Loop.h | 1 | ||||
-rw-r--r-- | Volume.cpp | 18 | ||||
-rw-r--r-- | Volume.h | 3 | ||||
-rw-r--r-- | VolumeManager.cpp | 353 | ||||
-rw-r--r-- | VolumeManager.h | 17 | ||||
-rw-r--r-- | cryptfs.c | 158 | ||||
-rw-r--r-- | logwrapper.c | 45 | ||||
-rw-r--r-- | vdc.c | 2 |
15 files changed, 657 insertions, 197 deletions
@@ -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) @@ -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; +} @@ -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 @@ -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; +} @@ -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); @@ -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; } @@ -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" { @@ -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)); } } @@ -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; |