summaryrefslogtreecommitdiff
path: root/trans
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-10-05 13:20:01 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-11-21 05:41:20 +0100
commitc99cb9e4ab1bd2683759f35a6878a685bf5e8dd7 (patch)
tree6b6d779c237fd373fea113239c594a0b9d09e6a2 /trans
parent36f340ae47a0f643be6d59a8190600cdd34eef0c (diff)
trans/mtab: avoid firmlink loops
* trans/mtab.c (struct mtab): Add a hash table to keep track of seen ports. (mtab_mark_as_seen): New function that records the identity port of a given node in the hash table and reports whether it has been there before. (mtab_populate): Use the new function to avoid running in circles. (main, open_hook): Initialize hash table. (close_hook): Free ports and destroy hash table.
Diffstat (limited to 'trans')
-rw-r--r--trans/mtab.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/trans/mtab.c b/trans/mtab.c
index 5207c1ea..a9928b32 100644
--- a/trans/mtab.c
+++ b/trans/mtab.c
@@ -24,6 +24,7 @@
#include <error.h>
#include <fcntl.h>
#include <hurd.h>
+#include <hurd/ihash.h>
#include <hurd/trivfs.h>
#include <inttypes.h>
#include <mntent.h>
@@ -55,6 +56,7 @@ struct mtab
char *contents;
size_t contents_len;
off_t offs;
+ struct hurd_ihash ports_seen;
};
const char *argp_program_version = STANDARD_HURD_VERSION (mtab);
@@ -244,7 +246,11 @@ main (int argc, char *argv[])
else
{
/* One-shot mode. */
- struct mtab mtab = { .lock = PTHREAD_MUTEX_INITIALIZER };
+ struct mtab mtab =
+ {
+ .lock = PTHREAD_MUTEX_INITIALIZER,
+ .ports_seen = HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP),
+ };
err = mtab_populate (&mtab, target_path, insecure);
if (err)
error (5, err, "%s", target_path);
@@ -301,6 +307,33 @@ is_filesystem_translator (file_t node)
}
}
+/* Records NODE's idport in ports_seen, returns true if we have
+ already seen this node or there was an error getting the id
+ port. */
+boolean_t
+mtab_mark_as_seen (struct mtab *mtab, mach_port_t node)
+{
+ error_t err;
+ mach_port_t idport, fsidport;
+ ino_t fileno;
+
+ err = io_identity (node, &idport, &fsidport, &fileno);
+ if (err)
+ return TRUE;
+
+ mach_port_deallocate (mach_task_self (), fsidport);
+
+ if (hurd_ihash_find (&mtab->ports_seen, idport))
+ {
+ /* Already seen. Get rid of the extra reference. */
+ mach_port_deallocate (mach_task_self (), idport);
+ return TRUE;
+ }
+
+ hurd_ihash_add (&mtab->ports_seen, idport, idport);
+ return FALSE;
+}
+
/* Populates the given MTAB object with the information for PATH. If
INSECURE is given, also follow translators bound to nodes not owned
by root or the current user. */
@@ -363,6 +396,13 @@ mtab_populate (struct mtab *mtab, const char *path, int insecure)
goto errout;
}
+ /* Avoid running in circles. */
+ if (mtab_mark_as_seen (mtab, node))
+ {
+ err = 0;
+ goto errout;
+ }
+
/* Query its options. */
err = file_get_fs_options (node, &argz, &argz_len);
if (err)
@@ -602,6 +642,7 @@ open_hook (struct trivfs_peropen *peropen)
mtab->offs = 0;
mtab->contents = NULL;
mtab->contents_len = 0;
+ hurd_ihash_init (&mtab->ports_seen, HURD_IHASH_NO_LOCP);
/* The mtab object is initialized, but not yet populated. We delay
that until that data is really needed. This avoids the following
@@ -635,6 +676,9 @@ close_hook (struct trivfs_peropen *peropen)
struct mtab *op = peropen->hook;
pthread_mutex_destroy (&op->lock);
free (op->contents);
+ HURD_IHASH_ITERATE (&op->ports_seen, p)
+ mach_port_deallocate (mach_task_self (), (mach_port_t) p);
+ hurd_ihash_destroy (&op->ports_seen);
free (op);
}