summaryrefslogtreecommitdiffstats
path: root/src/mtab.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-01-22 14:21:36 -0500
committerTavian Barnes <tavianator@tavianator.com>2023-01-22 14:21:36 -0500
commit869e4010433c8610ba59f9a6a310df8be228d718 (patch)
tree6054e9225ff8cd8e9a0276c7d2c8b0483b2fff16 /src/mtab.c
parentd2f3a10f4373610e912e586814e26e2a06fd7d88 (diff)
downloadbfs-869e4010433c8610ba59f9a6a310df8be228d718.tar.xz
mtab: Mitigate the race between bfs_mtab_parse() and bfs_mtab_fill_types()
Fixes #97.
Diffstat (limited to 'src/mtab.c')
-rw-r--r--src/mtab.c37
1 files changed, 35 insertions, 2 deletions
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;