From c99cb9e4ab1bd2683759f35a6878a685bf5e8dd7 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 5 Oct 2014 13:20:01 +0200 Subject: 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. --- trans/mtab.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'trans/mtab.c') 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 #include #include +#include #include #include #include @@ -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); } -- cgit v1.2.3