diff options
author | Chris Dunlap <[email protected]> | 2014-10-19 12:05:07 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2015-01-30 14:46:17 -0800 |
commit | 854f30a91fc6a2accc6bf49cb7fcc52b498fda2a (patch) | |
tree | 6aa05457e95928a24ce390d445a2c14997f92073 /cmd/zed/zed_strings.c | |
parent | 0365064a9726f6bb6e148611a6e42fa80302d083 (diff) |
Protect against adding duplicate strings in ZED
The zed_strings container stores strings in an AVL, but does not
check for duplicate strings being added. Within the AVL, strings
are indexed by the string value itself. avl_add() requires the node
being added must not already exist in the tree, and will assert()
if this is not the case.
This should not cause problems in practice. ZED uses this container
in two places. In zed_conf.c, it is used to store the names of
enabled zedlets as zed scans the zedlet directory listing; duplicate
entries cannot occur here since duplicate names cannot occur within
a directory. In zed_event.c, it is used to store the environment
variables (as "NAME=VALUE" strings) that will be passed to zedlets;
duplicate strings here should never happen unless there is a bug
resulting in a duplicate nvpair or environment variable.
This commit protects against adding a duplicate to a zed_strings
container by first checking for the string being added, and removing
the previous entry should one exist. This implements a "last one
wins" policy.
This commit also changes the prototype for zed_strings_add() to allow
the string key (by which it is indexed in the AVL) to differ from
the string value. By adding zedlet environment variables using the
variable name as the key, multiple adds for the same variable name
will result in only the last value being stored.
Finally, this commit routes all additions of zedlet environment
variables through the updated _zed_event_add_var(). This ensures
all zedlet environment variable names are properly converted.
Signed-off-by: Chris Dunlap <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #3042
Diffstat (limited to 'cmd/zed/zed_strings.c')
-rw-r--r-- | cmd/zed/zed_strings.c | 99 |
1 files changed, 80 insertions, 19 deletions
diff --git a/cmd/zed/zed_strings.c b/cmd/zed/zed_strings.c index 8e0f58079..01736e388 100644 --- a/cmd/zed/zed_strings.c +++ b/cmd/zed/zed_strings.c @@ -40,7 +40,8 @@ struct zed_strings { struct zed_strings_node { avl_node_t node; - char string[]; + char *key; + char *val; }; typedef struct zed_strings_node zed_strings_node_t; @@ -59,9 +60,9 @@ _zed_strings_node_compare(const void *x1, const void *x2) assert(x1 != NULL); assert(x2 != NULL); - s1 = ((const zed_strings_node_t *) x1)->string; + s1 = ((const zed_strings_node_t *) x1)->key; assert(s1 != NULL); - s2 = ((const zed_strings_node_t *) x2)->string; + s2 = ((const zed_strings_node_t *) x2)->key; assert(s2 != NULL); rv = strcmp(s1, s2); @@ -94,7 +95,62 @@ zed_strings_create(void) } /* - * Destroy the string container [zsp] and all strings within. + * Destroy the string node [np]. + */ +static void +_zed_strings_node_destroy(zed_strings_node_t *np) +{ + if (!np) + return; + + if (np->key) { + if (np->key != np->val) + free(np->key); + np->key = NULL; + } + if (np->val) { + free(np->val); + np->val = NULL; + } + free(np); +} + +/* + * Return a new string node for storing the string [val], or NULL on error. + * If [key] is specified, it will be used to index the node; otherwise, + * the string [val] will be used. + */ +zed_strings_node_t * +_zed_strings_node_create(const char *key, const char *val) +{ + zed_strings_node_t *np; + + assert(val != NULL); + + np = calloc(1, sizeof (*np)); + if (!np) + return (NULL); + + np->val = strdup(val); + if (!np->val) + goto nomem; + + if (key) { + np->key = strdup(key); + if (!np->key) + goto nomem; + } else { + np->key = np->val; + } + return (np); + +nomem: + _zed_strings_node_destroy(np); + return (NULL); +} + +/* + * Destroy the string container [zsp] and all nodes within. */ void zed_strings_destroy(zed_strings_t *zsp) @@ -107,36 +163,41 @@ zed_strings_destroy(zed_strings_t *zsp) cookie = NULL; while ((np = avl_destroy_nodes(&zsp->tree, &cookie))) - free(np); + _zed_strings_node_destroy(np); avl_destroy(&zsp->tree); free(zsp); } /* - * Add a copy of the string [s] to the container [zsp]. + * Add a copy of the string [s] indexed by [key] to the container [zsp]. + * If [key] already exists within the container [zsp], it will be replaced + * with the new string [s]. + * If [key] is NULL, the string [s] will be used as the key. * Return 0 on success, or -1 on error. - * - * FIXME: Handle dup strings. */ int -zed_strings_add(zed_strings_t *zsp, const char *s) +zed_strings_add(zed_strings_t *zsp, const char *key, const char *s) { - size_t len; - zed_strings_node_t *np; + zed_strings_node_t *newp, *oldp; if (!zsp || !s) { errno = EINVAL; return (-1); } - len = sizeof (zed_strings_node_t) + strlen(s) + 1; - np = calloc(1, len); - if (!np) + if (key == s) + key = NULL; + + newp = _zed_strings_node_create(key, s); + if (!newp) return (-1); - assert((char *) np->string + strlen(s) < (char *) np + len); - (void) strcpy(np->string, s); - avl_add(&zsp->tree, np); + oldp = avl_find(&zsp->tree, newp, NULL); + if (oldp) { + avl_remove(&zsp->tree, oldp); + _zed_strings_node_destroy(oldp); + } + avl_add(&zsp->tree, newp); return (0); } @@ -157,7 +218,7 @@ zed_strings_first(zed_strings_t *zsp) if (!zsp->iteratorp) return (NULL); - return (((zed_strings_node_t *) zsp->iteratorp)->string); + return (((zed_strings_node_t *) zsp->iteratorp)->val); } @@ -181,7 +242,7 @@ zed_strings_next(zed_strings_t *zsp) if (!zsp->iteratorp) return (NULL); - return (((zed_strings_node_t *)zsp->iteratorp)->string); + return (((zed_strings_node_t *)zsp->iteratorp)->val); } /* |