Print this page
NEX-9323  cfgadm FC plugin allocates insufficient memory for internal
buffers
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.

  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 
  28 #include <libgen.h>

  29 #include "cfga_fp.h"
  30 
  31 /* The following are used by update_fabric_wwn_list() */
  32 #define COPY_EXT        ".cpy."         /* Extn used in naming backup file */
  33 #define TMP_EXT         ".tmp."         /* Extn used in naming temp file */
  34 static char *HDR =
  35 "#\n"
  36 "# fabric_WWN_map\n"
  37 "#\n"
  38 "# The physical ap_id list of configured fabric devices.\n"
  39 "# Do NOT edit this file by hand -- refer to the cfgadm_fp(1M)\n"
  40 "# man page and use cfgadm(1m) instead.\n"
  41 "#\n";
  42 
  43 /*
  44  * This function searches for "srch_str" (of length "slen") in "buf" (of length
  45  * "buflen"). If it is not found, "write_offset" has the offset in "buf" where
  46  * "srch_str" would have to be added in "buf". If "srch_str" is found in "buf",
  47  * "write_offset" has its offset in "buf"
  48  *


 205  * and has some data, it is expected to be of atleast the size of the lenght
 206  * of the warning header. This is the only check that is performed on the
 207  * validity of the file. No other checks are performed. On a valid
 208  * repository, to perform the update, this function basically makes use of
 209  * 3 buffers - the original buffer (repbuf), a copy buffer (c_repbuf) and a
 210  * temp buffer (t_repbuf).
 211  * The contents of the repository are mmap-ed into the repbuf and then
 212  * copied into the c_repbuf. All further operations are done using the copy.
 213  * t_repbuf is created to be the size of c_repbuf +/- 'slen' (based on
 214  * whether it is add or remove operation). After adding/removing the
 215  * 'update_str', the c_repbuf is copied to a OLD_FAB_REPOSITORY and t_repbuf
 216  * is made FAB_REPOSITORY.
 217  *
 218  */
 219 int
 220 update_fabric_wwn_list(int cmd, const char *update_str, char **errstring)
 221 {
 222         int     fd, copy_fd, tmp_fd, new_file_flag = 0;
 223         int     len, write_offset, bytes_left;
 224         int     sizeof_rep_hdr = strlen(HDR);

 225         char    *repbuf, *c_repbuf, *t_repbuf;
 226         char    *copy_rep, *tmp_rep, *upd_str;
 227         off_t   filesize, size;
 228         struct stat     stbuf;
 229 
 230         /* Do some initializations */
 231         fd = copy_fd = tmp_fd = -1;
 232         repbuf = c_repbuf = t_repbuf = NULL;
 233         copy_rep = tmp_rep = upd_str = NULL;
 234         size = filesize = write_offset = bytes_left = 0;
 235 
 236         /*
 237          * Set the mode to read only.  Root user can still open as RDWR.
 238          * We ignore errors in general here. But, just notice ENOENTs
 239          */
 240         if ((chmod(FAB_REPOSITORY, S_IRUSR|S_IRGRP|S_IROTH) == -1) &&
 241                                                         (errno == ENOENT)) {
 242                 new_file_flag = 1;
 243                 mkdirp(FAB_REPOSITORY_DIR,
 244                                 S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);


 286                 /*
 287                  * We are trying to add/remove a NULL string.
 288                  * Just return success
 289                  */
 290                 close(fd);
 291                 return (FPCFGA_OK);
 292         }
 293 
 294         if ((upd_str = calloc(1, len + 2)) == NULL) {
 295                 close(fd);
 296                 cfga_err(errstring, errno, ERR_UPD_REP, 0);
 297                 return (FPCFGA_LIB_ERR);
 298         }
 299 
 300         strcpy(upd_str, update_str);
 301         strcat(upd_str, "\n");          /* Append a new line char */
 302         len = strlen(upd_str);
 303 
 304         if (filesize > 0) {
 305                 if ((copy_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
 306                                 sizeof (COPY_EXT) + sizeof (pid_t))) == NULL) {
 307                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 308                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 309                 }
 310 
 311                 (void) sprintf(copy_rep, "%s%s%ld", FAB_REPOSITORY, COPY_EXT,
 312                                                                 getpid());
 313 
 314                 if ((copy_fd = open(copy_rep, O_RDWR | O_CREAT | O_TRUNC,
 315                                                 S_IRUSR | S_IWUSR)) < 0) {
 316                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 317                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 318                 }
 319 
 320                 if ((repbuf = (char *)mmap(0, filesize, PROT_READ,
 321                                         MAP_SHARED, fd, 0)) == MAP_FAILED) {
 322                         close(fd);
 323                         free(upd_str);
 324                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 325                         return (FPCFGA_LIB_ERR);
 326                 }


 413                 }
 414         }
 415 
 416         /* Now, size and filesize are > sizeof_rep_hdr */
 417 
 418         switch (cmd) {
 419         case ADD_ENTRY:
 420                 size += len;
 421                 /*
 422                  * We'll search the full repository, header included, since
 423                  * we dont expect upd_str to match anything in the header.
 424                  */
 425                 if (search_line(c_repbuf, filesize, upd_str,
 426                                 len - 1, &write_offset, &bytes_left) == 0) {
 427                         /* line already exists in repository or len == 0 */
 428                         CLEANUP_N_RET(FPCFGA_OK); /* SUCCESS */
 429                 }
 430 
 431                 /* construct temp file name using pid. */
 432                 if ((tmp_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
 433                                 sizeof (TMP_EXT) + sizeof (pid_t))) == NULL) {
 434                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 435                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 436                 }
 437 
 438                 (void) sprintf(tmp_rep, "%s%s%ld", FAB_REPOSITORY,
 439                                                         TMP_EXT, getpid());
 440 
 441                 /* Open tmp repository file in absolute mode */
 442                 if ((tmp_fd = open(tmp_rep, O_RDWR|O_CREAT|O_TRUNC,
 443                                                 S_IRUSR | S_IWUSR)) < 0) {
 444                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 445                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 446                 }
 447 
 448                 if (lseek(tmp_fd, size - 1, SEEK_SET) == -1) {
 449                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 450                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 451                 }
 452 
 453                 if (write(tmp_fd, "", 1) != 1) {


 508 
 509         case REMOVE_ENTRY:
 510                 if (size >= sizeof_rep_hdr + len - 1) {
 511                         size -= len;
 512                         /*
 513                          * No need to init the 'else' part (size < len) because
 514                          * in that case, there will be nothing to delete from
 515                          * the file and so 'size' will not be used in the code
 516                          * below since search_line() will not find upd_str.
 517                          */
 518                 }
 519 
 520                 if (search_line(c_repbuf, filesize, upd_str, len - 1,
 521                                         &write_offset, &bytes_left) != 0) {
 522                         /* this line does not exists - nothing to remove */
 523                         CLEANUP_N_RET(FPCFGA_OK); /* SUCCESS */
 524                 }
 525 
 526                 /* construct temp file name using pid. */
 527                 if ((tmp_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
 528                                 sizeof (TMP_EXT) + sizeof (pid_t))) == NULL) {
 529                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 530                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 531                 }
 532 
 533                 (void) sprintf(tmp_rep, "%s%s%ld", FAB_REPOSITORY,
 534                                                         TMP_EXT, getpid());
 535 
 536                 /* Open tmp repository file in absolute mode */
 537                 if ((tmp_fd = open(tmp_rep, O_RDWR|O_CREAT|O_TRUNC,
 538                                                 S_IRUSR | S_IWUSR)) < 0) {
 539                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 540                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 541                 }
 542 
 543                 if (size > 0) {
 544                         if (lseek(tmp_fd, size - 1, SEEK_SET) == -1) {
 545                                 cfga_err(errstring, errno, ERR_UPD_REP, 0);
 546                                 CLEANUP_N_RET(FPCFGA_LIB_ERR);
 547                         }
 548 




   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 
  29 #include <libgen.h>
  30 #include <limits.h>
  31 #include "cfga_fp.h"
  32 
  33 /* The following are used by update_fabric_wwn_list() */
  34 #define COPY_EXT        ".cpy."         /* Extn used in naming backup file */
  35 #define TMP_EXT         ".tmp."         /* Extn used in naming temp file */
  36 static char *HDR =
  37 "#\n"
  38 "# fabric_WWN_map\n"
  39 "#\n"
  40 "# The physical ap_id list of configured fabric devices.\n"
  41 "# Do NOT edit this file by hand -- refer to the cfgadm_fp(1M)\n"
  42 "# man page and use cfgadm(1m) instead.\n"
  43 "#\n";
  44 
  45 /*
  46  * This function searches for "srch_str" (of length "slen") in "buf" (of length
  47  * "buflen"). If it is not found, "write_offset" has the offset in "buf" where
  48  * "srch_str" would have to be added in "buf". If "srch_str" is found in "buf",
  49  * "write_offset" has its offset in "buf"
  50  *


 207  * and has some data, it is expected to be of atleast the size of the lenght
 208  * of the warning header. This is the only check that is performed on the
 209  * validity of the file. No other checks are performed. On a valid
 210  * repository, to perform the update, this function basically makes use of
 211  * 3 buffers - the original buffer (repbuf), a copy buffer (c_repbuf) and a
 212  * temp buffer (t_repbuf).
 213  * The contents of the repository are mmap-ed into the repbuf and then
 214  * copied into the c_repbuf. All further operations are done using the copy.
 215  * t_repbuf is created to be the size of c_repbuf +/- 'slen' (based on
 216  * whether it is add or remove operation). After adding/removing the
 217  * 'update_str', the c_repbuf is copied to a OLD_FAB_REPOSITORY and t_repbuf
 218  * is made FAB_REPOSITORY.
 219  *
 220  */
 221 int
 222 update_fabric_wwn_list(int cmd, const char *update_str, char **errstring)
 223 {
 224         int     fd, copy_fd, tmp_fd, new_file_flag = 0;
 225         int     len, write_offset, bytes_left;
 226         int     sizeof_rep_hdr = strlen(HDR);
 227         int     pid_maxlen = snprintf(NULL, 0, "%d", PID_MAX) + 1;
 228         char    *repbuf, *c_repbuf, *t_repbuf;
 229         char    *copy_rep, *tmp_rep, *upd_str;
 230         off_t   filesize, size;
 231         struct stat     stbuf;
 232 
 233         /* Do some initializations */
 234         fd = copy_fd = tmp_fd = -1;
 235         repbuf = c_repbuf = t_repbuf = NULL;
 236         copy_rep = tmp_rep = upd_str = NULL;
 237         size = filesize = write_offset = bytes_left = 0;
 238 
 239         /*
 240          * Set the mode to read only.  Root user can still open as RDWR.
 241          * We ignore errors in general here. But, just notice ENOENTs
 242          */
 243         if ((chmod(FAB_REPOSITORY, S_IRUSR|S_IRGRP|S_IROTH) == -1) &&
 244                                                         (errno == ENOENT)) {
 245                 new_file_flag = 1;
 246                 mkdirp(FAB_REPOSITORY_DIR,
 247                                 S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);


 289                 /*
 290                  * We are trying to add/remove a NULL string.
 291                  * Just return success
 292                  */
 293                 close(fd);
 294                 return (FPCFGA_OK);
 295         }
 296 
 297         if ((upd_str = calloc(1, len + 2)) == NULL) {
 298                 close(fd);
 299                 cfga_err(errstring, errno, ERR_UPD_REP, 0);
 300                 return (FPCFGA_LIB_ERR);
 301         }
 302 
 303         strcpy(upd_str, update_str);
 304         strcat(upd_str, "\n");          /* Append a new line char */
 305         len = strlen(upd_str);
 306 
 307         if (filesize > 0) {
 308                 if ((copy_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
 309                                 sizeof (COPY_EXT) + pid_maxlen)) == NULL) {
 310                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 311                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 312                 }
 313 
 314                 (void) sprintf(copy_rep, "%s%s%ld", FAB_REPOSITORY, COPY_EXT,
 315                                                                 getpid());
 316 
 317                 if ((copy_fd = open(copy_rep, O_RDWR | O_CREAT | O_TRUNC,
 318                                                 S_IRUSR | S_IWUSR)) < 0) {
 319                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 320                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 321                 }
 322 
 323                 if ((repbuf = (char *)mmap(0, filesize, PROT_READ,
 324                                         MAP_SHARED, fd, 0)) == MAP_FAILED) {
 325                         close(fd);
 326                         free(upd_str);
 327                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 328                         return (FPCFGA_LIB_ERR);
 329                 }


 416                 }
 417         }
 418 
 419         /* Now, size and filesize are > sizeof_rep_hdr */
 420 
 421         switch (cmd) {
 422         case ADD_ENTRY:
 423                 size += len;
 424                 /*
 425                  * We'll search the full repository, header included, since
 426                  * we dont expect upd_str to match anything in the header.
 427                  */
 428                 if (search_line(c_repbuf, filesize, upd_str,
 429                                 len - 1, &write_offset, &bytes_left) == 0) {
 430                         /* line already exists in repository or len == 0 */
 431                         CLEANUP_N_RET(FPCFGA_OK); /* SUCCESS */
 432                 }
 433 
 434                 /* construct temp file name using pid. */
 435                 if ((tmp_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
 436                                 sizeof (TMP_EXT) + pid_maxlen)) == NULL) {
 437                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 438                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 439                 }
 440 
 441                 (void) sprintf(tmp_rep, "%s%s%ld", FAB_REPOSITORY,
 442                                                         TMP_EXT, getpid());
 443 
 444                 /* Open tmp repository file in absolute mode */
 445                 if ((tmp_fd = open(tmp_rep, O_RDWR|O_CREAT|O_TRUNC,
 446                                                 S_IRUSR | S_IWUSR)) < 0) {
 447                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 448                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 449                 }
 450 
 451                 if (lseek(tmp_fd, size - 1, SEEK_SET) == -1) {
 452                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 453                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 454                 }
 455 
 456                 if (write(tmp_fd, "", 1) != 1) {


 511 
 512         case REMOVE_ENTRY:
 513                 if (size >= sizeof_rep_hdr + len - 1) {
 514                         size -= len;
 515                         /*
 516                          * No need to init the 'else' part (size < len) because
 517                          * in that case, there will be nothing to delete from
 518                          * the file and so 'size' will not be used in the code
 519                          * below since search_line() will not find upd_str.
 520                          */
 521                 }
 522 
 523                 if (search_line(c_repbuf, filesize, upd_str, len - 1,
 524                                         &write_offset, &bytes_left) != 0) {
 525                         /* this line does not exists - nothing to remove */
 526                         CLEANUP_N_RET(FPCFGA_OK); /* SUCCESS */
 527                 }
 528 
 529                 /* construct temp file name using pid. */
 530                 if ((tmp_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
 531                                 sizeof (TMP_EXT) + pid_maxlen)) == NULL) {
 532                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 533                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 534                 }
 535 
 536                 (void) sprintf(tmp_rep, "%s%s%ld", FAB_REPOSITORY,
 537                                                         TMP_EXT, getpid());
 538 
 539                 /* Open tmp repository file in absolute mode */
 540                 if ((tmp_fd = open(tmp_rep, O_RDWR|O_CREAT|O_TRUNC,
 541                                                 S_IRUSR | S_IWUSR)) < 0) {
 542                         cfga_err(errstring, errno, ERR_UPD_REP, 0);
 543                         CLEANUP_N_RET(FPCFGA_LIB_ERR);
 544                 }
 545 
 546                 if (size > 0) {
 547                         if (lseek(tmp_fd, size - 1, SEEK_SET) == -1) {
 548                                 cfga_err(errstring, errno, ERR_UPD_REP, 0);
 549                                 CLEANUP_N_RET(FPCFGA_LIB_ERR);
 550                         }
 551