From 4d9037d1120ac6a62a020b6f8dc4cf4b48d03f75 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Mon, 11 Dec 2017 21:06:41 -0600 Subject: [PATCH] Hard-link loop detection for VFS tar file-system Detect loops by walking hard-links at two different speeds and checking for lapping. Tar link walking is no longer a recursive procedure. Caught a loop created by GNU tar 1.29. Fix #2611 --- repos/os/src/lib/vfs/tar_file_system.h | 30 +++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/repos/os/src/lib/vfs/tar_file_system.h b/repos/os/src/lib/vfs/tar_file_system.h index b3eca3be0d..7693ff76eb 100644 --- a/repos/os/src/lib/vfs/tar_file_system.h +++ b/repos/os/src/lib/vfs/tar_file_system.h @@ -428,19 +428,33 @@ class Vfs::Tar_file_system : public File_system /** * Walk hardlinks until we reach a file - * - * XXX: check for hardlink loops */ Node const *dereference(char const *path) { Node const *node = _root_node.lookup(path); - if (!node) return 0; + Node const *slow_node = node; + int i = 0; + while (node) { + Record const *record = node->record; + if (!record || record->type() != Record::TYPE_HARDLINK) + break; /* got it */ - Record const *record = node->record; - if (!record || record->type() != Record::TYPE_HARDLINK) - return node; - - return dereference(record->linked_name()); + /* + * The `node` pointer is followed every iteration and + * `slow_node` every-other iteration. If there is a + * loop then eventually we catch it as the faster + * laps the slower. + */ + node = _root_node.lookup(record->linked_name()); + if (i++ & 1) { + slow_node = _root_node.lookup(slow_node->record->linked_name()); + if (node == slow_node) { + Genode::error(_rom_name, " contains a hard-link loop at '", path, "'"); + node = nullptr; + } + } + } + return node; } public: