nfs_mknod_async: fix use-after-free
[deb_libnfs.git] / lib / libnfs.c
index 572cd7818a6839d771367019b30dea8ab530c893..c660db3ecf11211c732003e2abb686459b01c5c0 100644 (file)
@@ -524,27 +524,16 @@ int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program
        return 0;
 }
 
-void free_nfs_cb_data(struct nfs_cb_data *data)
+static void free_nfs_cb_data(struct nfs_cb_data *data)
 {
-       if (data->saved_path != NULL) {
-               free(data->saved_path);
-               data->saved_path = NULL;
-       }
-
        if (data->continue_data != NULL) {
+               assert(data->free_continue_data);
                data->free_continue_data(data->continue_data);
-               data->continue_data = NULL;
        }
 
-       if (data->fh.data.data_val != NULL) {
-               free(data->fh.data.data_val);
-               data->fh.data.data_val = NULL;
-       }
-
-       if (data->buffer != NULL) {
-               free(data->buffer);
-               data->buffer = NULL;
-       }
+       free(data->saved_path);
+       free(data->fh.data.data_val);
+       free(data->buffer);
 
        free(data);
 }
@@ -1105,6 +1094,8 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to allocate "
                        "nfs_cb_data structure");
+               if (free_continue_data)
+                       free_continue_data(continue_data);
                return -1;
        }
        memset(data, 0, sizeof(struct nfs_cb_data));
@@ -2369,6 +2360,7 @@ int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb
        ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", path);
+               free(new_path);
                return -1;
        }
        *ptr = 0;
@@ -2590,6 +2582,7 @@ int nfs_mknod_async(struct nfs_context *nfs, const char *path, int mode, int dev
        ptr = strrchr(cb_data->path, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", path);
+               free_mknod_cb_data(cb_data);
                return -1;
        }
        *ptr = 0;
@@ -2601,7 +2594,6 @@ int nfs_mknod_async(struct nfs_context *nfs, const char *path, int mode, int dev
        /* data->path now points to the parent directory,  and beyond the nul terminateor is the new directory to create */
        if (nfs_lookuppath_async(nfs, cb_data->path, cb, private_data, nfs_mknod_continue_internal, cb_data, free_mknod_cb_data, 0) != 0) {
                rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
-               free_mknod_cb_data(cb_data);
                return -1;
        }
 
@@ -2736,6 +2728,7 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d
                nfsdirent->name = strdup(entry->name);
                if (nfsdirent->name == NULL) {
                        data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
+                       free(nfsdirent);
                        nfs_free_nfsdir(nfsdir);
                        data->continue_data = NULL;
                        free_nfs_cb_data(data);
@@ -2795,6 +2788,9 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d
                         * commands in flight to complete
                         */
                        if (rdpe_cb_data->getattrcount > 0) {
+                               nfs_free_nfsdir(nfsdir);
+                               data->continue_data = NULL;
+                               free_nfs_cb_data(data);
                                rdpe_cb_data->status = RPC_STATUS_ERROR;
                                free(rdpe_lookup_cb_data);
                                return;
@@ -2812,7 +2808,6 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d
        }
 }
 
-
 static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        READDIRPLUS3res *res = command_data;
@@ -2876,6 +2871,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
                nfsdirent->name = strdup(entry->name);
                if (nfsdirent->name == NULL) {
                        data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
+                       free(nfsdirent);
                        nfs_free_nfsdir(nfsdir);
                        data->continue_data = NULL;
                        free_nfs_cb_data(data);
@@ -3315,7 +3311,6 @@ int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs
        memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
 
        if (nfs_chmod_continue_internal(nfs, data) != 0) {
-               free_nfs_cb_data(data);
                return -1;
        }
 
@@ -3428,10 +3423,10 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int
        chown_data->uid = uid;
        chown_data->gid = gid;
 
-
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for fchown data");
+               free(chown_data);
                return -1;
        }
        memset(data, 0, sizeof(struct nfs_cb_data));
@@ -3439,6 +3434,7 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int
        data->cb            = cb;
        data->private_data  = private_data;
        data->continue_data = chown_data;
+       data->free_continue_data = free;
        data->fh.data.data_len = nfsfh->fh.data.data_len;
        data->fh.data.data_val = malloc(data->fh.data.data_len);
        if (data->fh.data.data_val == NULL) {
@@ -3448,9 +3444,7 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int
        }
        memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
 
-
        if (nfs_chown_continue_internal(nfs, data) != 0) {
-               free_nfs_cb_data(data);
                return -1;
        }