Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP1:GA
xen.10697
xs-19-handle-alloc-failures.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File xs-19-handle-alloc-failures.patch of Package xen.10697
commit d2e41f6dc3bb4e040d5f72cc360b7c623bfed59a Author: Juergen Gross <jgross@suse.com> Date: Mon Dec 5 08:48:53 2016 +0100 xenstore: handle memory allocation failures in xenstored Check for failures when allocating new memory in xenstored. Signed-off-by: Juergen Gross <jgross@suse.com> Acked-by: Wei Liu <wei.liu2@citrix.com> --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -139,8 +139,10 @@ void trace(const char *fmt, ...) va_start(arglist, fmt); str = talloc_vasprintf(NULL, fmt, arglist); va_end(arglist); - dummy = write(tracefd, str, strlen(str)); - talloc_free(str); + if (str) { + dummy = write(tracefd, str, strlen(str)); + talloc_free(str); + } } static void trace_io(const struct connection *conn, @@ -387,7 +389,16 @@ static struct node *read_node(struct con } node = talloc(ctx, struct node); + if (!node) { + errno = ENOMEM; + return NULL; + } node->name = talloc_strdup(node, name); + if (!node->name) { + talloc_free(node); + errno = ENOMEM; + return NULL; + } node->parent = NULL; node->tdb = tdb_context(conn); talloc_steal(node, data.dptr); @@ -485,35 +496,46 @@ static enum xs_perm_type perm_for_conn(s */ static char *get_parent(const void *ctx, const char *node) { + char *parent; char *slash = strrchr(node + 1, '/'); - if (!slash) - return talloc_strdup(ctx, "/"); - return talloc_asprintf(ctx, "%.*s", (int)(slash - node), node); + + parent = slash ? talloc_asprintf(ctx, "%.*s", (int)(slash - node), node) + : talloc_strdup(ctx, "/"); + if (!parent) + errno = ENOMEM; + + return parent; } /* * What do parents say? * Temporary memory allocations are done with ctx. */ -static enum xs_perm_type ask_parents(struct connection *conn, const void *ctx, - const char *name) +static int ask_parents(struct connection *conn, const void *ctx, + const char *name, enum xs_perm_type *perm) { struct node *node; do { name = get_parent(ctx, name); + if (!name) + return errno; node = read_node(conn, ctx, name); if (node) break; + if (errno == ENOMEM) + return errno; } while (!streq(name, "/")); /* No permission at root? We're in trouble. */ if (!node) { corrupt(conn, "No permissions file at root"); - return XS_PERM_NONE; + *perm = XS_PERM_NONE; + return 0; } - return perm_for_conn(conn, node->perms, node->num_perms); + *perm = perm_for_conn(conn, node->perms, node->num_perms); + return 0; } /* @@ -527,11 +549,15 @@ static int errno_from_parents(struct con const char *node, int errnum, enum xs_perm_type perm) { + enum xs_perm_type parent_perm = XS_PERM_NONE; + /* We always tell them about memory failures. */ if (errnum == ENOMEM) return errnum; - if (ask_parents(conn, ctx, node) & perm) + if (ask_parents(conn, ctx, node, &parent_perm)) + return errno; + if (parent_perm & perm) return errnum; return EACCES; } @@ -561,7 +587,7 @@ struct node *get_node(struct connection } } /* Clean up errno if they weren't supposed to know. */ - if (!node) + if (!node && errno != ENOMEM) errno = errno_from_parents(conn, ctx, name, errno, perm); return node; } @@ -651,11 +677,29 @@ void send_reply(struct connection *conn, } else { /* Message is a child of the connection for auto-cleanup. */ bdata = new_buffer(conn); + + /* + * Allocation failure here is unfortunate: we have no way to + * tell anybody about it. + */ + if (!bdata) + return; } if (len <= DEFAULT_BUFFER_SIZE) bdata->buffer = bdata->default_buffer; else bdata->buffer = talloc_array(bdata, char, len); + if (!bdata->buffer) { + if (type == XS_WATCH_EVENT) { + /* Same as above: no way to tell someone. */ + talloc_free(bdata); + return; + } + /* re-establish request buffer for sending ENOMEM. */ + conn->in = bdata; + send_error(conn, ENOMEM); + return; + } /* Update relevant header fields and fill in the message body. */ bdata->hdr.msg.type = type; @@ -664,6 +708,8 @@ void send_reply(struct connection *conn, /* Queue for later transmission. */ list_add_tail(&bdata->list, &conn->out_list); + + return; } /* Some routines (write, mkdir, etc) just need a non-error return */ @@ -725,6 +771,8 @@ static char *perms_to_strings(const void strings = talloc_realloc(ctx, strings, char, *len + strlen(buffer) + 1); + if (!strings) + return NULL; strcpy(strings + *len, buffer); *len += strlen(buffer) + 1; } @@ -871,6 +919,9 @@ static struct node *construct_node(struc struct node *parent, *node; char *children, *parentname = get_parent(ctx, name); + if (!parentname) + return NULL; + /* If parent doesn't exist, create it. */ parent = read_node(conn, parentname, parentname); if (!parent) @@ -1032,6 +1083,7 @@ static void delete_node(struct connectio bool changed) { unsigned int i; + char *name; /* Delete self, then delete children. If we crash, then the worst that can happen is the children will continue to take up space, but @@ -1042,17 +1094,18 @@ static void delete_node(struct connectio for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) { struct node *child; - child = read_node(conn, node, - talloc_asprintf(node, "%s/%s", node->name, - node->children + i)); + name = talloc_asprintf(node, "%s/%s", node->name, + node->children + i); + child = name ? read_node(conn, node, name) : NULL; if (child) { delete_node(conn, child, false); } else { - trace("delete_node: No child '%s/%s' found!\n", + trace("delete_node: Error deleting child '%s/%s'!\n", node->name, node->children + i); /* Skip it, we've already deleted the parent. */ } + talloc_free(name); } } @@ -1095,9 +1148,15 @@ static int _rm(struct connection *conn, /* Delete from parent first, then if we crash, the worst that can happen is the child will continue to take up space, but will otherwise be unreachable. */ - struct node *parent = read_node(conn, ctx, get_parent(ctx, name)); + struct node *parent; + char *parentname = get_parent(ctx, name); + + if (!parentname) + return errno; + + parent = read_node(conn, ctx, parentname); if (!parent) - return EINVAL; + return (errno == ENOMEM) ? ENOMEM : EINVAL; if (!delete_child(conn, parent, basename(name))) return EINVAL; @@ -1123,19 +1182,24 @@ static int do_rm(struct connection *conn struct node *node; int ret; char *name; + char *parentname; node = get_node_canonicalized(conn, in, onearg(in), &name, XS_PERM_WRITE); if (!node) { /* Didn't exist already? Fine, if parent exists. */ if (errno == ENOENT) { - node = read_node(conn, in, get_parent(in, name)); + parentname = get_parent(in, name); + if (!parentname) + return errno; + node = read_node(conn, in, parentname); if (node) { send_ack(conn, XS_RM); return 0; } /* Restore errno, just in case. */ - errno = ENOENT; + if (errno != ENOMEM) + errno = ENOENT; } return errno; } @@ -1195,6 +1259,8 @@ static int do_set_perms(struct connectio num--; perms = talloc_array(node, struct xs_permissions, num); + if (!perms) + return ENOMEM; if (!xs_strings_to_perms(perms, num, permstr)) return errno; @@ -1329,7 +1395,7 @@ static void handle_input(struct connecti if (!conn->in) { conn->in = new_buffer(conn); - /* In case of no memory just try it next time again. */ + /* In case of no memory just try it again next time. */ if (!conn->in) return; } @@ -1337,26 +1403,29 @@ static void handle_input(struct connecti /* Not finished header yet? */ if (in->inhdr) { - bytes = conn->read(conn, in->hdr.raw + in->used, - sizeof(in->hdr) - in->used); - if (bytes < 0) - goto bad_client; - in->used += bytes; - if (in->used != sizeof(in->hdr)) - return; - - if (in->hdr.msg.len > XENSTORE_PAYLOAD_MAX) { - syslog(LOG_ERR, "Client tried to feed us %i", - in->hdr.msg.len); - goto bad_client; + if (in->used != sizeof(in->hdr)) { + bytes = conn->read(conn, in->hdr.raw + in->used, + sizeof(in->hdr) - in->used); + if (bytes < 0) + goto bad_client; + in->used += bytes; + if (in->used != sizeof(in->hdr)) + return; + + if (in->hdr.msg.len > XENSTORE_PAYLOAD_MAX) { + syslog(LOG_ERR, "Client tried to feed us %i", + in->hdr.msg.len); + goto bad_client; + } } if (in->hdr.msg.len <= DEFAULT_BUFFER_SIZE) in->buffer = in->default_buffer; else in->buffer = talloc_array(in, char, in->hdr.msg.len); + /* In case of no memory just try it again next time. */ if (!in->buffer) - goto bad_client; + return; in->used = 0; in->inhdr = false; } @@ -1479,6 +1548,9 @@ static void manual_node(const char *name struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE }; node = talloc_zero(NULL, struct node); + if (!node) + barf_perror("Could not allocate initial node %s", name); + node->name = name; node->perms = &perms; node->num_perms = 1; @@ -1516,6 +1588,8 @@ static void setup_structure(void) { char *tdbname; tdbname = talloc_strdup(talloc_autofree_context(), xs_daemon_tdb()); + if (!tdbname) + barf_perror("Could not create tdbname"); if (!(tdb_flags & TDB_INTERNAL)) tdb_ctx = tdb_open_ex(tdbname, 0, tdb_flags, O_RDWR, 0, @@ -1594,11 +1668,14 @@ static char *child_name(const char *s1, } -static void remember_string(struct hashtable *hash, const char *str) +static int remember_string(struct hashtable *hash, const char *str) { char *k = malloc(strlen(str) + 1); + + if (!k) + return 0; strcpy(k, str); - hashtable_insert(hash, k, (void *)1); + return hashtable_insert(hash, k, (void *)1); } @@ -1615,9 +1692,10 @@ static void remember_string(struct hasht * As we go, we record each node in the given reachable hashtable. These * entries will be used later in clean_store. */ -static void check_store_(const char *name, struct hashtable *reachable) +static int check_store_(const char *name, struct hashtable *reachable) { struct node *node = read_node(NULL, name, name); + int ret = 0; if (node) { size_t i = 0; @@ -1625,14 +1703,24 @@ static void check_store_(const char *nam struct hashtable * children = create_hashtable(16, hash_from_key_fn, keys_equal_fn); - remember_string(reachable, name); + if (!remember_string(reachable, name)) { + hashtable_destroy(children, 0); + log("check_store: ENOMEM"); + return ENOMEM; + } - while (i < node->childlen) { + while (i < node->childlen && !ret) { + struct node *childnode; size_t childlen = strlen(node->children + i); char * childname = child_name(node->name, node->children + i); - struct node *childnode = read_node(NULL, childname, - childname); + + if (!childname) { + log("check_store: ENOMEM"); + ret = ENOMEM; + break; + } + childnode = read_node(NULL, childname, childname); if (childnode) { if (hashtable_search(children, childname)) { @@ -1646,11 +1734,18 @@ static void check_store_(const char *nam } } else { - remember_string(children, childname); - check_store_(childname, reachable); + if (!remember_string(children, + childname)) { + log("check_store: ENOMEM"); + talloc_free(childnode); + talloc_free(childname); + ret = ENOMEM; + break; + } + ret = check_store_(childname, + reachable); } - } - else { + } else if (errno != ENOMEM) { log("check_store: No child '%s' found!\n", childname); @@ -1658,6 +1753,9 @@ static void check_store_(const char *nam remove_child_entry(NULL, node, i); i -= childlen + 1; } + } else { + log("check_store: ENOMEM"); + ret = ENOMEM; } talloc_free(childnode); @@ -1668,14 +1766,18 @@ static void check_store_(const char *nam hashtable_destroy(children, 0 /* Don't free values (they are all (void *)1) */); talloc_free(node); - } - else { + } else if (errno != ENOMEM) { /* Impossible, because no database should ever be without the root, and otherwise, we've just checked in our caller (which made a recursive call to get here). */ log("check_store: No child '%s' found: impossible!", name); + } else { + log("check_store: ENOMEM"); + ret = ENOMEM; } + + return ret; } @@ -1688,6 +1790,11 @@ static int clean_store_(TDB_CONTEXT *tdb struct hashtable *reachable = private; char * name = talloc_strndup(NULL, key.dptr, key.dsize); + if (!name) { + log("clean_store: ENOMEM"); + return 1; + } + if (!hashtable_search(reachable, name)) { log("clean_store: '%s' is orphaned!", name); if (recovery) { @@ -1717,9 +1824,14 @@ static void check_store(void) struct hashtable * reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn); + if (!reachable) { + log("check_store: ENOMEM"); + return; + } + log("Checking store ..."); - check_store_(root, reachable); - clean_store(reachable); + if (!check_store_(root, reachable)) + clean_store(reachable); log("Checking store complete."); hashtable_destroy(reachable, 0 /* Don't free values (they are all @@ -1773,10 +1885,14 @@ static void init_sockets(int **psock, in /* Create sockets for them to listen to. */ *psock = sock = talloc(talloc_autofree_context(), int); + if (!sock) + barf_perror("No memory when creating sockets"); *sock = socket(PF_UNIX, SOCK_STREAM, 0); if (*sock < 0) barf_perror("Could not create socket"); *pro_sock = ro_sock = talloc(talloc_autofree_context(), int); + if (!ro_sock) + barf_perror("No memory when creating sockets"); *ro_sock = socket(PF_UNIX, SOCK_STREAM, 0); if (*ro_sock < 0) barf_perror("Could not create socket"); --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -297,10 +297,15 @@ static struct domain *new_domain(void *c int rc; domain = talloc(context, struct domain); + if (!domain) + return NULL; + domain->port = 0; domain->shutdown = 0; domain->domid = domid; domain->path = talloc_domain_path(domain, domid); + if (!domain->path) + return NULL; wrl_domain_new(domain); @@ -314,6 +319,9 @@ static struct domain *new_domain(void *c domain->port = rc; domain->conn = new_connection(writechn, readchn); + if (!domain->conn) + return NULL; + domain->conn->domain = domain; domain->conn->id = domid; @@ -518,6 +526,8 @@ int do_get_domain_path(struct connection return EINVAL; path = talloc_domain_path(conn, atoi(domid_str)); + if (!path) + return errno; send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1); --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -120,7 +120,18 @@ void add_change_node(struct connection * } i = talloc(trans, struct changed_node); + if (!i) { + /* All we can do is let the transaction fail. */ + generation++; + return; + } i->node = talloc_strdup(i, node->name); + if (!i->node) { + /* All we can do is let the transaction fail. */ + generation++; + talloc_free(i); + return; + } i->recurse = recurse; list_add_tail(&i->list, &trans->changes); } @@ -165,11 +176,16 @@ int do_transaction_start(struct connecti /* Attach transaction to input for autofree until it's complete */ trans = talloc_zero(in, struct transaction); + if (!trans) + return ENOMEM; + INIT_LIST_HEAD(&trans->changes); INIT_LIST_HEAD(&trans->changed_domains); trans->generation = generation; trans->tdb_name = talloc_asprintf(trans, "%s.%p", xs_daemon_tdb(), trans); + if (!trans->tdb_name) + return ENOMEM; trans->tdb = tdb_copy(tdb_context(conn), trans->tdb_name); if (!trans->tdb) return errno; @@ -251,6 +267,11 @@ void transaction_entry_inc(struct transa } d = talloc(trans, struct changed_domain); + if (!d) { + /* Let the transaction fail. */ + generation++; + return; + } d->domid = domid; d->nbentry = 1; list_add_tail(&d->list, &trans->changed_domains); @@ -267,6 +288,11 @@ void transaction_entry_dec(struct transa } d = talloc(trans, struct changed_domain); + if (!d) { + /* Let the transaction fail. */ + generation++; + return; + } d->domid = domid; d->nbentry = -1; list_add_tail(&d->list, &trans->changed_domains); --- a/tools/xenstore/xenstored_watch.c +++ b/tools/xenstore/xenstored_watch.c @@ -112,6 +112,8 @@ static void add_event(struct connection len = strlen(name) + 1 + strlen(watch->token) + 1; data = talloc_array(ctx, char, len); + if (!data) + return; strcpy(data, name); strcpy(data + strlen(name) + 1, watch->token); send_reply(conn, XS_WATCH_EVENT, data, len); @@ -166,6 +168,8 @@ int do_watch(struct connection *conn, st } else { relative = !strstarts(vec[0], "/"); vec[0] = canonicalize(conn, in, vec[0]); + if (!vec[0]) + return ENOMEM; if (!is_valid_nodename(vec[0])) return EINVAL; } @@ -181,8 +185,14 @@ int do_watch(struct connection *conn, st return E2BIG; watch = talloc(conn, struct watch); + if (!watch) + return ENOMEM; watch->node = talloc_strdup(watch, vec[0]); watch->token = talloc_strdup(watch, vec[1]); + if (!watch->node || !watch->token) { + talloc_free(watch); + return ENOMEM; + } if (relative) watch->relative_path = get_implicit_path(conn); else @@ -211,6 +221,8 @@ int do_unwatch(struct connection *conn, return EINVAL; node = canonicalize(conn, in, vec[0]); + if (!node) + return ENOMEM; list_for_each_entry(watch, &conn->watches, list) { if (streq(watch->node, node) && streq(watch->token, vec[1])) { list_del(&watch->list);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor