diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index f8e5e7b697..0ebe4bb7d2 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -1219,13 +1219,14 @@ static bool valid_chars(const char *node) "0123456789-/_@") == strlen(node)); } -bool is_valid_nodename(const struct connection *conn, const char *node) +bool is_valid_nodename(const struct connection *conn, const char *node, + bool allow_special) { int local_off = 0; unsigned int domid; - /* Must start in /. */ - if (!strstarts(node, "/")) + /* Must start in / or - if special nodes are allowed - in @. */ + if (!strstarts(node, "/") && (!allow_special || !strstarts(node, "@"))) return false; /* Cannot end in / (unless it's just "/"). */ @@ -1293,7 +1294,8 @@ static struct node *get_node_canonicalized(struct connection *conn, const void *ctx, const char *name, const char **canonical_name, - unsigned int perm) + unsigned int perm, + bool allow_special) { const char *tmp_name; @@ -1302,33 +1304,20 @@ static struct node *get_node_canonicalized(struct connection *conn, *canonical_name = canonicalize(conn, ctx, name); if (!*canonical_name) return NULL; - if (!is_valid_nodename(conn, *canonical_name)) { + if (!is_valid_nodename(conn, *canonical_name, allow_special)) { errno = EINVAL; return NULL; } return get_node(conn, ctx, *canonical_name, perm); } -static struct node *get_spec_node(struct connection *conn, const void *ctx, - const char *name, const char **canonical_name, - unsigned int perm) -{ - if (name[0] == '@') { - if (canonical_name) - *canonical_name = name; - return get_node(conn, ctx, name, perm); - } - - return get_node_canonicalized(conn, ctx, name, canonical_name, perm); -} - static int send_directory(const void *ctx, struct connection *conn, struct buffered_data *in) { struct node *node; node = get_node_canonicalized(conn, ctx, onearg(in), NULL, - XS_PERM_READ); + XS_PERM_READ, false); if (!node) return errno; @@ -1350,7 +1339,7 @@ static int send_directory_part(const void *ctx, struct connection *conn, /* First arg is node name. */ node = get_node_canonicalized(conn, ctx, in->buffer, NULL, - XS_PERM_READ); + XS_PERM_READ, false); if (!node) return errno; @@ -1400,7 +1389,7 @@ static int do_read(const void *ctx, struct connection *conn, struct node *node; node = get_node_canonicalized(conn, ctx, onearg(in), NULL, - XS_PERM_READ); + XS_PERM_READ, false); if (!node) return errno; @@ -1614,7 +1603,8 @@ static int do_write(const void *ctx, struct connection *conn, offset = strlen(vec[0]) + 1; datalen = in->used - offset; - node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE); + node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE, + false); if (!node) { /* No permissions, invalid input? */ if (errno != ENOENT) @@ -1643,7 +1633,7 @@ static int do_mkdir(const void *ctx, struct connection *conn, const char *name; node = get_node_canonicalized(conn, ctx, onearg(in), &name, - XS_PERM_WRITE); + XS_PERM_WRITE, false); /* If it already exists, fine. */ if (!node) { @@ -1773,7 +1763,7 @@ static int do_rm(const void *ctx, struct connection *conn, char *parentname; node = get_node_canonicalized(conn, ctx, onearg(in), &name, - XS_PERM_WRITE); + XS_PERM_WRITE, false); if (!node) { /* Didn't exist already? Fine, if parent exists. */ if (errno == ENOENT) { @@ -1814,7 +1804,8 @@ static int do_get_perms(const void *ctx, struct connection *conn, char *strings; unsigned int len; - node = get_spec_node(conn, ctx, onearg(in), NULL, XS_PERM_READ); + node = get_node_canonicalized(conn, ctx, onearg(in), NULL, XS_PERM_READ, + true); if (!node) return errno; @@ -1857,8 +1848,8 @@ static int do_set_perms(const void *ctx, struct connection *conn, return ENOENT; /* We must own node to do this (tools can do this too). */ - node = get_spec_node(conn, ctx, in->buffer, &name, - XS_PERM_WRITE | XS_PERM_OWNER); + node = get_node_canonicalized(conn, ctx, in->buffer, &name, + XS_PERM_WRITE | XS_PERM_OWNER, true); if (!node) return errno; diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index 07c59c07b7..5575cc0689 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -305,7 +305,8 @@ void check_store(void); void corrupt(struct connection *conn, const char *fmt, ...); /* Is this a valid node name? */ -bool is_valid_nodename(const struct connection *conn, const char *node); +bool is_valid_nodename(const struct connection *conn, const char *node, + bool allow_special); /* Get name of parent node. */ char *get_parent(const void *ctx, const char *node); diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c index d6e5a4be1e..e695762c64 100644 --- a/tools/xenstore/xenstored_watch.c +++ b/tools/xenstore/xenstored_watch.c @@ -163,19 +163,12 @@ static int destroy_watch(void *_watch) static int check_watch_path(struct connection *conn, const void *ctx, const char **path, bool *relative) { - /* Check if valid event. */ - if (strstarts(*path, "@")) { - *relative = false; - if (strlen(*path) > XENSTORE_REL_PATH_MAX) - goto inval; - } else { - *relative = !strstarts(*path, "/"); - *path = canonicalize(conn, ctx, *path); - if (!*path) - return errno; - if (!is_valid_nodename(conn, *path)) - goto inval; - } + *relative = !strstarts(*path, "/") && !strstarts(*path, "@"); + *path = canonicalize(conn, ctx, *path); + if (!*path) + return errno; + if (!is_valid_nodename(conn, *path, true)) + goto inval; return 0;