From 869e4010433c8610ba59f9a6a310df8be228d718 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 22 Jan 2023 14:21:36 -0500 Subject: mtab: Mitigate the race between bfs_mtab_parse() and bfs_mtab_fill_types() Fixes #97. --- src/mtab.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'src/mtab.c') diff --git a/src/mtab.c b/src/mtab.c index 39676e5..35ae51d 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -193,18 +193,51 @@ fail: } static void bfs_mtab_fill_types(struct bfs_mtab *mtab) { + const enum bfs_stat_flags flags = BFS_STAT_NOFOLLOW | BFS_STAT_NOSYNC; + for (size_t i = 0; i < darray_length(mtab->entries); ++i) { struct bfs_mtab_entry *entry = &mtab->entries[i]; + // It's possible that /path/to/mount was unmounted between bfs_mtab_parse() and bfs_mtab_fill_types(). + // In that case, the dev_t of /path/to/mount will be the same as /path/to, which should not get its + // fstype from the old mount record of /path/to/mount. + int fd = -1; + const char *path = entry->path; + char *dir = xdirname(path); + if (dir) { + fd = open(dir, O_SEARCH | O_CLOEXEC | O_DIRECTORY); + } + if (fd >= 0) { + path += xbaseoff(path); + } else { + fd = AT_FDCWD; + } + struct bfs_stat sb; - if (bfs_stat(AT_FDCWD, entry->path, BFS_STAT_NOFOLLOW | BFS_STAT_NOSYNC, &sb) != 0) { - continue; + if (bfs_stat(fd, path, flags, &sb) != 0) { + goto next; + } + + if (fd >= 0) { + struct bfs_stat parent; + if (bfs_stat(fd, NULL, flags, &parent) == 0) { + if (parent.dev == sb.dev) { + // Not a mount point any more (or a bind mount, but with the same fstype) + goto next; + } + } } struct trie_leaf *leaf = trie_insert_mem(&mtab->types, &sb.dev, sizeof(sb.dev)); if (leaf) { leaf->value = entry->type; } + + next: + free(dir); + if (fd >= 0) { + xclose(fd); + } } mtab->types_filled = true; -- cgit v1.2.3