Exclusive exec() path, format after partition.

Sadly setexeccon() is process global, so we need to carefully ensure
that all exec() are mutually exclusive to avoid transitioning into
unwanted domains.  Also, because we have several threads floating
around, we need to guard all our FDs with O_CLOEXEC.

Format all newly created volumes immediately after partitioning,
but silence all events emitted from those volumes to prevent the
framework from getting all excited.  Unify all notify events under a
single codepath to make them easy to silence.

Sent SIGINT before escalating to SIGTERM when unmounting.

Bug: 19993667
Change-Id: Idc6c806afc7919a004a93e2240b42884f6b52d6b
This commit is contained in:
Jeff Sharkey 2015-04-08 21:07:21 -07:00
parent 3896727376
commit ce6a913aea
15 changed files with 310 additions and 311 deletions

View file

@ -55,7 +55,7 @@ int Devmapper::dumpState(SocketClient *c) {
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening devmapper (%s)", strerror(errno));
free(buffer);
free(buffer2);
@ -138,7 +138,7 @@ int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) {
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening devmapper (%s)", strerror(errno));
free(buffer);
return -1;
@ -172,7 +172,7 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key,
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening devmapper (%s)", strerror(errno));
free(buffer);
return -1;
@ -269,7 +269,7 @@ int Devmapper::destroy(const char *name) {
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening devmapper (%s)", strerror(errno));
free(buffer);
return -1;

117
Disk.cpp
View file

@ -53,7 +53,7 @@ static const unsigned int kMajorBlockMmc = 179;
static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7";
static const char* kGptAndroidMeta = "19A710A2-B3CA-11E4-B026-10604B889DCF";
static const char* kGptAndroidExt = "193D1EA4-B3CA-11E4-B075-10604B889DCF";
static const char* kGptAndroidExpand = "193D1EA4-B3CA-11E4-B075-10604B889DCF";
static const char* kKeyPath = "/data/misc/vold";
@ -63,8 +63,10 @@ enum class Table {
kGpt,
};
Disk::Disk(const std::string& eventPath, dev_t device, const std::string& nickname, int flags) :
mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(false) {
Disk::Disk(const std::string& eventPath, dev_t device,
const std::string& nickname, int flags) :
mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(
false), mJustPartitioned(false) {
mId = StringPrintf("disk:%u,%u", major(device), minor(device));
mEventPath = eventPath;
mSysPath = StringPrintf("/sys/%s", eventPath.c_str());
@ -93,9 +95,7 @@ std::shared_ptr<VolumeBase> Disk::findVolume(const std::string& id) {
status_t Disk::create() {
CHECK(!mCreated);
mCreated = true;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::DiskCreated,
StringPrintf("%s %d", getId().c_str(), mFlags).c_str(), false);
notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
readMetadata();
readPartitions();
return OK;
@ -105,23 +105,28 @@ status_t Disk::destroy() {
CHECK(mCreated);
destroyAllVolumes();
mCreated = false;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::DiskDestroyed, getId().c_str(), false);
notifyEvent(ResponseCode::DiskDestroyed);
return OK;
}
static std::string BuildKeyPath(const std::string& partGuid) {
return StringPrintf("%s/ext_%s.key", kKeyPath, partGuid.c_str());
return StringPrintf("%s/expand_%s.key", kKeyPath, partGuid.c_str());
}
void Disk::createPublicVolume(dev_t device) {
auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));
vol->create();
if (mJustPartitioned) {
LOG(DEBUG) << "Device just partitioned; silently formatting";
vol->setSilent(true);
vol->create();
vol->format();
vol->destroy();
vol->setSilent(false);
}
mVolumes.push_back(vol);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::DiskVolumeCreated,
StringPrintf("%s %s", getId().c_str(), vol->getId().c_str()).c_str(), false);
vol->create();
notifyEvent(ResponseCode::DiskVolumeCreated, vol->getId());
}
void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
@ -142,12 +147,18 @@ void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
LOG(DEBUG) << "Found key for GUID " << normalizedGuid;
auto vol = std::shared_ptr<VolumeBase>(new PrivateVolume(device, keyRaw));
vol->create();
if (mJustPartitioned) {
LOG(DEBUG) << "Device just partitioned; silently formatting";
vol->setSilent(true);
vol->create();
vol->format();
vol->destroy();
vol->setSilent(false);
}
mVolumes.push_back(vol);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::DiskVolumeCreated,
StringPrintf("%s %s", getId().c_str(), vol->getId().c_str()).c_str(), false);
vol->create();
notifyEvent(ResponseCode::DiskVolumeCreated, vol->getId());
}
void Disk::destroyAllVolumes() {
@ -161,7 +172,7 @@ status_t Disk::readMetadata() {
mSize = -1;
mLabel.clear();
int fd = open(mDevPath.c_str(), O_RDONLY);
int fd = open(mDevPath.c_str(), O_RDONLY | O_CLOEXEC);
if (fd != -1) {
if (ioctl(fd, BLKGETSIZE64, &mSize)) {
mSize = -1;
@ -205,13 +216,8 @@ status_t Disk::readMetadata() {
}
}
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::DiskSizeChanged,
StringPrintf("%s %" PRId64, getId().c_str(), mSize).c_str(), false);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::DiskLabelChanged,
StringPrintf("%s %s", getId().c_str(), mLabel.c_str()).c_str(), false);
notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRId64, mSize));
notifyEvent(ResponseCode::DiskLabelChanged, mLabel);
return OK;
}
@ -224,22 +230,25 @@ status_t Disk::readPartitions() {
destroyAllVolumes();
// Parse partition table
std::string path(kSgdiskPath);
path += " --android-dump ";
path += mDevPath;
FILE* fp = popen(path.c_str(), "r");
if (!fp) {
PLOG(ERROR) << "Failed to run " << path;
return -errno;
std::vector<std::string> cmd;
cmd.push_back(kSgdiskPath);
cmd.push_back("--android-dump");
cmd.push_back(mDevPath);
std::vector<std::string> output;
status_t res = ForkExecvp(cmd, output);
if (res != OK) {
LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
mJustPartitioned = false;
return res;
}
char line[1024];
Table table = Table::kUnknown;
bool foundParts = false;
while (fgets(line, sizeof(line), fp) != nullptr) {
LOG(DEBUG) << "sgdisk: " << line;
char* token = strtok(line, kSgdiskToken);
for (auto line : output) {
char* cline = (char*) line.c_str();
char* token = strtok(cline, kSgdiskToken);
if (token == nullptr) continue;
if (!strcmp(token, "DISK")) {
@ -276,7 +285,7 @@ status_t Disk::readPartitions() {
if (!strcasecmp(typeGuid, kGptBasicData)) {
createPublicVolume(partDevice);
} else if (!strcasecmp(typeGuid, kGptAndroidExt)) {
} else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {
createPrivateVolume(partDevice, partGuid);
}
}
@ -289,7 +298,7 @@ status_t Disk::readPartitions() {
createPublicVolume(mDevice);
}
pclose(fp);
mJustPartitioned = false;
return OK;
}
@ -303,6 +312,7 @@ status_t Disk::unmountAll() {
status_t Disk::partitionPublic() {
// TODO: improve this code
destroyAllVolumes();
mJustPartitioned = true;
struct disk_info dinfo;
memset(&dinfo, 0, sizeof(dinfo));
@ -346,9 +356,10 @@ status_t Disk::partitionPrivate() {
}
status_t Disk::partitionMixed(int8_t ratio) {
int status = 0;
int res;
destroyAllVolumes();
mJustPartitioned = true;
// First nuke any existing partition table
std::vector<std::string> cmd;
@ -356,9 +367,9 @@ status_t Disk::partitionMixed(int8_t ratio) {
cmd.push_back("--zap-all");
cmd.push_back(mDevPath);
if (ForkExecvp(cmd, &status, false, true)) {
LOG(ERROR) << "Failed to zap; status " << status;
return -EIO;
if ((res = ForkExecvp(cmd)) != 0) {
LOG(ERROR) << "Failed to zap; status " << res;
return res;
}
// We've had some success above, so generate both the private partition
@ -408,20 +419,30 @@ status_t Disk::partitionMixed(int8_t ratio) {
// Define a single private partition filling the rest of disk.
cmd.push_back("--new=0:0:-0");
cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidExt));
cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidExpand));
cmd.push_back(StringPrintf("--partition-guid=0:%s", partGuid.c_str()));
cmd.push_back("--change-name=0:android_ext");
cmd.push_back("--change-name=0:android_expand");
cmd.push_back(mDevPath);
if (ForkExecvp(cmd, &status, false, true)) {
LOG(ERROR) << "Failed to partition; status " << status;
return -EIO;
if ((res = ForkExecvp(cmd)) != 0) {
LOG(ERROR) << "Failed to partition; status " << res;
return res;
}
return OK;
}
void Disk::notifyEvent(int event) {
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
getId().c_str(), false);
}
void Disk::notifyEvent(int event, const std::string& value) {
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
}
int Disk::getMaxMinors() {
// Figure out maximum partition devices supported
switch (major(mDevice)) {

5
Disk.h
View file

@ -74,6 +74,9 @@ public:
status_t partitionPrivate();
status_t partitionMixed(int8_t ratio);
void notifyEvent(int msg);
void notifyEvent(int msg, const std::string& value);
private:
/* ID that uniquely references this disk */
std::string mId;
@ -97,6 +100,8 @@ private:
int mFlags;
/* Flag indicating object is created */
bool mCreated;
/* Flag that we just partitioned and should format all volumes */
bool mJustPartitioned;
void createPublicVolume(dev_t device);
void createPrivateVolume(dev_t device, const std::string& partGuid);

106
Ext4.cpp
View file

@ -48,14 +48,11 @@
#include "Utils.h"
#include "VoldUtil.h"
#define RESIZE2FS_PATH "/system/bin/resize2fs"
using android::base::StringPrintf;
static const char* kResizefsPath = "/system/bin/resize2fs";
static const char* kMkfsPath = "/system/bin/make_ext4fs";
static const char* kFsckPath = "/system/bin/e2fsck";
static const char* kFsckLogFile = "/dev/fscklogs/log";
int Ext4::check(const char *fsPath, const char *mountPoint) {
// The following is shamelessly borrowed from fs_mgr.c, so it should be
@ -68,11 +65,6 @@ int Ext4::check(const char *fsPath, const char *mountPoint) {
int ret;
long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
char *tmpmnt_opts = (char*) "nomblk_io_submit,errors=remount-ro";
char *e2fsck_argv[] = {
(char*) kFsckPath,
(char*) "-y",
blk_device
};
/*
* First try to mount and unmount the filesystem. We do this because
@ -112,23 +104,13 @@ int Ext4::check(const char *fsPath, const char *mountPoint) {
} else {
ALOGD("Running %s on %s\n", kFsckPath, blk_device);
// Ext4 devices are currently always trusted
if (setexeccon(android::vold::sFsckContext)) {
LOG(ERROR) << "Failed to setexeccon()";
errno = EPERM;
return -1;
}
ret = android_fork_execvp(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
&status, false, true);
if (setexeccon(NULL)) {
abort();
}
std::vector<std::string> cmd;
cmd.push_back(kFsckPath);
cmd.push_back("-y");
cmd.push_back(blk_device);
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
ALOGW("Failed trying to run %s\n", kFsckPath);
return -1;
}
// Ext4 devices are currently always trusted
return android::vold::ForkExecvp(cmd, android::vold::sFsckContext);
}
return 0;
@ -157,51 +139,16 @@ int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remo
}
int Ext4::resize(const char *fspath, unsigned int numSectors) {
const char *args[4];
char* size_str;
int rc;
int status;
std::vector<std::string> cmd;
cmd.push_back(kResizefsPath);
cmd.push_back("-f");
cmd.push_back(fspath);
cmd.push_back(StringPrintf("%u", numSectors));
args[0] = RESIZE2FS_PATH;
args[1] = "-f";
args[2] = fspath;
if (asprintf(&size_str, "%ds", numSectors) < 0)
{
SLOGE("Filesystem (ext4) resize failed to set size");
return -1;
}
args[3] = size_str;
rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false,
true);
free(size_str);
if (rc != 0) {
SLOGE("Filesystem (ext4) resize failed due to logwrap error");
errno = EIO;
return -1;
}
if (!WIFEXITED(status)) {
SLOGE("Filesystem (ext4) resize did not exit properly");
errno = EIO;
return -1;
}
status = WEXITSTATUS(status);
if (status == 0) {
SLOGI("Filesystem (ext4) resized OK");
return 0;
} else {
SLOGE("Resize (ext4) failed (unknown exit code %d)", status);
errno = EIO;
return -1;
}
return 0;
return android::vold::ForkExecvp(cmd);
}
int Ext4::format(const char *fsPath, unsigned int numSectors, const char *mountpoint) {
int status;
std::vector<std::string> cmd;
cmd.push_back(kMkfsPath);
cmd.push_back("-J");
@ -214,30 +161,9 @@ int Ext4::format(const char *fsPath, unsigned int numSectors, const char *mountp
cmd.push_back(StringPrintf("%u", numSectors * 512));
}
// Always generate a real UUID
cmd.push_back("-u");
cmd.push_back(fsPath);
int rc = android::vold::ForkExecvp(cmd, &status, false, true);
if (rc != 0) {
SLOGE("Filesystem (ext4) format failed due to logwrap error");
errno = EIO;
return -1;
}
if (!WIFEXITED(status)) {
SLOGE("Filesystem (ext4) format did not exit properly");
errno = EIO;
return -1;
}
status = WEXITSTATUS(status);
if (status == 0) {
SLOGI("Filesystem (ext4) formatted OK");
return 0;
} else {
SLOGE("Format (ext4) failed (unknown exit code %d)", status);
errno = EIO;
return -1;
}
return 0;
return android::vold::ForkExecvp(cmd);
}

100
Fat.cpp
View file

@ -38,6 +38,7 @@
#define LOG_TAG "Vold"
#include <base/logging.h>
#include <base/stringprintf.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <selinux/selinux.h>
@ -48,12 +49,13 @@
#include "Utils.h"
#include "VoldUtil.h"
static char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
static char MKDOSFS_PATH[] = "/system/bin/newfs_msdos";
extern "C" int mount(const char *, const char *, const char *, unsigned long, const void *);
using android::base::StringPrintf;
static const char* kMkfsPath = "/system/bin/newfs_msdos";
static const char* kFsckPath = "/system/bin/fsck_msdos";
int Fat::check(const char *fsPath) {
if (access(FSCK_MSDOS_PATH, X_OK)) {
if (access(kFsckPath, X_OK)) {
SLOGW("Skipping fs checks\n");
return 0;
}
@ -61,40 +63,22 @@ int Fat::check(const char *fsPath) {
int pass = 1;
int rc = 0;
do {
const char *args[4];
int status;
args[0] = FSCK_MSDOS_PATH;
args[1] = "-p";
args[2] = "-f";
args[3] = fsPath;
std::vector<std::string> cmd;
cmd.push_back(kFsckPath);
cmd.push_back("-p");
cmd.push_back("-f");
cmd.push_back(fsPath);
// Fat devices are currently always untrusted
if (setexeccon(android::vold::sFsckUntrustedContext)) {
LOG(ERROR) << "Failed to setexeccon()";
errno = EPERM;
return -1;
}
rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status,
false, true);
if (setexeccon(NULL)) {
abort();
}
rc = android::vold::ForkExecvp(cmd, android::vold::sFsckUntrustedContext);
if (rc != 0) {
if (rc < 0) {
SLOGE("Filesystem check failed due to logwrap error");
errno = EIO;
return -1;
}
if (!WIFEXITED(status)) {
SLOGE("Filesystem check did not exit properly");
errno = EIO;
return -1;
}
status = WEXITSTATUS(status);
switch(status) {
switch(rc) {
case 0:
SLOGI("Filesystem check completed OK");
return 0;
@ -115,7 +99,7 @@ int Fat::check(const char *fsPath) {
return -1;
default:
SLOGE("Filesystem check failed (unknown exit code %d)", status);
SLOGE("Filesystem check failed (unknown exit code %d)", rc);
errno = EIO;
return -1;
}
@ -182,57 +166,39 @@ int Fat::doMount(const char *fsPath, const char *mountPoint,
}
int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) {
const char *args[11];
int rc;
int status;
if (wipe) {
Fat::wipe(fsPath, numSectors);
}
args[0] = MKDOSFS_PATH;
args[1] = "-F";
args[2] = "32";
args[3] = "-O";
args[4] = "android";
args[5] = "-c";
args[6] = "64";
args[7] = "-A";
std::vector<std::string> cmd;
cmd.push_back(kMkfsPath);
cmd.push_back("-F");
cmd.push_back("32");
cmd.push_back("-O");
cmd.push_back("android");
cmd.push_back("-c");
cmd.push_back("64");
cmd.push_back("-A");
if (numSectors) {
char tmp[32];
snprintf(tmp, sizeof(tmp), "%u", numSectors);
const char *size = tmp;
args[8] = "-s";
args[9] = size;
args[10] = fsPath;
rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status,
false, true);
} else {
args[8] = fsPath;
rc = android_fork_execvp(9, (char **)args, &status, false,
true);
cmd.push_back("-s");
cmd.push_back(StringPrintf("%u", numSectors));
}
if (rc != 0) {
cmd.push_back(fsPath);
int rc = android::vold::ForkExecvp(cmd);
if (rc < 0) {
SLOGE("Filesystem format failed due to logwrap error");
errno = EIO;
return -1;
}
if (!WIFEXITED(status)) {
SLOGE("Filesystem format did not exit properly");
errno = EIO;
return -1;
}
status = WEXITSTATUS(status);
if (status == 0) {
if (rc == 0) {
SLOGI("Filesystem formatted OK");
return 0;
} else {
SLOGE("Format failed (unknown exit code %d)", status);
SLOGE("Format failed (unknown exit code %d)", rc);
errno = EIO;
return -1;
}
@ -242,7 +208,7 @@ int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) {
void Fat::wipe(const char *fsPath, unsigned int numSectors) {
unsigned long long range[2];
int fd = open(fsPath, O_RDWR);
int fd = open(fsPath, O_RDWR | O_CLOEXEC);
if (fd == -1) {
SLOGE("Fat wipe failed to open device %s", fsPath);
return;

View file

@ -49,7 +49,7 @@ int Loop::dumpState(SocketClient *c) {
sprintf(filename, "/dev/block/loop%d", i);
if ((fd = open(filename, O_RDWR)) < 0) {
if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
if (errno != ENOENT) {
SLOGE("Unable to open %s (%s)", filename, strerror(errno));
} else {
@ -93,7 +93,7 @@ int Loop::lookupActive(const char *id, char *buffer, size_t len) {
sprintf(filename, "/dev/block/loop%d", i);
if ((fd = open(filename, O_RDWR)) < 0) {
if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
if (errno != ENOENT) {
SLOGE("Unable to open %s (%s)", filename, strerror(errno));
} else {
@ -168,7 +168,7 @@ int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, s
setfscreatecon(NULL);
}
if ((fd = open(filename, O_RDWR)) < 0) {
if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Unable to open %s (%s)", filename, strerror(errno));
return -1;
}
@ -196,7 +196,7 @@ int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, s
int file_fd;
if ((file_fd = open(loopFile, O_RDWR)) < 0) {
if ((file_fd = open(loopFile, O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Unable to open %s (%s)", loopFile, strerror(errno));
close(fd);
return -1;
@ -231,7 +231,7 @@ int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, s
int Loop::destroyByDevice(const char *loopDevice) {
int device_fd;
device_fd = open(loopDevice, O_RDONLY);
device_fd = open(loopDevice, O_RDONLY | O_CLOEXEC);
if (device_fd < 0) {
SLOGE("Failed to open loop (%d)", errno);
return -1;
@ -272,7 +272,7 @@ int Loop::createImageFile(const char *file, unsigned int numSectors) {
int Loop::resizeImageFile(const char *file, unsigned int numSectors) {
int fd;
if ((fd = open(file, O_RDWR)) < 0) {
if ((fd = open(file, O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening imagefile (%s)", strerror(errno));
return -1;
}
@ -301,7 +301,7 @@ int Loop::lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigne
int fd;
struct asec_superblock buffer;
if ((fd = open(loopDevice, O_RDONLY)) < 0) {
if ((fd = open(loopDevice, O_RDONLY | O_CLOEXEC)) < 0) {
SLOGE("Failed to open loopdevice (%s)", strerror(errno));
destroyByDevice(loopDevice);
return -1;

View file

@ -50,17 +50,9 @@ PrivateVolume::~PrivateVolume() {
status_t PrivateVolume::readMetadata() {
status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeFsTypeChanged,
StringPrintf("%s %s", getId().c_str(), mFsType.c_str()).c_str(), false);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeFsUuidChanged,
StringPrintf("%s %s", getId().c_str(), mFsUuid.c_str()).c_str(), false);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeFsLabelChanged,
StringPrintf("%s %s", getId().c_str(), mFsLabel.c_str()).c_str(), false);
notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
return res;
}

View file

@ -66,7 +66,7 @@ int Process::pathMatchesMountPoint(const char* path, const char* mountPoint) {
void Process::getProcessName(int pid, char *buffer, size_t max) {
int fd;
snprintf(buffer, max, "/proc/%d/cmdline", pid);
fd = open(buffer, O_RDONLY);
fd = open(buffer, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
strcpy(buffer, "???");
} else {

View file

@ -52,17 +52,9 @@ PublicVolume::~PublicVolume() {
status_t PublicVolume::readMetadata() {
status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeFsTypeChanged,
StringPrintf("%s %s", getId().c_str(), mFsType.c_str()).c_str(), false);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeFsUuidChanged,
StringPrintf("%s %s", getId().c_str(), mFsUuid.c_str()).c_str(), false);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeFsLabelChanged,
StringPrintf("%s %s", getId().c_str(), mFsLabel.c_str()).c_str(), false);
notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
return res;
}

130
Utils.cpp
View file

@ -24,6 +24,7 @@
#include <private/android_filesystem_config.h>
#include <logwrap/logwrap.h>
#include <mutex>
#include <fcntl.h>
#include <linux/fs.h>
#include <stdlib.h>
@ -41,6 +42,10 @@ using android::base::StringPrintf;
namespace android {
namespace vold {
/* Since we use setexeccon(), we need to carefully lock around any
* code that calls exec() to avoid crossing the streams. */
static std::mutex sExecLock;
security_context_t sBlkidContext = nullptr;
security_context_t sBlkidUntrustedContext = nullptr;
security_context_t sFsckContext = nullptr;
@ -116,6 +121,14 @@ status_t ForceUnmount(const std::string& path) {
}
PLOG(WARNING) << "Failed to unmount " << path;
sleep(5);
Process::killProcessesWithOpenFiles(cpath, SIGINT);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
PLOG(WARNING) << "Failed to unmount " << path;
sleep(5);
Process::killProcessesWithOpenFiles(cpath, SIGTERM);
@ -149,48 +162,40 @@ static status_t readMetadata(const std::string& path, std::string& fsType,
fsUuid.clear();
fsLabel.clear();
std::string cmd(StringPrintf("%s -c /dev/null %s", kBlkidPath, path.c_str()));
if (setexeccon(untrusted ? sBlkidUntrustedContext : sBlkidContext)) {
LOG(ERROR) << "Failed to setexeccon()";
return -EPERM;
}
FILE* fp = popen(cmd.c_str(), "r");
if (setexeccon(NULL)) {
abort();
}
if (!fp) {
PLOG(ERROR) << "Failed to run " << cmd;
return -errno;
std::vector<std::string> cmd;
cmd.push_back(kBlkidPath);
cmd.push_back("-c");
cmd.push_back("/dev/null");
cmd.push_back(path);
std::vector<std::string> output;
status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
if (res != OK) {
LOG(WARNING) << "blkid failed to identify " << path;
return res;
}
status_t res = OK;
char line[1024];
char value[128];
if (fgets(line, sizeof(line), fp) != nullptr) {
LOG(DEBUG) << "blkid identified " << path << " as " << line;
for (auto line : output) {
// Extract values from blkid output, if defined
char* start = strstr(line, "TYPE=");
const char* cline = line.c_str();
char* start = strstr(cline, "TYPE=");
if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
fsType = value;
}
start = strstr(line, "UUID=");
start = strstr(cline, "UUID=");
if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
fsUuid = value;
}
start = strstr(line, "LABEL=");
start = strstr(cline, "LABEL=");
if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
fsLabel = value;
}
} else {
LOG(WARNING) << "blkid failed to identify " << path;
res = -ENODATA;
}
pclose(fp);
return res;
return OK;
}
status_t ReadMetadata(const std::string& path, std::string& fsType,
@ -203,11 +208,14 @@ status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
return readMetadata(path, fsType, fsUuid, fsLabel, true);
}
status_t ForkExecvp(const std::vector<std::string>& args, int* status,
bool ignore_int_quit, bool logwrap) {
int argc = args.size();
status_t ForkExecvp(const std::vector<std::string>& args) {
return ForkExecvp(args, nullptr);
}
status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context) {
size_t argc = args.size();
char** argv = (char**) calloc(argc, sizeof(char*));
for (int i = 0; i < argc; i++) {
for (size_t i = 0; i < argc; i++) {
argv[i] = (char*) args[i].c_str();
if (i == 0) {
LOG(VERBOSE) << args[i];
@ -215,11 +223,73 @@ status_t ForkExecvp(const std::vector<std::string>& args, int* status,
LOG(VERBOSE) << " " << args[i];
}
}
int res = android_fork_execvp(argc, argv, status, ignore_int_quit, logwrap);
status_t res = OK;
{
std::lock_guard<std::mutex> lock(sExecLock);
if (setexeccon(context)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
res = android_fork_execvp(argc, argv, NULL, false, true);
if (setexeccon(nullptr)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
}
free(argv);
return res;
}
status_t ForkExecvp(const std::vector<std::string>& args,
std::vector<std::string>& output) {
return ForkExecvp(args, output, nullptr);
}
status_t ForkExecvp(const std::vector<std::string>& args,
std::vector<std::string>& output, security_context_t context) {
std::string cmd;
for (size_t i = 0; i < args.size(); i++) {
cmd += args[i] + " ";
if (i == 0) {
LOG(VERBOSE) << args[i];
} else {
LOG(VERBOSE) << " " << args[i];
}
}
output.clear();
FILE* fp = nullptr;
{
std::lock_guard<std::mutex> lock(sExecLock);
if (setexeccon(context)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
fp = popen(cmd.c_str(), "r");
if (setexeccon(nullptr)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
}
if (!fp) {
PLOG(ERROR) << "Failed to popen " << cmd;
return -errno;
}
char line[1024];
while (fgets(line, sizeof(line), fp) != nullptr) {
LOG(VERBOSE) << line;
output.push_back(std::string(line));
}
if (pclose(fp) != 0) {
PLOG(ERROR) << "Failed to pclose " << cmd;
return -errno;
}
return OK;
}
status_t ReadRandomBytes(size_t bytes, std::string& out) {
out.clear();

10
Utils.h
View file

@ -60,8 +60,14 @@ status_t ReadMetadata(const std::string& path, std::string& fsType,
status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel);
status_t ForkExecvp(const std::vector<std::string>& args, int* status,
bool ignore_int_quit, bool logwrap);
/* Returns either WEXITSTATUS() status, or a negative errno */
status_t ForkExecvp(const std::vector<std::string>& args);
status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context);
status_t ForkExecvp(const std::vector<std::string>& args,
std::vector<std::string>& output);
status_t ForkExecvp(const std::vector<std::string>& args,
std::vector<std::string>& output, security_context_t context);
status_t ReadRandomBytes(size_t bytes, std::string& out);

View file

@ -36,7 +36,8 @@ namespace android {
namespace vold {
VolumeBase::VolumeBase(Type type) :
mType(type), mFlags(0), mUser(-1), mCreated(false), mState(State::kUnmounted) {
mType(type), mFlags(0), mUser(-1), mCreated(false), mState(
State::kUnmounted), mSilent(false) {
}
VolumeBase::~VolumeBase() {
@ -45,10 +46,7 @@ VolumeBase::~VolumeBase() {
void VolumeBase::setState(State state) {
mState = state;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeStateChanged,
StringPrintf("%s %d", getId().c_str(), mState).c_str(), false);
notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
}
status_t VolumeBase::setFlags(int flags) {
@ -71,6 +69,16 @@ status_t VolumeBase::setUser(userid_t user) {
return OK;
}
status_t VolumeBase::setSilent(bool silent) {
if (mCreated) {
LOG(WARNING) << getId() << " silence change requires destroyed";
return -EBUSY;
}
mSilent = silent;
return OK;
}
status_t VolumeBase::setId(const std::string& id) {
if (mCreated) {
LOG(WARNING) << getId() << " id change requires not created";
@ -88,12 +96,22 @@ status_t VolumeBase::setPath(const std::string& path) {
}
mPath = path;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumePathChanged,
StringPrintf("%s %s", getId().c_str(), mPath.c_str()).c_str(), false);
notifyEvent(ResponseCode::VolumePathChanged, mPath);
return OK;
}
void VolumeBase::notifyEvent(int event) {
if (mSilent) return;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
getId().c_str(), false);
}
void VolumeBase::notifyEvent(int event, const std::string& value) {
if (mSilent) return;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
}
void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
mVolumes.push_back(volume);
}
@ -116,9 +134,7 @@ status_t VolumeBase::create() {
mCreated = true;
status_t res = doCreate();
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeCreated,
StringPrintf("%s %d", getId().c_str(), mType).c_str(), false);
notifyEvent(ResponseCode::VolumeCreated, StringPrintf("%d", mType));
return res;
}
@ -133,8 +149,7 @@ status_t VolumeBase::destroy() {
unmount();
}
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeDestroyed, getId().c_str(), false);
notifyEvent(ResponseCode::VolumeDestroyed);
status_t res = doDestroy();
mCreated = false;
return res;

View file

@ -86,6 +86,7 @@ public:
status_t setFlags(int flags);
status_t setUser(userid_t user);
status_t setSilent(bool silent);
void addVolume(const std::shared_ptr<VolumeBase>& volume);
void removeVolume(const std::shared_ptr<VolumeBase>& volume);
@ -110,6 +111,9 @@ protected:
status_t setId(const std::string& id);
status_t setPath(const std::string& path);
void notifyEvent(int msg);
void notifyEvent(int msg, const std::string& value);
private:
/* ID that uniquely references volume while alive */
std::string mId;
@ -125,6 +129,8 @@ private:
State mState;
/* Path to mounted volume */
std::string mPath;
/* Flag indicating that volume should emit no events */
bool mSilent;
/* Volumes stacked on top of this volume */
std::list<std::shared_ptr<VolumeBase>> mVolumes;

View file

@ -95,7 +95,7 @@ static const unsigned int kMajorBlockMmc = 179;
/* writes superblock at end of file or device given by name */
static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) {
int sbfd = open(name, O_RDWR);
int sbfd = open(name, O_RDWR | O_CLOEXEC);
if (sbfd < 0) {
SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno));
return -1;
@ -726,7 +726,7 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, const cha
}
if (usingExt4) {
int dirfd = open(mountPoint, O_DIRECTORY);
int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
if (dirfd >= 0) {
if (fchown(dirfd, ownerUid, AID_SYSTEM)
|| fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
@ -775,7 +775,7 @@ int VolumeManager::resizeAsec(const char *id, unsigned numSectors, const char *k
int fd;
unsigned int oldNumSec = 0;
if ((fd = open(asecFileName, O_RDONLY)) < 0) {
if ((fd = open(asecFileName, O_RDONLY | O_CLOEXEC)) < 0) {
SLOGE("Failed to open ASEC file (%s)", strerror(errno));
return -1;
}
@ -1021,7 +1021,7 @@ int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* f
*/
const bool privateFile = !strcmp(ftsent->fts_name, filename);
int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
int fd = open(ftsent->fts_accpath, O_NOFOLLOW | O_CLOEXEC);
if (fd < 0) {
SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
result = -1;
@ -1046,7 +1046,7 @@ int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* f
fts_close(fts);
// Finally make the directory readable by everyone.
int dirfd = open(mountPoint, O_DIRECTORY);
int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
if (dirfd < 0 || fchmod(dirfd, 0755)) {
SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
result |= -1;
@ -1354,7 +1354,7 @@ bool VolumeManager::isLegalAsecId(const char *id) const {
}
bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
int dirfd = open(dir, O_DIRECTORY);
int dirfd = open(dir, O_DIRECTORY | O_CLOEXEC);
if (dirfd < 0) {
SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
return false;
@ -1546,7 +1546,7 @@ int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
int fd;
unsigned long nr_sec = 0;
if ((fd = open(loopDevice, O_RDWR)) < 0) {
if ((fd = open(loopDevice, O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Failed to open loopdevice (%s)", strerror(errno));
Loop::destroyByDevice(loopDevice);
return -1;
@ -1612,7 +1612,7 @@ int VolumeManager::listMountedObbs(SocketClient* cli) {
mntent* mentry;
while ((mentry = getmntent(fp)) != NULL) {
if (!strncmp(mentry->mnt_dir, loopDir, loopDirLen)) {
int fd = open(mentry->mnt_fsname, O_RDONLY);
int fd = open(mentry->mnt_fsname, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
struct loop_info64 li;
if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {

View file

@ -380,7 +380,7 @@ static unsigned int get_fs_size(char *dev)
struct ext4_super_block sb;
off64_t len;
if ((fd = open(dev, O_RDONLY)) < 0) {
if ((fd = open(dev, O_RDONLY|O_CLOEXEC)) < 0) {
SLOGE("Cannot open device to get filesystem size ");
return 0;
}
@ -423,7 +423,7 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off)
fs_mgr_get_crypt_info(fstab, key_loc, real_blkdev, sizeof(key_loc));
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
if ( (fd = open(real_blkdev, O_RDWR)) < 0) {
if ( (fd = open(real_blkdev, O_RDWR|O_CLOEXEC)) < 0) {
SLOGE("Cannot open real block device %s\n", real_blkdev);
return -1;
}
@ -485,7 +485,7 @@ static int put_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
SLOGE("Unexpected value for crypto key location\n");
return -1;
}
if ( (fd = open(fname, O_RDWR | O_CREAT, 0600)) < 0) {
if ( (fd = open(fname, O_RDWR | O_CREAT|O_CLOEXEC, 0600)) < 0) {
SLOGE("Cannot open footer file %s for put\n", fname);
return -1;
}
@ -623,7 +623,7 @@ static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
SLOGE("Unexpected value for crypto key location\n");
return -1;
}
if ( (fd = open(fname, O_RDWR)) < 0) {
if ( (fd = open(fname, O_RDWR|O_CLOEXEC)) < 0) {
SLOGE("Cannot open footer file %s for get\n", fname);
return -1;
}
@ -748,7 +748,7 @@ static int load_persistent_data(void)
return -1;
}
fd = open(fname, O_RDONLY);
fd = open(fname, O_RDONLY|O_CLOEXEC);
if (fd < 0) {
SLOGE("Cannot open %s metadata file", fname);
return -1;
@ -829,7 +829,7 @@ static int save_persistent_data(void)
return -1;
}
fd = open(fname, O_RDWR);
fd = open(fname, O_RDWR|O_CLOEXEC);
if (fd < 0) {
SLOGE("Cannot open %s metadata file", fname);
return -1;
@ -1067,7 +1067,7 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr,
char *extra_params;
int load_count;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) {
if ((fd = open("/dev/device-mapper", O_RDWR|O_CLOEXEC)) < 0 ) {
SLOGE("Cannot open device-mapper\n");
goto errout;
}
@ -1132,7 +1132,7 @@ static int delete_crypto_blk_dev(char *name)
struct dm_ioctl *io;
int retval = -1;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) {
if ((fd = open("/dev/device-mapper", O_RDWR|O_CLOEXEC)) < 0 ) {
SLOGE("Cannot open device-mapper\n");
goto errout;
}
@ -1416,7 +1416,7 @@ static int create_encrypted_random_key(char *passwd, unsigned char *master_key,
unsigned char key_buf[KEY_LEN_BYTES];
/* Get some random bits for a key */
fd = open("/dev/urandom", O_RDONLY);
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC);
read(fd, key_buf, sizeof(key_buf));
read(fd, salt, SALT_LEN);
close(fd);
@ -1892,7 +1892,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
*/
int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
const unsigned char* key, int keysize, char* out_crypto_blkdev) {
int fd = open(real_blkdev, O_RDONLY);
int fd = open(real_blkdev, O_RDONLY|O_CLOEXEC);
if (fd == -1) {
SLOGE("Failed to open %s: %s", real_blkdev, strerror(errno));
return -1;
@ -2453,14 +2453,14 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev,
data.real_blkdev = real_blkdev;
data.crypto_blkdev = crypto_blkdev;
if ( (data.realfd = open(real_blkdev, O_RDWR)) < 0) {
if ( (data.realfd = open(real_blkdev, O_RDWR|O_CLOEXEC)) < 0) {
SLOGE("Error opening real_blkdev %s for inplace encrypt. err=%d(%s)\n",
real_blkdev, errno, strerror(errno));
rc = -1;
goto errout;
}
if ( (data.cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) {
if ( (data.cryptofd = open(crypto_blkdev, O_WRONLY|O_CLOEXEC)) < 0) {
SLOGE("Error opening crypto_blkdev %s for ext4 inplace encrypt. err=%d(%s)\n",
crypto_blkdev, errno, strerror(errno));
rc = ENABLE_INPLACE_ERR_DEV;
@ -2584,12 +2584,12 @@ static int cryptfs_enable_inplace_f2fs(char *crypto_blkdev,
data.crypto_blkdev = crypto_blkdev;
data.realfd = -1;
data.cryptofd = -1;
if ( (data.realfd = open64(real_blkdev, O_RDWR)) < 0) {
if ( (data.realfd = open64(real_blkdev, O_RDWR|O_CLOEXEC)) < 0) {
SLOGE("Error opening real_blkdev %s for f2fs inplace encrypt\n",
real_blkdev);
goto errout;
}
if ( (data.cryptofd = open64(crypto_blkdev, O_WRONLY)) < 0) {
if ( (data.cryptofd = open64(crypto_blkdev, O_WRONLY|O_CLOEXEC)) < 0) {
SLOGE("Error opening crypto_blkdev %s for f2fs inplace encrypt. err=%d(%s)\n",
crypto_blkdev, errno, strerror(errno));
rc = ENABLE_INPLACE_ERR_DEV;
@ -2656,12 +2656,12 @@ static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev,
off64_t one_pct, cur_pct, new_pct;
off64_t blocks_already_done, tot_numblocks;
if ( (realfd = open(real_blkdev, O_RDONLY)) < 0) {
if ( (realfd = open(real_blkdev, O_RDONLY|O_CLOEXEC)) < 0) {
SLOGE("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev);
return ENABLE_INPLACE_ERR_OTHER;
}
if ( (cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) {
if ( (cryptofd = open(crypto_blkdev, O_WRONLY|O_CLOEXEC)) < 0) {
SLOGE("Error opening crypto_blkdev %s for inplace encrypt. err=%d(%s)\n",
crypto_blkdev, errno, strerror(errno));
close(realfd);
@ -2819,7 +2819,7 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev,
static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf)
{
int fd = open(filename, O_RDONLY);
int fd = open(filename, O_RDONLY|O_CLOEXEC);
if (fd == -1) {
SLOGE("Error opening file %s", filename);
return -1;
@ -2959,7 +2959,7 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
/* Get the size of the real block device */
int fd = open(real_blkdev, O_RDONLY);
int fd = open(real_blkdev, O_RDONLY|O_CLOEXEC);
if (fd == -1) {
SLOGE("Cannot open block device %s\n", real_blkdev);
goto error_unencrypted;
@ -3190,7 +3190,7 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
/* 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, 0600);
int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0600);
if (fd >= 0) {
write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
write(fd, "--reason=cryptfs_enable_internal\n", strlen("--reason=cryptfs_enable_internal\n") + 1);