[OpenWrt-Devel] [PATCH] rpcd: uci: fix segfault and double free on set method

Yousong Zhou yszhou4tech at gmail.com
Mon Oct 28 23:16:40 EDT 2019


Hi Daniel,

On Mon, 28 Oct 2019 at 18:32, Daniel Danzberger <daniel at dd-wrt.com> wrote:
>
> Invalid reuse of pointers from uci_ptr can cause the rcpd to segfault on already freed memory.
> This bug could be trigged by calling 'set' with emtpy values on multiple non existing or already cleard options.
>
> For example:
>  ubus call uci set '{"config":"network","section":"wan","values":{"proto":"static","foo":"", "bar":""}}'
>
> Signed-off-by: Daniel Danzberger <daniel at dd-wrt.com>
> ---
>  uci.c | 55 ++++++++++++++++++++++++++-----------------------------
>  1 file changed, 26 insertions(+), 29 deletions(-)
>
> diff --git a/uci.c b/uci.c
> index 1587a19..e6ddbb5 100644
> --- a/uci.c
> +++ b/uci.c
> @@ -812,55 +812,58 @@ out:
>   *     option of if the existing options value differs from the blob value
>   */
>  static int
> -rpc_uci_merge_set(struct blob_attr *opt, struct uci_ptr *ptr)
> +rpc_uci_merge_set(struct blob_attr *opt,
> +                       struct uci_package *package,
> +                       const char *section)
>  {
> +       struct uci_ptr ptr = {};
>         struct blob_attr *cur;
>         int rem, rv;
>
> -       ptr->o = NULL;
> -       ptr->option = blobmsg_name(opt);
> -       ptr->value = NULL;

Also zeroing out ptr->flags should suffice to fix the issue.

 - When setting "proto", flags will have UCI_LOOKUP_COMPLETE set.
 - That flag remained there when working on "foo", and uci_set()
thought we were setting empty string on existing option, calling
uci_delete() instead which caused ptr->s to be freed.
 - Then when working on "bar", we access already freed up ptr->s

Preferably we could rework uci to allow setting empty string as value,
but that changes existing behavior and could break things.

Regards,
                yousong

> +       ptr.p = package;
> +       ptr.section = section;
> +       ptr.option = blobmsg_name(opt);
>
> -       if (!rpc_uci_verify_name(ptr->option))
> +       if (!rpc_uci_verify_name(ptr.option))
>                 return UBUS_STATUS_INVALID_ARGUMENT;
>
> -       if (rpc_uci_lookup(ptr) || !ptr->s)
> +       if (rpc_uci_lookup(&ptr) || !ptr.s)
>                 return UBUS_STATUS_NOT_FOUND;
>
>         if (blobmsg_type(opt) == BLOBMSG_TYPE_ARRAY)
>         {
> -               if (ptr->o)
> -                       uci_delete(cursor, ptr);
> +               if (ptr.o)
> +                       uci_delete(cursor, &ptr);
>
>                 rv = UBUS_STATUS_INVALID_ARGUMENT;
>
>                 blobmsg_for_each_attr(cur, opt, rem)
>                 {
> -                       if (!rpc_uci_format_blob(cur, &ptr->value))
> +                       if (!rpc_uci_format_blob(cur, &ptr.value))
>                                 continue;
>
> -                       uci_add_list(cursor, ptr);
> +                       uci_add_list(cursor, &ptr);
>                         rv = 0;
>                 }
>
>                 return rv;
>         }
> -       else if (ptr->o && ptr->o->type == UCI_TYPE_LIST)
> +       else if (ptr.o && ptr.o->type == UCI_TYPE_LIST)
>         {
> -               uci_delete(cursor, ptr);
> +               uci_delete(cursor, &ptr);
>
> -               if (!rpc_uci_format_blob(opt, &ptr->value))
> +               if (!rpc_uci_format_blob(opt, &ptr.value))
>                         return UBUS_STATUS_INVALID_ARGUMENT;
>
> -               uci_set(cursor, ptr);
> +               uci_set(cursor, &ptr);
>         }
>         else
>         {
> -               if (!rpc_uci_format_blob(opt, &ptr->value))
> +               if (!rpc_uci_format_blob(opt, &ptr.value))
>                         return UBUS_STATUS_INVALID_ARGUMENT;
>
> -               if (!ptr->o || !ptr->o->v.string || strcmp(ptr->o->v.string, ptr->value))
> -                       uci_set(cursor, ptr);
> +               if (!ptr.o || !ptr.o->v.string || strcmp(ptr.o->v.string, ptr.value))
> +                       uci_set(cursor, &ptr);
>         }
>
>         return 0;
> @@ -875,7 +878,7 @@ rpc_uci_set(struct ubus_context *ctx, struct ubus_object *obj,
>         struct blob_attr *cur;
>         struct uci_package *p = NULL;
>         struct uci_element *e;
> -       struct uci_ptr ptr = { 0 };
> +       const char *package, *section;
>         int rem, rv, err = 0;
>
>         blobmsg_parse(rpc_uci_set_policy, __RPC_S_MAX, tb,
> @@ -892,17 +895,17 @@ rpc_uci_set(struct ubus_context *ctx, struct ubus_object *obj,
>             !rpc_uci_verify_section(blobmsg_data(tb[RPC_S_SECTION])))
>                 return UBUS_STATUS_INVALID_ARGUMENT;
>
> -       ptr.package = blobmsg_data(tb[RPC_S_CONFIG]);
> +       package = blobmsg_data(tb[RPC_S_CONFIG]);
>
> -       if (uci_load(cursor, ptr.package, &p))
> +       if (uci_load(cursor, package, &p))
>                 return rpc_uci_status();
>
>         if (tb[RPC_S_SECTION])
>         {
> -               ptr.section = blobmsg_data(tb[RPC_S_SECTION]);
> +               section = blobmsg_data(tb[RPC_S_SECTION]);
>                 blobmsg_for_each_attr(cur, tb[RPC_S_VALUES], rem)
>                 {
> -                       rv = rpc_uci_merge_set(cur, &ptr);
> +                       rv = rpc_uci_merge_set(cur, p, section);
>
>                         if (rv)
>                                 err = rv;
> @@ -916,12 +919,9 @@ rpc_uci_set(struct ubus_context *ctx, struct ubus_object *obj,
>                                                    tb[RPC_S_TYPE], tb[RPC_S_MATCH]))
>                                 continue;
>
> -                       ptr.s = NULL;
> -                       ptr.section = e->name;
> -
>                         blobmsg_for_each_attr(cur, tb[RPC_S_VALUES], rem)
>                         {
> -                               rv = rpc_uci_merge_set(cur, &ptr);
> +                               rv = rpc_uci_merge_set(cur, p, e->name);
>
>                                 if (rv)
>                                         err = rv;
> @@ -929,9 +929,6 @@ rpc_uci_set(struct ubus_context *ctx, struct ubus_object *obj,
>                 }
>         }
>
> -       if (!err && !ptr.s)
> -               err = UBUS_STATUS_NOT_FOUND;
> -
>         if (!err)
>                 uci_save(cursor, p);
>
> --
> 2.23.0
>
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel at lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel

_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list