Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9729b415 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android Git Automerger
Browse files

am 44d6342c: Remove mkdir() side effect, add .nomedia, utils.

* commit '44d6342c':
  Remove mkdir() side effect, add .nomedia, utils.
parents 4d5d633b 44d6342c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -55,6 +55,14 @@ extern int fs_read_atomic_int(const char* path, int* value);
 */
extern int fs_write_atomic_int(const char* path, int value);

/*
 * Ensure that all directories along given path exist, creating parent
 * directories as needed.  Validates that given path is absolute and that
 * it contains no relative "." or ".." paths or symlinks.  Last path segment
 * is treated as filename and ignored, unless the path ends with "/".
 */
extern int fs_mkdirs(const char* path, mode_t mode);

#ifdef __cplusplus
}
#endif
+90 −0
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@

#define LOG_TAG "cutils"

/* These defines are only needed because prebuilt headers are out of date */
#define __USE_XOPEN2K8 1
#define _ATFILE_SOURCE 1
#define _GNU_SOURCE 1

#include <cutils/fs.h>
#include <cutils/log.h>

@@ -27,6 +32,7 @@
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <dirent.h>

#define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
#define BUF_SIZE 64
@@ -141,3 +147,87 @@ fail_closed:
    unlink(temp);
    return -1;
}

int fs_mkdirs(const char* path, mode_t mode) {
    int res = 0;
    int fd = 0;
    struct stat sb;
    char* buf = strdup(path);

    if (*buf != '/') {
        ALOGE("Relative paths are not allowed: %s", buf);
        res = -EINVAL;
        goto done;
    }

    if ((fd = open("/", 0)) == -1) {
        ALOGE("Failed to open(/): %s", strerror(errno));
        res = -errno;
        goto done;
    }

    char* segment = buf + 1;
    char* p = segment;
    while (*p != '\0') {
        if (*p == '/') {
            *p = '\0';

            if (!strcmp(segment, "..") || !strcmp(segment, ".") || !strcmp(segment, "")) {
                ALOGE("Invalid path: %s", buf);
                res = -EINVAL;
                goto done_close;
            }

            if (fstatat(fd, segment, &sb, AT_SYMLINK_NOFOLLOW) != 0) {
                if (errno == ENOENT) {
                    /* Nothing there yet; let's create it! */
                    if (mkdirat(fd, segment, mode) != 0) {
                        if (errno == EEXIST) {
                            /* We raced with someone; ignore */
                        } else {
                            ALOGE("Failed to mkdirat(%s): %s", buf, strerror(errno));
                            res = -errno;
                            goto done_close;
                        }
                    }
                } else {
                    ALOGE("Failed to fstatat(%s): %s", buf, strerror(errno));
                    res = -errno;
                    goto done_close;
                }
            } else {
                if (S_ISLNK(sb.st_mode)) {
                    ALOGE("Symbolic links are not allowed: %s", buf);
                    res = -ELOOP;
                    goto done_close;
                }
                if (!S_ISDIR(sb.st_mode)) {
                    ALOGE("Existing segment not a directory: %s", buf);
                    res = -ENOTDIR;
                    goto done_close;
                }
            }

            /* Yay, segment is ready for us to step into */
            int next_fd;
            if ((next_fd = openat(fd, segment, 0)) == -1) {
                ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
                res = -errno;
                goto done_close;
            }

            close(fd);
            fd = next_fd;

            *p = '/';
            segment = p + 1;
        }
        p++;
    }

done_close:
    close(fd);
done:
    free(buf);
    return res;
}
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ loglevel 3

    # See storage config details at http://source.android.com/tech/storage/
    mkdir /mnt/shell 0700 shell shell
    mkdir /storage 0050 root sdcard_r
    mkdir /storage 0751 root sdcard_r

    # Directory for putting things only root should see.
    mkdir /mnt/secure 0700 root root
+59 −51
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <sys/resource.h>
#include <sys/inotify.h>

#include <cutils/fs.h>
#include <cutils/hashmap.h>
#include <cutils/multiuser.h>

@@ -193,8 +194,9 @@ static int str_hash(void *key) {
    return hashmapHash(key, strlen(key));
}

static bool str_equals(void *keyA, void *keyB) {
    return strcmp(keyA, keyB) == 0;
/** Test if two string keys are equal ignoring case */
static bool str_icase_equals(void *keyA, void *keyB) {
    return strcasecmp(keyA, keyB) == 0;
}

static int int_hash(void *key) {
@@ -401,6 +403,20 @@ static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const s
    attr->mode = (attr->mode & S_IFMT) | filtered_mode;
}

static int touch(char* path, mode_t mode) {
    int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
    if (fd == -1) {
        if (errno == EEXIST) {
            return 0;
        } else {
            ERROR("Failed to open(%s): %s\n", path, strerror(errno));
            return -1;
        }
    }
    close(fd);
    return 0;
}

static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
        struct node *node) {
    appid_t appid;
@@ -429,37 +445,37 @@ static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
    case PERM_ROOT:
        /* Assume masked off by default. */
        node->mode = 0770;
        if (!strcmp(node->name, "Android")) {
        if (!strcasecmp(node->name, "Android")) {
            /* App-specific directories inside; let anyone traverse */
            node->perm = PERM_ANDROID;
            node->mode = 0771;
        } else if (fuse->split_perms) {
            if (!strcmp(node->name, "DCIM")
                    || !strcmp(node->name, "Pictures")) {
            if (!strcasecmp(node->name, "DCIM")
                    || !strcasecmp(node->name, "Pictures")) {
                node->gid = AID_SDCARD_PICS;
            } else if (!strcmp(node->name, "Alarms")
                    || !strcmp(node->name, "Movies")
                    || !strcmp(node->name, "Music")
                    || !strcmp(node->name, "Notifications")
                    || !strcmp(node->name, "Podcasts")
                    || !strcmp(node->name, "Ringtones")) {
            } else if (!strcasecmp(node->name, "Alarms")
                    || !strcasecmp(node->name, "Movies")
                    || !strcasecmp(node->name, "Music")
                    || !strcasecmp(node->name, "Notifications")
                    || !strcasecmp(node->name, "Podcasts")
                    || !strcasecmp(node->name, "Ringtones")) {
                node->gid = AID_SDCARD_AV;
            }
        }
        break;
    case PERM_ANDROID:
        if (!strcmp(node->name, "data")) {
        if (!strcasecmp(node->name, "data")) {
            /* App-specific directories inside; let anyone traverse */
            node->perm = PERM_ANDROID_DATA;
            node->mode = 0771;
        } else if (!strcmp(node->name, "obb")) {
        } 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->obbpath;
            node->graft_pathlen = strlen(fuse->obbpath);
        } else if (!strcmp(node->name, "user")) {
        } else if (!strcasecmp(node->name, "user")) {
            /* User directories must only be accessible to system, protected
             * by sdcard_all. Zygote will bind mount the appropriate user-
             * specific path. */
@@ -505,9 +521,9 @@ static bool check_caller_access_to_name(struct fuse* fuse,
        const char* name, int mode, bool has_rw) {
    /* Always block security-sensitive files at root */
    if (parent_node && parent_node->perm == PERM_ROOT) {
        if (!strcmp(name, "autorun.inf")
                || !strcmp(name, ".android_secure")
                || !strcmp(name, "android_secure")) {
        if (!strcasecmp(name, "autorun.inf")
                || !strcasecmp(name, ".android_secure")
                || !strcasecmp(name, "android_secure")) {
            return false;
        }
    }
@@ -517,8 +533,9 @@ static bool check_caller_access_to_name(struct fuse* fuse,
        return true;
    }

    /* Root or shell always have access */
    if (hdr->uid == 0 || hdr->uid == AID_SHELL) {
    /* Root always has access; access for any other UIDs should always
     * be controlled through packages.list. */
    if (hdr->uid == 0) {
        return true;
    }

@@ -696,9 +713,10 @@ static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
        fuse->root.perm = PERM_LEGACY_PRE_ROOT;
        fuse->root.mode = 0771;
        fuse->root.gid = fs_gid;
        fuse->package_to_appid = hashmapCreate(256, str_hash, str_equals);
        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
        snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path);
        fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid());
        break;
    case DERIVE_UNIFIED:
        /* Unified multiuser layout which places secondary user_id under
@@ -706,7 +724,7 @@ static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
        fuse->root.perm = PERM_ROOT;
        fuse->root.mode = 0771;
        fuse->root.gid = fs_gid;
        fuse->package_to_appid = hashmapCreate(256, str_hash, str_equals);
        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
        snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path);
        break;
@@ -752,37 +770,8 @@ static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
    struct stat s;

    if (lstat(path, &s) < 0) {
        /* But wait! We'll automatically create a directory if its
         * a valid package name under data or obb, since apps may not
         * have enough permissions to create for themselves. */
        if (errno == ENOENT && (parent->perm == PERM_ANDROID_DATA
                || parent->perm == PERM_ANDROID_OBB)) {
            TRACE("automatically creating %s\n", path);

            pthread_mutex_lock(&fuse->lock);
            bool validPackage = hashmapContainsKey(fuse->package_to_appid, (char*) name);
            pthread_mutex_unlock(&fuse->lock);

            if (!validPackage) {
                return -ENOENT;
            }
            if (mkdir(path, 0775) == -1) {
                /* We might have raced with ourselves and already created */
                if (errno != EEXIST) {
                    ERROR("failed to mkdir(%s): %s\n", name, strerror(errno));
                    return -ENOENT;
                }
            }

            /* It should exist this time around! */
            if (lstat(path, &s) < 0) {
                ERROR("failed to lstat(%s): %s\n", name, strerror(errno));
        return -errno;
    }
        } else {
            return -errno;
        }
    }

    pthread_mutex_lock(&fuse->lock);
    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
@@ -1006,6 +995,25 @@ static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
    if (mkdir(child_path, mode) < 0) {
        return -errno;
    }

    /* When creating /Android/data and /Android/obb, mark them as .nomedia */
    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
        char nomedia[PATH_MAX];
        snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
        if (touch(nomedia, 0664) != 0) {
            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
            return -ENOENT;
        }
    }
    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
        char nomedia[PATH_MAX];
        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->obbpath);
        if (touch(nomedia, 0664) != 0) {
            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
            return -ENOENT;
        }
    }

    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
}