trace: don't leak file descriptor in error path
[project/procd.git] / hotplug-dispatch.c
index 6a4fa68a00a56b1a9657f445bcb4d172bb7e1de6..f1ece3833f235d59b321d6d9bd89ea3ef621fcd9 100644 (file)
@@ -16,7 +16,6 @@
 #include <sys/inotify.h>
 #include <sys/types.h>
 
-#include <assert.h>
 #include <dirent.h>
 #include <errno.h>
 #include <glob.h>
@@ -105,7 +104,11 @@ static void hotplug_exec(struct uloop_timeout *t)
                return;
        }
 
-       asprintf(&script, ". /lib/functions.sh\n. %s\n", pc->globbuf.gl_pathv[pc->cnt++]);
+       if (asprintf(&script, ". /lib/functions.sh\n. %s\n", pc->globbuf.gl_pathv[pc->cnt++]) == -1) {
+               pc->ret = ENOMEM;
+               return;
+       }
+
        /* prepare for execve() */
        exec_argv[0] = "/bin/sh";
        exec_argv[1] = "-c";
@@ -120,6 +123,7 @@ static void hotplug_exec(struct uloop_timeout *t)
                exit(execve(exec_argv[0], exec_argv, pc->envp));
        } else if (pc->process.pid < 0) {
                /* fork error */
+               free(script);
                hotplug_free(pc);
                return;
        }
@@ -184,6 +188,7 @@ static int hotplug_call(struct ubus_context *ctx, struct ubus_object *obj,
        size_t envz = 0;
        struct hotplug_process *pc;
        bool async = true;
+       int err = UBUS_STATUS_UNKNOWN_ERROR;
 
        blobmsg_parse(hotplug_policy, __HOTPLUG_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
 
@@ -195,10 +200,21 @@ static int hotplug_call(struct ubus_context *ctx, struct ubus_object *obj,
        /* first adding existing environment to avl_tree */
        while (*tmpenv) {
                envle = calloc(1, sizeof(struct envlist));
-               assert(envle != NULL);
+               if (!envle)
+                       goto err_envle;
+
                envle->env = strdup(*tmpenv);
+               if (!envle->env) {
+                       free(envle);
+                       goto err_envle;
+               }
                envle->avl.key = envle->env;
-               avl_insert(&env, &envle->avl);
+               if (avl_insert(&env, &envle->avl) == -1) {
+                       free(envle->env);
+                       free(envle);
+                       goto err_envle;
+               }
+
                ++tmpenv;
        }
 
@@ -232,14 +248,26 @@ static int hotplug_call(struct ubus_context *ctx, struct ubus_object *obj,
                        async = false;
 
                envle = calloc(1, sizeof(struct envlist));
-               assert(envle != NULL);
+               if (!envle)
+                       goto err_envle;
+
                envle->env = strdup(enve);
+               if (!envle->env) {
+                       free(envle);
+                       goto err_envle;
+               }
                envle->avl.key = envle->env;
                if (avl_insert(&env, &envle->avl)) {
+                       /* do not override existing env values, just skip */
                        free((void*)envle->env);
                        free(envle);
                }
-               ++tmpenv;
+       }
+
+       /* synchronous calls are unsupported for now */
+       if (!async) {
+               err = UBUS_STATUS_NOT_SUPPORTED;
+               goto err_envle;
        }
 
        /* allocating new environment */
@@ -247,7 +275,8 @@ static int hotplug_call(struct ubus_context *ctx, struct ubus_object *obj,
                ++envz;
 
        envp = calloc(envz + 1, sizeof(char *));
-       assert(envp != NULL);
+       if (!envp)
+               goto err_envle;
 
        /* populating new environment */
        envz = 0;
@@ -257,25 +286,22 @@ static int hotplug_call(struct ubus_context *ctx, struct ubus_object *obj,
                free(envle);
        }
 
-       /* glob'ing for hotplug scripts */
-       if (asprintf(&globstr, "%s/%s/*", HOTPLUG_BASEDIR, subsys) == -1) {
+       pc = calloc(1, sizeof(struct hotplug_process));
+       if (!pc) {
                env_free(envp);
                return UBUS_STATUS_UNKNOWN_ERROR;
        }
-
-       /* synchronous calls are unsupported for now */
-       if (!async) {
-               env_free(envp);
-               return UBUS_STATUS_NOT_SUPPORTED;
-       }
-
-       pc = calloc(1, sizeof(struct hotplug_process));
-       assert(pc != NULL);
        pc->timeout.cb = hotplug_exec;
        pc->envp = envp;
        pc->cnt = 0;
        pc->ubus = obj;
 
+       /* glob'ing for hotplug scripts */
+       if (asprintf(&globstr, "%s/%s/*", HOTPLUG_BASEDIR, subsys) == -1) {
+               hotplug_free(pc);
+               return UBUS_STATUS_UNKNOWN_ERROR;
+       }
+
        if (glob(globstr, GLOB_DOOFFS, NULL, &pc->globbuf)) {
                free(globstr);
                hotplug_free(pc);
@@ -288,6 +314,17 @@ static int hotplug_call(struct ubus_context *ctx, struct ubus_object *obj,
        uloop_timeout_set(&pc->timeout, 50);
 
        return UBUS_STATUS_OK;
+
+err_envle:
+       avl_for_each_element_safe(&env, envle, avl, p) {
+               if (envle->env)
+                       free(envle->env);
+
+               avl_delete(&env, &envle->avl);
+               free(envle);
+       }
+
+       return err;
 }
 
 static const struct ubus_method hotplug_methods[] = {
@@ -302,7 +339,8 @@ static void add_subsystem(int nlen, char *newname)
        struct hotplug_subsys *nh = calloc(1, sizeof(struct hotplug_subsys));
        char *name;
 
-       asprintf(&name, "%s%.*s", HOTPLUG_OBJECT_PREFIX, nlen, newname);
+       if (asprintf(&name, "%s%.*s", HOTPLUG_OBJECT_PREFIX, nlen, newname) == -1)
+               exit(ENOMEM);
 
        /* prepare and add ubus object */
        nh->ubus.name = name;
@@ -403,10 +441,18 @@ void ubus_init_hotplug(struct ubus_context *newctx)
        }
        fd_inotify_read.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
        fd_inotify_read.cb = inotify_read_handler;
-       assert(fd_inotify_read.fd != -1);
+       if (fd_inotify_read.fd == -1) {
+               printf("failed to initialize inotify handler for %s\n", HOTPLUG_BASEDIR);
+               return;
+       }
 
        inotify_buffer = calloc(1, INOTIFY_SZ);
-       assert(inotify_buffer != NULL);
-       inotify_add_watch(fd_inotify_read.fd, HOTPLUG_BASEDIR, IN_CREATE | IN_MOVED_TO | IN_DELETE | IN_MOVED_FROM | IN_ONLYDIR);
+       if (!inotify_buffer)
+               return;
+
+       if (inotify_add_watch(fd_inotify_read.fd, HOTPLUG_BASEDIR,
+               IN_CREATE | IN_MOVED_TO | IN_DELETE | IN_MOVED_FROM | IN_ONLYDIR) == -1)
+               return;
+
        uloop_fd_add(&fd_inotify_read, ULOOP_READ);
 }