Whamcloud - gitweb
LU-9833 utils: resolve buffer over runs in lustre_rsync 14/31014/5
authorJames Simmons <uja.ornl@yahoo.com>
Fri, 12 Jan 2018 19:05:52 +0000 (14:05 -0500)
committerJohn L. Hammond <john.hammond@intel.com>
Mon, 26 Feb 2018 18:46:39 +0000 (18:46 +0000)
Newer version of gcc will report of snprintf is used in an
incorrect way. For the case of the lustre_rsync application
many times two buffers of size PATH_MAX are being placed into
one buffer of the size PATH_MAX. This can easily lead to a
buffer overrun. This patch resolves those bugs.

Test-Parameters: trivial testlist=lustre-rsync-test

Lustre-change: https://review.whamcloud.com/30373
Lustre-commit: b9bdd849f076302550221ff195e83e31dd7bddfc

Change-Id: I035b4a3b1d9695a16822649c2165e492e9f2879d
Signed-off-by: James Simmons <uja.ornl@yahoo.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: Dmitry Eremin <dmitry.eremin@intel.com>
Signed-off-by: Minh Diep <minh.diep@intel.com>
Reviewed-on: https://review.whamcloud.com/31014
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
lustre/utils/lustre_rsync.c

index 7d9dc09..0748832 100644 (file)
@@ -162,13 +162,13 @@ struct lr_info {
        char spfid[LR_FID_STR_LEN];
        char sname[NAME_MAX + 1];
        char name[NAME_MAX + 1];
-        char src[PATH_MAX + 1];
-        char dest[PATH_MAX + 1];
+       char src[3 * PATH_MAX + 1];
+       char dest[3 * PATH_MAX + 1];
         char path[PATH_MAX + 1];
         char savedpath[PATH_MAX + 1];
         char link[PATH_MAX + 1];
         char linktmp[PATH_MAX + 1];
-        char cmd[PATH_MAX];
+       char cmd[PATH_MAX * 10];
         int bufsize;
         char *buf;
 
@@ -284,9 +284,8 @@ void * lr_grow_buf(void *buf, int size)
 /* Use rsync to replicate file data */
 int lr_rsync_data(struct lr_info *info)
 {
-        int rc;
-        struct stat st_src, st_dest;
-        char cmd[PATH_MAX];
+       struct stat st_src, st_dest;
+       int rc;
 
         lr_debug(DTRACE, "Syncing data%s\n", info->tfid);
 
@@ -315,10 +314,14 @@ int lr_rsync_data(struct lr_info *info)
                  * replication is also to be considered.
                  */
                 int status;
-                snprintf(cmd, PATH_MAX, "%s --inplace %s %s", rsync, info->src,
-                        info->dest);
-                lr_debug(DTRACE, "\t%s %s\n", cmd, info->tfid);
-                status = system(cmd);
+
+               if (snprintf(info->cmd, sizeof(info->cmd), "%s --inplace %s %s",
+                            rsync, info->src, info->dest) >= sizeof(info->cmd)) {
+                       rc = -E2BIG;
+                       goto err;
+               }
+               lr_debug(DTRACE, "\t%s %s\n", info->cmd, info->tfid);
+               status = system(info->cmd);
                 if (status == -1) {
                         rc = -errno;
                 } else if (WIFEXITED(status)) {
@@ -341,7 +344,7 @@ int lr_rsync_data(struct lr_info *info)
                 lr_debug(DTRACE, "Not syncing %s and %s %s\n", info->src,
                          info->dest, info->tfid);
         }
-
+err:
         return rc;
 }
 
@@ -574,7 +577,7 @@ int lr_get_symlink(struct lr_info *info)
                     strlen(status->ls_source)) == 0) {
                 /* Strip source fs path and replace with target fs path. */
                 link = info->linktmp + strlen(status->ls_source);
-                snprintf(info->src, PATH_MAX, "%s%s",
+               snprintf(info->src, sizeof(info->src), "%s%s",
                          status->ls_targets[info->target_no], link);
                 link = info->src;
         } else {
@@ -671,18 +674,22 @@ out_err:
 void lr_cascade_move(const char *fid, const char *dest, struct lr_info *info)
 {
         struct lr_parent_child_list *curr, *prev;
-        char *d;
+       char d[4 * PATH_MAX + 1];
         int rc;
 
-        d = calloc(1, PATH_MAX + 1);
         prev = curr = parents;
         while (curr) {
                 if (strcmp(curr->pc_log.pcl_pfid, fid) == 0) {
-                        snprintf(d, PATH_MAX, "%s/%s", dest,
-                                 curr->pc_log.pcl_name);
-                        snprintf(info->src, PATH_MAX, "%s/%s/%s",
-                                status->ls_targets[info->target_no],
-                                SPECIAL_DIR, curr->pc_log.pcl_tfid);
+                       if (snprintf(d, sizeof(d), "%s/%s", dest,
+                                    curr->pc_log.pcl_name) >= sizeof(d)) {
+                               fprintf(stderr, "Buffer truncated\n");
+                               return;
+                       }
+                       if (snprintf(info->src, sizeof(info->src), "%s/%s/%s",
+                                    status->ls_targets[info->target_no],
+                                    SPECIAL_DIR, curr->pc_log.pcl_tfid) >=
+                           sizeof(info->src))
+                               return;
                         rc = rename(info->src, d);
                         if (rc == -1) {
                                 fprintf(stderr, "Error renaming file "
@@ -703,8 +710,6 @@ void lr_cascade_move(const char *fid, const char *dest, struct lr_info *info)
                         curr = curr->pc_next;
                 }
         }
-
-        free(d);
 }
 
 /* remove [info->spfid, info->sfid] from parents */
@@ -731,7 +736,7 @@ int lr_mk_special(struct lr_info *info)
 {
         int rc;
 
-        snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+       snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
                 status->ls_targets[info->target_no], SPECIAL_DIR,
                 info->tfid);
 
@@ -760,10 +765,11 @@ int lr_rmfile(struct lr_info *info)
 /* Recursively remove directory and its contents */
 int lr_rm_recursive(struct lr_info *info)
 {
-        int rc;
+       int rc;
 
-        snprintf(info->cmd, PATH_MAX, "rm -rf %s", info->dest);
-        rc = system(info->cmd);
+       snprintf(info->cmd, sizeof(info->cmd), "rm -rf %s",
+                info->dest);
+       rc = system(info->cmd);
         if (rc == -1)
                 rc = -errno;
 
@@ -775,7 +781,7 @@ int lr_rm_special(struct lr_info *info)
 {
         int rc;
 
-        snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+       snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
                  status->ls_targets[info->target_no], SPECIAL_DIR,
                  info->tfid);
         rc = lr_rmfile(info);
@@ -819,11 +825,13 @@ int lr_create(struct lr_info *info)
         /* Is f2p(pfid)+name != f2p(tfid)? If not the file has moved. */
         len = strlen(info->path);
        if (len == 1 && info->path[0] == '/')
-               snprintf(info->dest, PATH_MAX, "%s", info->name);
+               snprintf(info->dest, sizeof(info->dest), "%s", info->name);
        else if (len - 1 > 0 && info->path[len - 1] == '/')
-                snprintf(info->dest, PATH_MAX, "%s%s", info->path, info->name);
+               snprintf(info->dest, sizeof(info->dest), "%s%s", info->path,
+                        info->name);
         else
-                snprintf(info->dest, PATH_MAX, "%s/%s", info->path, info->name);
+               snprintf(info->dest, sizeof(info->dest), "%s/%s", info->path,
+                        info->name);
 
         lr_debug(DTRACE, "dest = %s; savedpath = %s\n", info->dest,
                  info->savedpath);
@@ -836,8 +844,8 @@ int lr_create(struct lr_info *info)
         /* Is f2p(pfid) present on the target? If not, the parent has
            moved */
         if (!mkspecial) {
-               snprintf(info->dest, PATH_MAX, "%s/%s", status->ls_targets[0],
-                       info->path);
+               snprintf(info->dest, sizeof(info->dest), "%s/%s",
+                        status->ls_targets[0], info->path);
                if (access(info->dest, F_OK) != 0) {
                        lr_debug(DTRACE, "create: parent %s not found\n",
                                info->dest);
@@ -846,10 +854,10 @@ int lr_create(struct lr_info *info)
         }
         for (info->target_no = 0; info->target_no < status->ls_num_targets;
              info->target_no++) {
-                snprintf(info->dest, PATH_MAX, "%s/%s",
+               snprintf(info->dest, sizeof(info->dest), "%s/%s",
                         status->ls_targets[info->target_no], info->savedpath);
                 lr_get_FID_PATH(status->ls_source, info->tfid, info->src,
-                                    PATH_MAX);
+                               PATH_MAX);
 
                 if (!mkspecial)
                         rc1 = lr_mkfile(info);
@@ -885,7 +893,7 @@ int lr_remove(struct lr_info *info)
                         rc = rc1;
                         continue;
                 }
-                snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+               snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
                         status->ls_targets[info->target_no], info->path,
                         info->name);
 
@@ -928,21 +936,22 @@ int lr_move(struct lr_info *info)
              info->target_no++) {
 
                 if (!rc_dest) {
-                        snprintf(info->dest, PATH_MAX, "%s/%s",
+                       snprintf(info->dest, sizeof(info->dest), "%s/%s",
                                 status->ls_targets[info->target_no],
                                info->path);
                         if (access(info->dest, F_OK) != 0) {
                                 rc_dest = -errno;
                         } else {
-                                snprintf(info->dest, PATH_MAX, "%s/%s/%s",
-                                        status->ls_targets[info->target_no],
-                                       info->path, info->name);
+                               snprintf(info->dest, sizeof(info->dest),
+                                        "%s/%s/%s",
+                                        status->ls_targets[info->target_no],
+                                        info->path, info->name);
                         }
                        lr_debug(DINFO, "dest path %s rc_dest=%d\n", info->dest,
                                 rc_dest);
                 }
                 if (rc_dest == -ENOENT) {
-                        snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+                       snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
                                 status->ls_targets[info->target_no],
                                SPECIAL_DIR, info->sfid);
                         special_dest = 1;
@@ -950,7 +959,7 @@ int lr_move(struct lr_info *info)
                 }
 
                if (!rc_src) {
-                       snprintf(info->src, PATH_MAX, "%s/%s/%s",
+                       snprintf(info->src, sizeof(info->src), "%s/%s/%s",
                                status->ls_targets[info->target_no],
                                srcpath, info->sname);
                        lr_debug(DINFO, "src path %s rc_src=%d\n", info->src,
@@ -958,7 +967,7 @@ int lr_move(struct lr_info *info)
                }
                 if (rc_src == -ENOENT || (access(info->src, F_OK) != 0 &&
                                           errno == ENOENT)) {
-                        snprintf(info->src, PATH_MAX, "%s/%s/%s",
+                       snprintf(info->src, sizeof(info->src), "%s/%s/%s",
                                 status->ls_targets[info->target_no],
                                SPECIAL_DIR, info->sfid);
                         special_src = 1;
@@ -1029,6 +1038,8 @@ int lr_link(struct lr_info *info)
 
                /* Search through the hardlinks to get the src */
                for (i = 0; i < st.st_nlink && info->src[0] == 0; i++) {
+                       size_t len;
+
                         rc1 = lr_get_path_ln(info, info->tfid, i);
                         lr_debug(rc1 ? 0:DTRACE, "\tfid2path %s, %s, %d rc=%d\n",
                                  info->path, info->name, i, rc1);
@@ -1039,7 +1050,9 @@ int lr_link(struct lr_info *info)
                         * Compare the path of target FID with info->dest
                         * to find out info->src.
                         */
-                       char srcpath[PATH_MAX];
+                       len = sizeof(status->ls_targets[info->target_no]) +
+                             sizeof(info->path);
+                       char srcpath[len + 1];
 
                        snprintf(srcpath, sizeof(srcpath), "%s/%s",
                                 status->ls_targets[info->target_no],
@@ -1058,11 +1071,11 @@ int lr_link(struct lr_info *info)
                 }
 
                 if (info->src[0] == 0)
-                        snprintf(info->src, PATH_MAX, "%s/%s/%s",
+                       snprintf(info->src, sizeof(info->src), "%s/%s/%s",
                                 status->ls_targets[info->target_no],
                                 SPECIAL_DIR, info->tfid);
                 else if (info->dest[0] == 0)
-                        snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+                       snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
                                 status->ls_targets[info->target_no],
                                 SPECIAL_DIR, info->tfid);
 
@@ -1095,7 +1108,7 @@ int lr_setattr(struct lr_info *info)
         for (info->target_no = 0; info->target_no < status->ls_num_targets;
              info->target_no++) {
 
-                snprintf(info->dest, PATH_MAX, "%s/%s",
+               snprintf(info->dest, sizeof(info->dest), "%s/%s",
                          status->ls_targets[info->target_no], info->path);
                 lr_debug(DINFO, "setattr: %s %s %s", info->src, info->dest,
                          info->tfid);
@@ -1126,7 +1139,7 @@ int lr_setxattr(struct lr_info *info)
         for (info->target_no = 0; info->target_no < status->ls_num_targets;
              info->target_no++) {
 
-                snprintf(info->dest, PATH_MAX, "%s/%s",
+               snprintf(info->dest, sizeof(info->dest), "%s/%s",
                         status->ls_targets[info->target_no], info->path);
                 lr_debug(DINFO, "setxattr: %s %s %s\n", info->src, info->dest,
                          info->tfid);
@@ -1213,7 +1226,7 @@ void lr_backup_log()
 
         if (logbackedup)
                 return;
-        snprintf(backupfile, PATH_MAX, "%s.old", statuslog);
+       snprintf(backupfile, sizeof(backupfile), "%s.old", statuslog);
         (void) rename(statuslog, backupfile);
         logbackedup = 1;
 
@@ -1416,12 +1429,12 @@ int lr_locate_rsync()
         int len;
 
         /* Locate rsync */
-        snprintf(rsync, PATH_MAX, "%s -p %s", TYPE, RSYNC);
+       snprintf(rsync, sizeof(rsync), "%s -p %s", TYPE, RSYNC);
         fp = popen(rsync, "r");
         if (fp == NULL)
                 return -1;
 
-        if (fgets(rsync, PATH_MAX, fp) == NULL) {
+       if (fgets(rsync, sizeof(rsync), fp) == NULL) {
                 fclose(fp);
                 return -1;
         }
@@ -1432,12 +1445,12 @@ int lr_locate_rsync()
         fclose(fp);
 
         /* Determine the version of rsync */
-        snprintf(rsync_ver, PATH_MAX, "%s --version", rsync);
+       snprintf(rsync_ver, sizeof(rsync_ver), "%s --version", rsync);
         fp = popen(rsync_ver, "r");
         if (fp == NULL)
                 return -1;
 
-        if (fgets(rsync_ver, PATH_MAX, fp) == NULL) {
+       if (fgets(rsync_ver, sizeof(rsync_ver), fp) == NULL) {
                 fclose(fp);
                 return -1;
         }
@@ -1507,9 +1520,18 @@ int lr_replicate()
                         "mountpoint.\n");
                goto out;
         }
-        if (status->ls_mdt_device[0] == '\0')
-                snprintf(status->ls_mdt_device, LR_NAME_MAXLEN, "%s%s",
-                        status->ls_source_fs, DEFAULT_MDT);
+
+       if (status->ls_mdt_device[0] == '\0') {
+               int len;
+
+               len = snprintf(status->ls_mdt_device,
+                              sizeof(status->ls_mdt_device), "%s%s",
+                              status->ls_source_fs, DEFAULT_MDT);
+               if (len >= sizeof(status->ls_mdt_device)) {
+                       rc = -E2BIG;
+                       goto out;
+               }
+       }
 
         ext = calloc(1, sizeof(struct lr_info));
        if (ext == NULL) {
@@ -1518,8 +1540,8 @@ int lr_replicate()
        }
 
         for (i = 0, xattr_not_supp = 0; i < status->ls_num_targets; i++) {
-                snprintf(info->dest, PATH_MAX, "%s/%s", status->ls_targets[i],
-                        SPECIAL_DIR);
+               snprintf(info->dest, sizeof(info->dest), "%s/%s",
+                        status->ls_targets[i], SPECIAL_DIR);
                 rc = mkdir(info->dest, 0777);
                 if (rc == -1 && errno != EEXIST) {
                         fprintf(stderr, "Error writing to target path %s.\n",