Merge "libutils: fix overflow in String8::allocFromUTF8" into mnc-dev
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index e8e9a0f..5d17335 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -57,7 +57,7 @@
if(x == 0) return 0;
*x = 0;
if (should_use_fs_config(name)) {
- fs_config(name, 1, &uid, &gid, &mode, &cap);
+ fs_config(name, 1, NULL, &uid, &gid, &mode, &cap);
}
ret = adb_mkdir(name, mode);
if((ret < 0) && (errno != EEXIST)) {
@@ -366,7 +366,7 @@
tmp++;
}
if (should_use_fs_config(path)) {
- fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+ fs_config(tmp, 0, NULL, &uid, &gid, &mode, &cap);
}
return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
}
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 7175749..0e35323 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -41,6 +41,7 @@
};
static struct fs_config_entry* canned_config = NULL;
+static char *target_out_path = NULL;
/* Each line in the canned file should be a path plus three ints (uid,
* gid, mode). */
@@ -79,7 +80,8 @@
} else {
// Use the compiled-in fs_config() function.
unsigned st_mode = s->st_mode;
- fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+ fs_config(path, S_ISDIR(s->st_mode), target_out_path,
+ &s->st_uid, &s->st_gid, &st_mode, &capabilities);
s->st_mode = (typeof(s->st_mode)) st_mode;
}
}
@@ -328,6 +330,12 @@
argc--;
argv++;
+ if (argc > 1 && strcmp(argv[0], "-d") == 0) {
+ target_out_path = argv[1];
+ argc -= 2;
+ argv += 2;
+ }
+
if (argc > 1 && strcmp(argv[0], "-f") == 0) {
read_canned_config(argv[1]);
argc -= 2;
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index c310160..beb95de 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -225,11 +225,26 @@
}
int32_t FingerprintDaemonProxy::closeHal() {
- return -ENOSYS; // TODO
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeCloseHal()\n");
+ if (mDevice == NULL) {
+ ALOGE("No valid device");
+ return -ENOSYS;
+ }
+ int err;
+ if (0 != (err = mDevice->common.close(reinterpret_cast<hw_device_t*>(mDevice)))) {
+ ALOGE("Can't close fingerprint module, error: %d", err);
+ return err;
+ }
+ mDevice = NULL;
+ return 0;
}
void FingerprintDaemonProxy::binderDied(const wp<IBinder>& who) {
ALOGD("binder died");
+ int err;
+ if (0 != (err = closeHal())) {
+ ALOGE("Can't close fingerprint device, error: %d", err);
+ }
if (IInterface::asBinder(mCallback) == who) {
mCallback = NULL;
}
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index 95c6a74..c73045d 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -52,7 +52,7 @@
info.len = ((off64_t)nr_sec * 512);
/* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
- rc = make_ext4fs_internal(fd, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
+ rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
if (rc) {
ERROR("make_ext4fs returned %d.\n", rc);
}
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index cc8c57e..2d1abbe 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -767,8 +767,24 @@
static int load_verity_state(struct fstab_rec *fstab, int *mode)
{
- off64_t offset = 0;
+ char propbuf[PROPERTY_VALUE_MAX];
int match = 0;
+ off64_t offset = 0;
+
+ /* use the kernel parameter if set */
+ property_get("ro.boot.veritymode", propbuf, "");
+
+ if (*propbuf != '\0') {
+ if (!strcmp(propbuf, "enforcing")) {
+ *mode = VERITY_MODE_DEFAULT;
+ return 0;
+ } else if (!strcmp(propbuf, "logging")) {
+ *mode = VERITY_MODE_LOGGING;
+ return 0;
+ } else {
+ INFO("Unknown value %s for veritymode; ignoring", propbuf);
+ }
+ }
if (get_verity_state_offset(fstab, &offset) < 0) {
/* fall back to stateless behavior */
@@ -855,6 +871,13 @@
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
struct fstab *fstab = NULL;
+ /* check if we need to store the state */
+ property_get("ro.boot.veritymode", propbuf, "");
+
+ if (*propbuf != '\0') {
+ return 0; /* state is kept by the bootloader */
+ }
+
fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
if (fd == -1) {
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index ce050ae..55b2d5e 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -18,7 +18,12 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused
-LOCAL_SRC_FILES := SoftGateKeeperDevice.cpp IGateKeeperService.cpp gatekeeperd.cpp
+LOCAL_SRC_FILES := \
+ SoftGateKeeperDevice.cpp \
+ IGateKeeperService.cpp \
+ gatekeeperd.cpp \
+ IUserManager.cpp
+
LOCAL_MODULE := gatekeeperd
LOCAL_SHARED_LIBRARIES := \
libbinder \
diff --git a/gatekeeperd/IUserManager.cpp b/gatekeeperd/IUserManager.cpp
new file mode 100644
index 0000000..8645fc2
--- /dev/null
+++ b/gatekeeperd/IUserManager.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "IUserManager"
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+
+#include "IUserManager.h"
+
+namespace android {
+
+class BpUserManager : public BpInterface<IUserManager>
+{
+public:
+ BpUserManager(const sp<IBinder>& impl) :
+ BpInterface<IUserManager>(impl) {
+ }
+ virtual int32_t getCredentialOwnerProfile(int32_t user_id) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IUserManager::getInterfaceDescriptor());
+ data.writeInt32(user_id);
+ status_t rc = remote()->transact(GET_CREDENTIAL_OWNER_PROFILE, data, &reply, 0);
+ if (rc != NO_ERROR) {
+ ALOGE("%s: failed (%d)\n", __func__, rc);
+ return -1;
+ }
+
+ int32_t exception = reply.readExceptionCode();
+ if (exception != 0) {
+ ALOGE("%s: got exception (%d)\n", __func__, exception);
+ return -1;
+ }
+
+ return reply.readInt32();
+ }
+
+};
+
+IMPLEMENT_META_INTERFACE(UserManager, "android.os.IUserManager");
+
+}; // namespace android
+
diff --git a/gatekeeperd/IUserManager.h b/gatekeeperd/IUserManager.h
new file mode 100644
index 0000000..640e9b5
--- /dev/null
+++ b/gatekeeperd/IUserManager.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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 IUSERMANAGER_H_
+#define IUSERMANAGER_H_
+
+#include <inttypes.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+/*
+* Communication channel to UserManager
+*/
+class IUserManager : public IInterface {
+ public:
+ // must be kept in sync with IUserManager.aidl
+ enum {
+ GET_CREDENTIAL_OWNER_PROFILE = IBinder::FIRST_CALL_TRANSACTION + 0,
+ };
+
+ virtual int32_t getCredentialOwnerProfile(int32_t user_id) = 0;
+
+ DECLARE_META_INTERFACE(UserManager);
+};
+
+}; // namespace android
+
+#endif // IUSERMANAGER_H_
+
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 6622df9..b4fdab0 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -40,6 +40,7 @@
#include <hardware/hw_auth_token.h>
#include "SoftGateKeeperDevice.h"
+#include "IUserManager.h"
namespace android {
@@ -50,6 +51,8 @@
public:
GateKeeperProxy() {
int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
+ device = NULL;
+
if (ret < 0) {
ALOGW("falling back to software GateKeeper");
soft_device.reset(new SoftGateKeeperDevice());
@@ -112,6 +115,7 @@
int fd = open(filename, O_RDONLY);
if (fd < 0) return 0;
read(fd, &sid, sizeof(sid));
+ close(fd);
return sid;
}
@@ -260,7 +264,21 @@
}
virtual uint64_t getSecureUserId(uint32_t uid) {
- return read_sid(uid);
+ uint64_t sid = read_sid(uid);
+ if (sid == 0) {
+ // might be a work profile, look up the parent
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("user"));
+ sp<IUserManager> um = interface_cast<IUserManager>(binder);
+ int32_t parent = um->getCredentialOwnerProfile(uid);
+ if (parent < 0) {
+ return 0;
+ } else if (parent != (int32_t) uid) {
+ return read_sid(parent);
+ }
+ }
+ return sid;
+
}
virtual void clearSecureUserId(uint32_t uid) {
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 02fe2b5..2ed27dc 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -206,13 +206,13 @@
* Used in:
* build/tools/fs_config/fs_config.c
* build/tools/fs_get_stats/fs_get_stats.c
- * external/genext2fs/genext2fs.c
+ * system/extras/ext4_utils/make_ext4fs_main.c
* external/squashfs-tools/squashfs-tools/android.c
* system/core/cpio/mkbootfs.c
* system/core/adb/file_sync_service.cpp
* system/extras/ext4_utils/canned_fs_config.c
*/
-void fs_config(const char *path, int dir,
+void fs_config(const char *path, int dir, const char *target_out_path,
unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);
diff --git a/include/system/graphics.h b/include/system/graphics.h
index ff3fd88..afd9f7b 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -370,7 +370,7 @@
* struct android_ycbcr (below) is the the struct used to describe it.
*
* This format must be accepted by the gralloc module when
- * USAGE_HW_CAMERA_WRITE and USAGE_SW_READ_* are set.
+ * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set.
*
* This format is locked for use by gralloc's (*lock_ycbcr) method, and
* locking with the (*lock) method will return an error.
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 9f8023e..9a1ad19 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -149,14 +149,21 @@
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
};
-static int fs_config_open(int dir)
+static int fs_config_open(int dir, const char *target_out_path)
{
int fd = -1;
- const char *out = getenv("OUT");
- if (out && *out) {
+ if (target_out_path && *target_out_path) {
+ /* target_out_path is the path to the directory holding content of system partition
+ but as we cannot guaranty it ends with '/system' we need this below skip_len logic */
char *name = NULL;
- asprintf(&name, "%s%s", out, dir ? conf_dir : conf_file);
+ int target_out_path_len = strlen(target_out_path);
+ int skip_len = strlen("/system");
+
+ if (target_out_path[target_out_path_len] == '/') {
+ skip_len++;
+ }
+ asprintf(&name, "%s%s", target_out_path, (dir ? conf_dir : conf_file) + skip_len);
if (name) {
fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
free(name);
@@ -187,7 +194,7 @@
return !strncmp(prefix, path, len);
}
-void fs_config(const char *path, int dir,
+void fs_config(const char *path, int dir, const char *target_out_path,
unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
{
const struct fs_path_config *pc;
@@ -199,7 +206,7 @@
plen = strlen(path);
- fd = fs_config_open(dir);
+ fd = fs_config_open(dir, target_out_path);
if (fd >= 0) {
struct fs_path_config_from_file header;
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 2347028..23dcd62 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -463,19 +463,19 @@
// Construct "SERVERS=<comma-separated string of DNS addresses>".
static const char kServerTag[] = "SERVERS=";
- static const int kTagLength = strlen(kServerTag);
+ static const size_t kTagLength = strlen(kServerTag);
// Reserve sufficient space for an IPv6 link-local address: all but the
// last address are followed by ','; the last is followed by '\0'.
- static const int kMaxSingleAddressLength =
+ static const size_t kMaxSingleAddressLength =
INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(",");
- const int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
+ const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength;
char *buf = (char *) malloc(bufsize);
if (!buf) {
SLOGE("RDNSS option: out of memory\n");
return false;
}
strcpy(buf, kServerTag);
- int pos = kTagLength;
+ size_t pos = kTagLength;
struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
for (int i = 0; i < numaddrs; i++) {
diff --git a/logd/main.cpp b/logd/main.cpp
index 9b88983..a3241d0 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -103,6 +103,10 @@
return -1;
}
+ if (setgroups(0, NULL) == -1) {
+ return -1;
+ }
+
if (setgid(AID_LOGD) != 0) {
return -1;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 7af2b77..b71908c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -69,16 +69,17 @@
# Storage views to support runtime permissions
mkdir /storage 0755 root root
- mkdir /mnt/runtime_default 0755 root root
- mkdir /mnt/runtime_default/self 0755 root root
- mkdir /mnt/runtime_read 0755 root root
- mkdir /mnt/runtime_read/self 0755 root root
- mkdir /mnt/runtime_write 0755 root root
- mkdir /mnt/runtime_write/self 0755 root root
+ mkdir /mnt/runtime 0700 root root
+ mkdir /mnt/runtime/default 0755 root root
+ mkdir /mnt/runtime/default/self 0755 root root
+ mkdir /mnt/runtime/read 0755 root root
+ mkdir /mnt/runtime/read/self 0755 root root
+ mkdir /mnt/runtime/write 0755 root root
+ mkdir /mnt/runtime/write/self 0755 root root
# Symlink to keep legacy apps working in multi-user world
symlink /storage/self/primary /sdcard
- symlink /mnt/user/0/primary /mnt/runtime_default/self/primary
+ symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
# memory control cgroup
mkdir /dev/memcg 0700 root system
@@ -145,9 +146,9 @@
chown system system /dev/cpuset/tasks
chown system system /dev/cpuset/foreground/tasks
chown system system /dev/cpuset/background/tasks
- chmod 0644 /dev/cpuset/foreground/tasks
- chmod 0644 /dev/cpuset/background/tasks
- chmod 0644 /dev/cpuset/tasks
+ chmod 0664 /dev/cpuset/foreground/tasks
+ chmod 0664 /dev/cpuset/background/tasks
+ chmod 0664 /dev/cpuset/tasks
# qtaguid will limit access to specific data based on group memberships.
@@ -216,7 +217,7 @@
# Mount shared so changes propagate into child namespaces
mount rootfs rootfs / shared rec
# Mount default storage into root namespace
- mount none /mnt/runtime_default /storage slave bind rec
+ mount none /mnt/runtime/default /storage slave bind rec
# We chown/chmod /cache again so because mount is run as root + defaults
chown system cache /cache
@@ -523,6 +524,7 @@
socket logd stream 0666 logd logd
socket logdr seqpacket 0666 logd logd
socket logdw dgram 0222 logd logd
+ group root system
service logd-reinit /system/bin/logd --reinit
oneshot
@@ -532,6 +534,7 @@
class core
critical
seclabel u:r:healthd:s0
+ group root system
service console /system/bin/sh
class core
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 4b8e0c0..a79e2dd 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -151,8 +151,7 @@
perm_t perm;
userid_t userid;
uid_t uid;
- gid_t gid;
- mode_t mode;
+ bool under_android;
struct node *next; /* per-dir sibling list */
struct node *child; /* first contained file by this dir */
@@ -192,22 +191,13 @@
gid_t gid;
bool multi_user;
- Hashmap* package_to_appid;
-};
-
-/* Single FUSE mount */
-struct fuse {
- struct fuse_global* global;
-
char source_path[PATH_MAX];
- char dest_path[PATH_MAX];
char obb_path[PATH_MAX];
+ Hashmap* package_to_appid;
+
__u64 next_generation;
- int fd;
struct node root;
- gid_t gid;
- mode_t mask;
/* Used to allocate unique inode numbers for fuse nodes. We use
* a simple counter based scheme where inode numbers from deleted
@@ -227,6 +217,22 @@
* Accesses must be guarded by |lock|.
*/
__u32 inode_ctr;
+
+ struct fuse* fuse_default;
+ struct fuse* fuse_read;
+ struct fuse* fuse_write;
+};
+
+/* Single FUSE mount */
+struct fuse {
+ struct fuse_global* global;
+
+ char dest_path[PATH_MAX];
+
+ int fd;
+
+ gid_t gid;
+ mode_t mask;
};
/* Private data used by a single FUSE handler */
@@ -386,8 +392,8 @@
return actual;
}
-static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node)
-{
+static void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
+ const struct stat *s, const struct node* node) {
attr->ino = node->ino;
attr->size = s->st_size;
attr->blocks = s->st_blocks;
@@ -401,12 +407,35 @@
attr->nlink = s->st_nlink;
attr->uid = node->uid;
- attr->gid = node->gid;
- /* Filter requested mode based on underlying file, and
- * pass through file type. */
+ if (fuse->gid == AID_SDCARD_RW) {
+ /* As an optimization, certain trusted system components only run
+ * as owner but operate across all users. Since we're now handing
+ * out the sdcard_rw GID only to trusted apps, we're okay relaxing
+ * the user boundary enforcement for the default view. The UIDs
+ * assigned to app directories are still multiuser aware. */
+ attr->gid = AID_SDCARD_RW;
+ } else {
+ attr->gid = multiuser_get_uid(node->userid, fuse->gid);
+ }
+
+ int visible_mode = 0775 & ~fuse->mask;
+ if (node->perm == PERM_PRE_ROOT) {
+ /* Top of multi-user view should always be visible to ensure
+ * secondary users can traverse inside. */
+ visible_mode = 0711;
+ } else if (node->under_android) {
+ /* Block "other" access to Android directories, since only apps
+ * belonging to a specific user should be in there; we still
+ * leave +x open for the default view. */
+ if (fuse->gid == AID_SDCARD_RW) {
+ visible_mode = visible_mode & ~0006;
+ } else {
+ visible_mode = visible_mode & ~0007;
+ }
+ }
int owner_mode = s->st_mode & 0700;
- int filtered_mode = node->mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
+ int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
attr->mode = (attr->mode & S_IFMT) | filtered_mode;
}
@@ -432,8 +461,7 @@
node->perm = PERM_INHERIT;
node->userid = parent->userid;
node->uid = parent->uid;
- node->gid = parent->gid;
- node->mode = parent->mode;
+ node->under_android = parent->under_android;
/* Derive custom permissions based on parent and current node */
switch (parent->perm) {
@@ -444,43 +472,28 @@
/* Legacy internal layout places users at top level */
node->perm = PERM_ROOT;
node->userid = strtoul(node->name, NULL, 10);
- if (fuse->gid == AID_SDCARD_RW) {
- /* As an optimization, certain trusted system components only run
- * as owner but operate across all users. Since we're now handing
- * out the sdcard_rw GID only to trusted apps, we're okay relaxing
- * the user boundary enforcement for the default view. The UIDs
- * assigned to app directories are still multiuser aware. */
- node->gid = fuse->gid;
- } else {
- node->gid = multiuser_get_uid(node->userid, fuse->gid);
- }
- node->mode = 0771;
break;
case PERM_ROOT:
/* Assume masked off by default. */
- node->mode = 0770;
if (!strcasecmp(node->name, "Android")) {
/* App-specific directories inside; let anyone traverse */
node->perm = PERM_ANDROID;
- node->mode = 0771;
+ node->under_android = true;
}
break;
case PERM_ANDROID:
if (!strcasecmp(node->name, "data")) {
/* App-specific directories inside; let anyone traverse */
node->perm = PERM_ANDROID_DATA;
- node->mode = 0771;
} else if (!strcasecmp(node->name, "obb")) {
/* App-specific directories inside; let anyone traverse */
node->perm = PERM_ANDROID_OBB;
- node->mode = 0771;
/* Single OBB directory is always shared */
- node->graft_path = fuse->obb_path;
- node->graft_pathlen = strlen(fuse->obb_path);
+ node->graft_path = fuse->global->obb_path;
+ node->graft_pathlen = strlen(fuse->global->obb_path);
} else if (!strcasecmp(node->name, "media")) {
/* App-specific directories inside; let anyone traverse */
node->perm = PERM_ANDROID_MEDIA;
- node->mode = 0771;
}
break;
case PERM_ANDROID_DATA:
@@ -490,11 +503,8 @@
if (appid != 0) {
node->uid = multiuser_get_uid(parent->userid, appid);
}
- node->mode = 0770;
break;
}
-
- node->mode = node->mode & ~fuse->mask;
}
/* Kernel has already enforced everything we returned through
@@ -535,7 +545,7 @@
// Detect overflows in the inode counter. "4 billion nodes should be enough
// for everybody".
- if (fuse->inode_ctr == 0) {
+ if (fuse->global->inode_ctr == 0) {
ERROR("No more inode numbers available");
return NULL;
}
@@ -561,8 +571,8 @@
}
node->namelen = namelen;
node->nid = ptr_to_id(node);
- node->ino = fuse->inode_ctr++;
- node->gen = fuse->next_generation++;
+ node->ino = fuse->global->inode_ctr++;
+ node->gen = fuse->global->next_generation++;
node->deleted = false;
@@ -616,7 +626,7 @@
static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
{
if (nid == FUSE_ROOT_ID) {
- return &fuse->root;
+ return &fuse->global->root;
} else {
return id_to_ptr(nid);
}
@@ -708,7 +718,7 @@
return -ENOMEM;
}
memset(&out, 0, sizeof(out));
- attr_from_stat(&out.attr, &s, node);
+ attr_from_stat(fuse, &out.attr, &s, node);
out.attr_valid = 10;
out.entry_valid = 10;
out.nodeid = node->nid;
@@ -728,12 +738,43 @@
return -errno;
}
memset(&out, 0, sizeof(out));
- attr_from_stat(&out.attr, &s, node);
+ attr_from_stat(fuse, &out.attr, &s, node);
out.attr_valid = 10;
fuse_reply(fuse, unique, &out, sizeof(out));
return NO_STATUS;
}
+static void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
+ const __u64 child, const char* name) {
+ struct fuse_out_header hdr;
+ struct fuse_notify_delete_out data;
+ struct iovec vec[3];
+ size_t namelen = strlen(name);
+ int res;
+
+ hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
+ hdr.error = FUSE_NOTIFY_DELETE;
+ hdr.unique = 0;
+
+ data.parent = parent;
+ data.child = child;
+ data.namelen = namelen;
+ data.padding = 0;
+
+ vec[0].iov_base = &hdr;
+ vec[0].iov_len = sizeof(hdr);
+ vec[1].iov_base = &data;
+ vec[1].iov_len = sizeof(data);
+ vec[2].iov_base = (void*) name;
+ vec[2].iov_len = namelen + 1;
+
+ res = writev(fuse->fd, vec, 3);
+ /* Ignore ENOENT, since other views may not have seen the entry */
+ if (res < 0 && errno != ENOENT) {
+ ERROR("*** NOTIFY FAILED *** %d\n", errno);
+ }
+}
+
static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
const struct fuse_in_header *hdr, const char* name)
{
@@ -931,7 +972,7 @@
}
if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
char nomedia[PATH_MAX];
- snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->obb_path);
+ snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
if (touch(nomedia, 0664) != 0) {
ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
return -ENOENT;
@@ -972,6 +1013,20 @@
child_node->deleted = true;
}
pthread_mutex_unlock(&fuse->global->lock);
+ if (parent_node && child_node) {
+ /* Tell all other views that node is gone */
+ TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
+ handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
+ if (fuse != fuse->global->fuse_default) {
+ fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
+ }
+ if (fuse != fuse->global->fuse_read) {
+ fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
+ }
+ if (fuse != fuse->global->fuse_write) {
+ fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
+ }
+ }
return 0;
}
@@ -1006,6 +1061,20 @@
child_node->deleted = true;
}
pthread_mutex_unlock(&fuse->global->lock);
+ if (parent_node && child_node) {
+ /* Tell all other views that node is gone */
+ TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
+ handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
+ if (fuse != fuse->global->fuse_default) {
+ fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
+ }
+ if (fuse != fuse->global->fuse_read) {
+ fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
+ }
+ if (fuse != fuse->global->fuse_write) {
+ fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
+ }
+ }
return 0;
}
@@ -1201,12 +1270,12 @@
pthread_mutex_lock(&fuse->global->lock);
TRACE("[%d] STATFS\n", handler->token);
- res = get_node_path_locked(&fuse->root, path, sizeof(path));
+ res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
pthread_mutex_unlock(&fuse->global->lock);
if (res < 0) {
return -ENOENT;
}
- if (statfs(fuse->root.name, &stat) < 0) {
+ if (statfs(fuse->global->root.name, &stat) < 0) {
return -errno;
}
memset(&out, 0, sizeof(out));
@@ -1664,8 +1733,9 @@
ERROR("usage: sdcard [OPTIONS] <source_path> <label>\n"
" -u: specify UID to run as\n"
" -g: specify GID to run as\n"
+ " -U: specify user ID that owns device\n"
" -m: source_path is multi-user\n"
- " -w: runtime_write mount has full write access\n"
+ " -w: runtime write mount has full write access\n"
"\n");
return 1;
}
@@ -1690,35 +1760,14 @@
return -1;
}
- fuse->next_generation = 0;
- fuse->inode_ctr = 1;
fuse->gid = gid;
fuse->mask = mask;
- memset(&fuse->root, 0, sizeof(fuse->root));
- fuse->root.nid = FUSE_ROOT_ID; /* 1 */
- fuse->root.refcount = 2;
- fuse->root.namelen = strlen(fuse->source_path);
- fuse->root.name = strdup(fuse->source_path);
- fuse->root.userid = 0;
- fuse->root.uid = AID_ROOT;
- fuse->root.gid = fuse->gid;
-
- if (fuse->global->multi_user) {
- fuse->root.perm = PERM_PRE_ROOT;
- fuse->root.mode = 0711;
- snprintf(fuse->obb_path, sizeof(fuse->obb_path), "%s/obb", fuse->source_path);
- } else {
- fuse->root.perm = PERM_ROOT;
- fuse->root.mode = 0771 & ~mask;
- snprintf(fuse->obb_path, sizeof(fuse->obb_path), "%s/Android/obb", fuse->source_path);
- }
-
return 0;
}
static void run(const char* source_path, const char* label, uid_t uid,
- gid_t gid, bool multi_user, bool full_write) {
+ gid_t gid, userid_t userid, bool multi_user, bool full_write) {
struct fuse_global global;
struct fuse fuse_default;
struct fuse fuse_read;
@@ -1743,30 +1792,69 @@
global.uid = uid;
global.gid = gid;
global.multi_user = multi_user;
+ global.next_generation = 0;
+ global.inode_ctr = 1;
+
+ memset(&global.root, 0, sizeof(global.root));
+ global.root.nid = FUSE_ROOT_ID; /* 1 */
+ global.root.refcount = 2;
+ global.root.namelen = strlen(source_path);
+ global.root.name = strdup(source_path);
+ global.root.userid = userid;
+ global.root.uid = AID_ROOT;
+ global.root.under_android = false;
+
+ strcpy(global.source_path, source_path);
+
+ if (multi_user) {
+ global.root.perm = PERM_PRE_ROOT;
+ snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
+ } else {
+ global.root.perm = PERM_ROOT;
+ snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
+ }
fuse_default.global = &global;
- strcpy(fuse_default.source_path, source_path);
- snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime_default/%s", label);
-
fuse_read.global = &global;
- strcpy(fuse_read.source_path, source_path);
- snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime_read/%s", label);
-
fuse_write.global = &global;
- strcpy(fuse_write.source_path, source_path);
- snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime_write/%s", label);
+
+ global.fuse_default = &fuse_default;
+ global.fuse_read = &fuse_read;
+ global.fuse_write = &fuse_write;
+
+ snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
+ snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
+ snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
handler_default.fuse = &fuse_default;
handler_read.fuse = &fuse_read;
handler_write.fuse = &fuse_write;
+ handler_default.token = 0;
+ handler_read.token = 1;
+ handler_write.token = 2;
+
umask(0);
- if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
- || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
- || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
- ERROR("failed to fuse_setup\n");
- exit(1);
+ if (multi_user) {
+ /* Multi-user storage is fully isolated per user, so "other"
+ * permissions are completely masked off. */
+ if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+ || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
+ || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
+ ERROR("failed to fuse_setup\n");
+ exit(1);
+ }
+ } else {
+ /* Physical storage is readable by all users on device, but
+ * the Android directories are masked off to a single user
+ * deep inside attr_from_stat(). */
+ if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+ || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
+ || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
+ ERROR("failed to fuse_setup\n");
+ exit(1);
+ }
}
/* Drop privs */
@@ -1784,9 +1872,7 @@
}
if (multi_user) {
- fs_prepare_dir(fuse_default.obb_path, 0775, uid, gid);
- fs_prepare_dir(fuse_read.obb_path, 0775, uid, gid);
- fs_prepare_dir(fuse_write.obb_path, 0775, uid, gid);
+ fs_prepare_dir(global.obb_path, 0775, uid, gid);
}
if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
@@ -1806,6 +1892,7 @@
const char *label = NULL;
uid_t uid = 0;
gid_t gid = 0;
+ userid_t userid = 0;
bool multi_user = false;
bool full_write = false;
int i;
@@ -1813,7 +1900,7 @@
int fs_version;
int opt;
- while ((opt = getopt(argc, argv, "u:g:mw")) != -1) {
+ while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
switch (opt) {
case 'u':
uid = strtoul(optarg, NULL, 10);
@@ -1821,6 +1908,9 @@
case 'g':
gid = strtoul(optarg, NULL, 10);
break;
+ case 'U':
+ userid = strtoul(optarg, NULL, 10);
+ break;
case 'm':
multi_user = true;
break;
@@ -1869,6 +1959,6 @@
sleep(1);
}
- run(source_path, label, uid, gid, multi_user, full_write);
+ run(source_path, label, uid, gid, userid, multi_user, full_write);
return 1;
}