From 6999d0a3f9d5ad824c076a04182e778dfffeece9 Mon Sep 17 00:00:00 2001 From: Masamichi Takagi Date: Tue, 24 Jul 2018 09:43:17 +0900 Subject: [PATCH] bind_mount_recursive: Use lstat instead of d_type of readdir Change-Id: I0eb8d6c7e1fa5df6dbc5962a639901546a159d04 --- executer/user/mcexec.c | 60 +++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/executer/user/mcexec.c b/executer/user/mcexec.c index edd000ed..a12cf313 100644 --- a/executer/user/mcexec.c +++ b/executer/user/mcexec.c @@ -1782,51 +1782,75 @@ static struct option mcexec_options[] = { }; #ifdef ENABLE_MCOVERLAYFS +/* bind-mount files under / over recursively */ void bind_mount_recursive(const char *root, char *prefix) { DIR *dir; struct dirent *entry; char path[PATH_MAX]; - int len; - len = snprintf(path, sizeof(path) - 1, "%s/%s", root, prefix); - path[len] = 0; + snprintf(path, sizeof(path), "%s/%s", root, prefix); + path[sizeof(path) - 1] = 0; if (!(dir = opendir(path))) { return; } while ((entry = readdir(dir))) { - len = snprintf(path, sizeof(path) - 1, - "%s/%s", prefix, entry->d_name); - path[len] = 0; + char fullpath[PATH_MAX]; + char shortpath[PATH_MAX]; + struct stat st; + + /* Use lstat instead of checking dt_type of readdir + result because the latter reports DT_UNKNOWN for + files on some file systems */ + snprintf(fullpath, sizeof(fullpath), + "%s/%s/%s", root, prefix, entry->d_name); + fullpath[sizeof(fullpath) - 1] = 0; + + if (lstat(fullpath, &st)) { + fprintf(stderr, "%s: error: lstat %s: %s\n", + __func__, fullpath, strerror(errno)); + continue; + } + + /* Traverse target or mount point */ + snprintf(shortpath, sizeof(shortpath), + "%s/%s", prefix, entry->d_name); + shortpath[sizeof(shortpath) - 1] = 0; + + if (S_ISDIR(st.st_mode)) { + __dprintf("dir found: %s\n", fullpath); - if (entry->d_type == DT_DIR) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; - bind_mount_recursive(root, path); + bind_mount_recursive(root, shortpath); } - else if (entry->d_type == DT_REG) { + else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { int ret; struct sys_mount_desc mount_desc; - memset(&mount_desc, '\0', sizeof mount_desc); - char bind_path[PATH_MAX]; - len = snprintf(bind_path, sizeof(bind_path) - 1, - "%s/%s/%s", root, prefix, entry->d_name); - bind_path[len] = 0; + __dprintf("reg/symlink found: %s\n", fullpath); - mount_desc.dev_name = bind_path; - mount_desc.dir_name = path; + if (lstat(shortpath, &st)) { + fprintf(stderr, "%s: warning: lstat of mount point (%s) failed: %s\n", + __func__, shortpath, strerror(errno)); + continue; + } + + memset(&mount_desc, '\0', sizeof(mount_desc)); + mount_desc.dev_name = fullpath; + mount_desc.dir_name = shortpath; mount_desc.type = NULL; mount_desc.flags = MS_BIND | MS_PRIVATE; mount_desc.data = NULL; + if ((ret = ioctl(fd, MCEXEC_UP_SYS_MOUNT, (unsigned long)&mount_desc)) != 0) { - fprintf(stderr, "WARNING: failed to bind mount %s over %s: %d\n", - bind_path, path, ret); + fprintf(stderr, "%s: warning: failed to bind mount %s over %s: %d\n", + __func__, fullpath, shortpath, ret); } } }