| By default qemu builds a complete list of directories within the user |
| emulation sysroot (-L option). The OE sysroot directory is large and |
| this is confusing, for example it indexes all pkgdata. In particular this |
| confuses strace of qemu binaries with tons of irrelevant paths. |
| |
| This patch stops the code indexing up front and instead only indexes |
| things if/as/when it needs to. This drastically reduces the files it |
| reads and reduces memory usage and cleans up strace. |
| |
| It would also avoid the infinite directory traversal bug in [YOCTO #6996] |
| although the code could still be vulnerable if it parsed those specific |
| paths. |
| |
| RP |
| 2016/3/9 |
| Upstream-Status: Pending |
| |
| Index: qemu-2.5.0/util/path.c |
| =================================================================== |
| --- qemu-2.5.0.orig/util/path.c |
| +++ qemu-2.5.0/util/path.c |
| @@ -19,6 +19,7 @@ struct pathelem |
| char *name; |
| /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ |
| char *pathname; |
| + int populated_entries; |
| struct pathelem *parent; |
| /* Children */ |
| unsigned int num_entries; |
| @@ -49,6 +50,7 @@ static struct pathelem *new_entry(const |
| new->name = g_strdup(name); |
| new->pathname = g_strdup_printf("%s/%s", root, name); |
| new->num_entries = 0; |
| + new->populated_entries = 0; |
| return new; |
| } |
| |
| @@ -57,15 +59,16 @@ static struct pathelem *new_entry(const |
| /* Not all systems provide this feature */ |
| #if defined(DT_DIR) && defined(DT_UNKNOWN) && defined(DT_LNK) |
| # define dirent_type(dirent) ((dirent)->d_type) |
| -# define is_dir_maybe(type) \ |
| - ((type) == DT_DIR || (type) == DT_UNKNOWN || (type) == DT_LNK) |
| +# define is_not_dir(type) \ |
| + ((type) != DT_DIR && (type) != DT_UNKNOWN && (type) != DT_LNK) |
| #else |
| # define dirent_type(dirent) (1) |
| -# define is_dir_maybe(type) (type) |
| +# define is_not_dir(type) (0) |
| #endif |
| |
| static struct pathelem *add_dir_maybe(struct pathelem *path) |
| { |
| + unsigned int i; |
| DIR *dir; |
| |
| if ((dir = opendir(path->pathname)) != NULL) { |
| @@ -78,6 +81,11 @@ static struct pathelem *add_dir_maybe(st |
| } |
| closedir(dir); |
| } |
| + |
| + for (i = 0; i < path->num_entries; i++) |
| + (path->entries[i])->parent = path; |
| + |
| + path->populated_entries = 1; |
| return path; |
| } |
| |
| @@ -93,26 +101,16 @@ static struct pathelem *add_entry(struct |
| e = &root->entries[root->num_entries-1]; |
| |
| *e = new_entry(root->pathname, root, name); |
| - if (is_dir_maybe(type)) { |
| - *e = add_dir_maybe(*e); |
| + if (is_not_dir(type)) { |
| + (*e)->populated_entries = 1; |
| } |
| |
| return root; |
| } |
| |
| -/* This needs to be done after tree is stabilized (ie. no more reallocs!). */ |
| -static void set_parents(struct pathelem *child, struct pathelem *parent) |
| -{ |
| - unsigned int i; |
| - |
| - child->parent = parent; |
| - for (i = 0; i < child->num_entries; i++) |
| - set_parents(child->entries[i], child); |
| -} |
| - |
| /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ |
| static const char * |
| -follow_path(const struct pathelem *cursor, const char *name) |
| +follow_path(struct pathelem *cursor, struct pathelem **source, const char *name) |
| { |
| unsigned int i, namelen; |
| |
| @@ -123,14 +121,18 @@ follow_path(const struct pathelem *curso |
| return cursor->pathname; |
| |
| if (strneq(name, namelen, "..")) |
| - return follow_path(cursor->parent, name + namelen); |
| + return follow_path(cursor->parent, &cursor->parent, name + namelen); |
| |
| if (strneq(name, namelen, ".")) |
| - return follow_path(cursor, name + namelen); |
| + return follow_path(cursor, source, name + namelen); |
| + |
| + if (!cursor->populated_entries) |
| + *source = add_dir_maybe(cursor); |
| + cursor = *source; |
| |
| for (i = 0; i < cursor->num_entries; i++) |
| if (strneq(name, namelen, cursor->entries[i]->name)) |
| - return follow_path(cursor->entries[i], name + namelen); |
| + return follow_path(cursor->entries[i], &cursor->entries[i], name + namelen); |
| |
| /* Not found */ |
| return NULL; |
| @@ -164,8 +166,6 @@ void init_paths(const char *prefix) |
| g_free(base->name); |
| g_free(base); |
| base = NULL; |
| - } else { |
| - set_parents(base, base); |
| } |
| } |
| |
| @@ -177,5 +177,5 @@ const char *path(const char *name) |
| if (!base || !name || name[0] != '/') |
| return name; |
| |
| - return follow_path(base, name) ?: name; |
| + return follow_path(base, &base, name) ?: name; |
| } |