From 7dc3e45b3a2a0946182159121d2d3b7d7b938697 Mon Sep 17 00:00:00 2001 From: Matthew Leeds Date: Thu, 14 Jun 2018 14:33:10 -0700 Subject: [PATCH] lib/prune: Don't modify dirent->d_name in place Currently when I run `ostree prune` it hits a seg fault when the hash_func is used (in this case g_str_hash) from the call stack _ostree_repo_prune_tmp() -> g_hash_table_contains() -> g_hash_table_lookup_node(). So the key, in this case dent->d_name, must be corrupt in some way. glnx_dirfd_iterator_next_dent() uses readdir() to get the dirent struct. And according to the man page for readdir(3), "POSIX.1 explicitly notes that this field should not be used as an lvalue" (in reference to d_name). So this commit avoids modifying d_name in place and copies it instead. This seems to avoid the seg fault. Closes: #1627 Approved by: jlebon --- src/libostree/ostree-repo-prune.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libostree/ostree-repo-prune.c b/src/libostree/ostree-repo-prune.c index b93d35ac..7ab9dc8d 100644 --- a/src/libostree/ostree-repo-prune.c +++ b/src/libostree/ostree-repo-prune.c @@ -153,26 +153,29 @@ _ostree_repo_prune_tmp (OstreeRepo *self, size_t len; gboolean has_sig_suffix = FALSE; struct dirent *dent; + g_autofree gchar *d_name = NULL; if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) return FALSE; if (dent == NULL) break; - len = strlen (dent->d_name); - if (len > 4 && g_strcmp0 (dent->d_name + len - 4, ".sig") == 0) + /* dirent->d_name can't be modified directly; see `man 3 readdir` */ + d_name = g_strdup (dent->d_name); + len = strlen (d_name); + if (len > 4 && g_strcmp0 (d_name + len - 4, ".sig") == 0) { has_sig_suffix = TRUE; - dent->d_name[len - 4] = '\0'; + d_name[len - 4] = '\0'; } - if (!g_hash_table_contains (self->remotes, dent->d_name)) + if (!g_hash_table_contains (self->remotes, d_name)) { /* Restore the previous value to get the file name. */ if (has_sig_suffix) - dent->d_name[len - 4] = '.'; + d_name[len - 4] = '.'; - if (!glnx_unlinkat (dfd_iter.fd, dent->d_name, 0, error)) + if (!glnx_unlinkat (dfd_iter.fd, d_name, 0, error)) return FALSE; } }