uci: reject invalid section and option names

The invoked libuci functions do not reliably check their arguments, causing
malformed section and option names to end up in the delta file, letting the
uci cli and other components to segfault when processung such invalid
entries.

In order to prevent that, manually test received values before passing them
on to libuci.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2018-08-08 18:14:30 +02:00
parent 820621952d
commit 51980c687b

74
uci.c
View file

@ -181,6 +181,60 @@ static const struct blobmsg_policy rpc_uci_rollback_policy[__RPC_B_MAX] = {
.type = BLOBMSG_TYPE_STRING }, .type = BLOBMSG_TYPE_STRING },
}; };
/*
* Validate a uci name
*/
static bool
rpc_uci_verify_str(const char *name, bool extended, bool type)
{
const char *c;
char *e;
if (!name || !*name)
return false;
if (extended && *name != '@')
extended = false;
for (c = name + extended; *c; c++)
if (!isalnum(*c) && *c != '_' && ((!type && !extended) || *c != '-'))
break;
if (extended) {
if (*c != '[')
return false;
strtol(++c, &e, 10);
return (e > c && *e == ']' && *(e+1) == 0);
}
return (*c == 0);
}
/*
* Check that string is a valid, shell compatible uci name
*/
static bool rpc_uci_verify_name(const char *name) {
return rpc_uci_verify_str(name, false, false);
}
/*
* Check that string is a valid section type name
*/
static bool rpc_uci_verify_type(const char *type) {
return rpc_uci_verify_str(type, false, true);
}
/*
* Check that the string is a valid section id, optionally in extended
* lookup notation
*/
static bool rpc_uci_verify_section(const char *section) {
return rpc_uci_verify_str(section, true, false);
}
/* /*
* Turn uci error state into ubus return code * Turn uci error state into ubus return code
*/ */
@ -644,6 +698,13 @@ rpc_uci_add(struct ubus_context *ctx, struct ubus_object *obj,
if (!rpc_uci_write_access(tb[RPC_A_SESSION], tb[RPC_A_CONFIG])) if (!rpc_uci_write_access(tb[RPC_A_SESSION], tb[RPC_A_CONFIG]))
return UBUS_STATUS_PERMISSION_DENIED; return UBUS_STATUS_PERMISSION_DENIED;
if (!rpc_uci_verify_type(blobmsg_data(tb[RPC_A_TYPE])))
return UBUS_STATUS_INVALID_ARGUMENT;
if (tb[RPC_A_NAME] &&
!rpc_uci_verify_name(blobmsg_data(tb[RPC_A_NAME])))
return UBUS_STATUS_INVALID_ARGUMENT;
ptr.package = blobmsg_data(tb[RPC_A_CONFIG]); ptr.package = blobmsg_data(tb[RPC_A_CONFIG]);
if (uci_load(cursor, ptr.package, &p)) if (uci_load(cursor, ptr.package, &p))
@ -676,6 +737,9 @@ rpc_uci_add(struct ubus_context *ctx, struct ubus_object *obj,
ptr.o = NULL; ptr.o = NULL;
ptr.option = blobmsg_name(cur); ptr.option = blobmsg_name(cur);
if (!rpc_uci_verify_name(ptr.option))
continue;
if (rpc_uci_lookup(&ptr) || !ptr.s) if (rpc_uci_lookup(&ptr) || !ptr.s)
continue; continue;
@ -726,6 +790,9 @@ rpc_uci_merge_set(struct blob_attr *opt, struct uci_ptr *ptr)
ptr->option = blobmsg_name(opt); ptr->option = blobmsg_name(opt);
ptr->value = NULL; ptr->value = NULL;
if (!rpc_uci_verify_name(ptr->option))
return;
if (rpc_uci_lookup(ptr) || !ptr->s) if (rpc_uci_lookup(ptr) || !ptr->s)
return; return;
@ -774,6 +841,10 @@ rpc_uci_set(struct ubus_context *ctx, struct ubus_object *obj,
if (!rpc_uci_write_access(tb[RPC_S_SESSION], tb[RPC_S_CONFIG])) if (!rpc_uci_write_access(tb[RPC_S_SESSION], tb[RPC_S_CONFIG]))
return UBUS_STATUS_PERMISSION_DENIED; return UBUS_STATUS_PERMISSION_DENIED;
if (tb[RPC_S_SECTION] &&
!rpc_uci_verify_section(blobmsg_data(tb[RPC_S_SECTION])))
return UBUS_STATUS_INVALID_ARGUMENT;
ptr.package = blobmsg_data(tb[RPC_S_CONFIG]); ptr.package = blobmsg_data(tb[RPC_S_CONFIG]);
if (uci_load(cursor, ptr.package, &p)) if (uci_load(cursor, ptr.package, &p))
@ -937,6 +1008,9 @@ rpc_uci_rename(struct ubus_context *ctx, struct ubus_object *obj,
ptr.section = blobmsg_data(tb[RPC_R_SECTION]); ptr.section = blobmsg_data(tb[RPC_R_SECTION]);
ptr.value = blobmsg_data(tb[RPC_R_NAME]); ptr.value = blobmsg_data(tb[RPC_R_NAME]);
if (!rpc_uci_verify_name(ptr.value))
return UBUS_STATUS_INVALID_ARGUMENT;
if (tb[RPC_R_OPTION]) if (tb[RPC_R_OPTION])
ptr.option = blobmsg_data(tb[RPC_R_OPTION]); ptr.option = blobmsg_data(tb[RPC_R_OPTION]);