diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-06-22 11:36:27 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-06-22 11:36:27 +0000 |
commit | 542213b19f73f84fe38a0c734394135d8a4041d8 (patch) | |
tree | 2ac84f50820b7d6bbf7016c88517ae401e18fb5f /usr | |
parent | 001cfa178a95def0f13cf06ea25b89bf4acc6651 (diff) | |
parent | c686756220120076a07be0dcce54be698101a3d1 (diff) | |
download | illumos-joyent-542213b19f73f84fe38a0c734394135d8a4041d8.tar.gz |
[illumos-gate merge]
commit c686756220120076a07be0dcce54be698101a3d1
12541 sgs: smatch and NULL pointer errors
commit d865fc92e4b640c73c2957a20b3d82622c741be5
12824 recvmsg(): adjust final cmsg->cmsg_len upon MSG_CTRUNC
commit ce5f7fb896fce369b4ec50da6d3a232bce2458ce
12836 loader: strings in nvlist are counted strings, not c-strings
Diffstat (limited to 'usr')
-rw-r--r-- | usr/src/boot/Makefile.version | 2 | ||||
-rw-r--r-- | usr/src/boot/lib/libstand/zfs/zfsimpl.c | 171 | ||||
-rw-r--r-- | usr/src/cmd/sgs/error/common/errorinput.c | 30 | ||||
-rw-r--r-- | usr/src/cmd/sgs/error/common/errorsubr.c | 25 | ||||
-rw-r--r-- | usr/src/cmd/sgs/error/common/errortouch.c | 58 | ||||
-rw-r--r-- | usr/src/cmd/sgs/rtld/common/a.out.c | 4 | ||||
-rw-r--r-- | usr/src/cmd/sgs/rtld/common/cache_a.out.c | 79 | ||||
-rw-r--r-- | usr/src/pkg/manifests/system-test-ostest.mf | 3 | ||||
-rw-r--r-- | usr/src/test/os-tests/runfiles/default.run | 4 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/sockfs/Makefile | 24 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/sockfs/rights.c | 700 | ||||
-rw-r--r-- | usr/src/uts/common/fs/sockfs/socksubr.c | 43 | ||||
-rw-r--r-- | usr/src/uts/common/fs/sockfs/socksyscalls.c | 62 | ||||
-rw-r--r-- | usr/src/uts/common/sys/socketvar.h | 4 |
14 files changed, 1010 insertions, 199 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version index 7b173d0d47..f48764b495 100644 --- a/usr/src/boot/Makefile.version +++ b/usr/src/boot/Makefile.version @@ -33,4 +33,4 @@ LOADER_VERSION = 1.1 # Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes. # The version is processed from left to right, the version number can only # be increased. -BOOT_VERSION = $(LOADER_VERSION)-2020.05.09.1 +BOOT_VERSION = $(LOADER_VERSION)-2020.06.10.1 diff --git a/usr/src/boot/lib/libstand/zfs/zfsimpl.c b/usr/src/boot/lib/libstand/zfs/zfsimpl.c index a5c0d4fc73..ce3180d493 100644 --- a/usr/src/boot/lib/libstand/zfs/zfsimpl.c +++ b/usr/src/boot/lib/libstand/zfs/zfsimpl.c @@ -193,7 +193,7 @@ xdr_uint64_t(const unsigned char **xdr, uint64_t *lp) static int nvlist_find(const unsigned char *nvlist, const char *name, int type, - int *elementsp, void *valuep) + int *elementsp, void *valuep, int *sizep) { const unsigned char *p, *pair; int junk; @@ -225,6 +225,8 @@ nvlist_find(const unsigned char *nvlist, const char *name, int type, } else if (type == DATA_TYPE_STRING) { int len; xdr_int(&p, &len); + if (sizep != NULL) + *sizep = len; (*(const char **)valuep) = (const char *)p; return (0); } else if (type == DATA_TYPE_NVLIST || @@ -389,7 +391,7 @@ nvlist_print(const unsigned char *nvlist, unsigned int indent) for (i = 0; i < indent; i++) printf(" "); - printf("%s %s", typenames[pairtype], pairname); + printf("%s %.*s", typenames[pairtype], namelen, pairname); xdr_int(&p, &elements); switch (pairtype) { @@ -403,7 +405,7 @@ nvlist_print(const unsigned char *nvlist, unsigned int indent) case DATA_TYPE_STRING: { int len; xdr_int(&p, &len); - printf(" = \"%s\"\n", p); + printf(" = \"%.*s\"\n", len, p); break; } @@ -419,8 +421,8 @@ nvlist_print(const unsigned char *nvlist, unsigned int indent) if (j != elements - 1) { for (i = 0; i < indent; i++) printf(" "); - printf("%s %s", typenames[pairtype], - pairname); + printf("%s %.*s", typenames[pairtype], + namelen, pairname); } } break; @@ -1083,17 +1085,17 @@ vdev_set_initial_state(vdev_t *vdev, const unsigned char *nvlist) is_offline = is_removed = is_faulted = is_degraded = isnt_present = 0; is_log = 0; (void) nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, NULL, - &is_offline); + &is_offline, NULL); (void) nvlist_find(nvlist, ZPOOL_CONFIG_REMOVED, DATA_TYPE_UINT64, NULL, - &is_removed); + &is_removed, NULL); (void) nvlist_find(nvlist, ZPOOL_CONFIG_FAULTED, DATA_TYPE_UINT64, NULL, - &is_faulted); + &is_faulted, NULL); (void) nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, - NULL, &is_degraded); + NULL, &is_degraded, NULL); (void) nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, - NULL, &isnt_present); + NULL, &isnt_present, NULL); (void) nvlist_find(nvlist, ZPOOL_CONFIG_IS_LOG, DATA_TYPE_UINT64, NULL, - &is_log); + &is_log, NULL); if (is_offline != 0) vdev->v_state = VDEV_STATE_OFFLINE; @@ -1115,34 +1117,37 @@ vdev_init(uint64_t guid, const unsigned char *nvlist, vdev_t **vdevp) uint64_t id, ashift, asize, nparity; const char *path; const char *type; + int len, pathlen; + char *name; vdev_t *vdev; - if (nvlist_find(nvlist, ZPOOL_CONFIG_ID, DATA_TYPE_UINT64, NULL, &id) || + if (nvlist_find(nvlist, ZPOOL_CONFIG_ID, DATA_TYPE_UINT64, NULL, &id, + NULL) || nvlist_find(nvlist, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING, - NULL, &type)) { + NULL, &type, &len)) { return (ENOENT); } - if (strcmp(type, VDEV_TYPE_MIRROR) != 0 && - strcmp(type, VDEV_TYPE_DISK) != 0 && + if (memcmp(type, VDEV_TYPE_MIRROR, len) != 0 && + memcmp(type, VDEV_TYPE_DISK, len) != 0 && #ifdef ZFS_TEST - strcmp(type, VDEV_TYPE_FILE) != 0 && + memcmp(type, VDEV_TYPE_FILE, len) != 0 && #endif - strcmp(type, VDEV_TYPE_RAIDZ) != 0 && - strcmp(type, VDEV_TYPE_INDIRECT) != 0 && - strcmp(type, VDEV_TYPE_REPLACING) != 0) { + memcmp(type, VDEV_TYPE_RAIDZ, len) != 0 && + memcmp(type, VDEV_TYPE_INDIRECT, len) != 0 && + memcmp(type, VDEV_TYPE_REPLACING, len) != 0) { printf("ZFS: can only boot from disk, mirror, raidz1, " "raidz2 and raidz3 vdevs\n"); return (EIO); } - if (strcmp(type, VDEV_TYPE_MIRROR) == 0) + if (memcmp(type, VDEV_TYPE_MIRROR, len) == 0) vdev = vdev_create(guid, vdev_mirror_read); - else if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) + else if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) vdev = vdev_create(guid, vdev_raidz_read); - else if (strcmp(type, VDEV_TYPE_REPLACING) == 0) + else if (memcmp(type, VDEV_TYPE_REPLACING, len) == 0) vdev = vdev_create(guid, vdev_replacing_read); - else if (strcmp(type, VDEV_TYPE_INDIRECT) == 0) { + else if (memcmp(type, VDEV_TYPE_INDIRECT, len) == 0) { vdev_indirect_config_t *vic; vdev = vdev_create(guid, vdev_indirect_read); @@ -1153,15 +1158,15 @@ vdev_init(uint64_t guid, const unsigned char *nvlist, vdev_t **vdevp) nvlist_find(nvlist, ZPOOL_CONFIG_INDIRECT_OBJECT, DATA_TYPE_UINT64, - NULL, &vic->vic_mapping_object); + NULL, &vic->vic_mapping_object, NULL); nvlist_find(nvlist, ZPOOL_CONFIG_INDIRECT_BIRTHS, DATA_TYPE_UINT64, - NULL, &vic->vic_births_object); + NULL, &vic->vic_births_object, NULL); nvlist_find(nvlist, ZPOOL_CONFIG_PREV_INDIRECT_VDEV, DATA_TYPE_UINT64, - NULL, &vic->vic_prev_indirect_vdev); + NULL, &vic->vic_prev_indirect_vdev, NULL); } } else { vdev = vdev_create(guid, vdev_disk_read); @@ -1173,51 +1178,67 @@ vdev_init(uint64_t guid, const unsigned char *nvlist, vdev_t **vdevp) vdev_set_initial_state(vdev, nvlist); vdev->v_id = id; if (nvlist_find(nvlist, ZPOOL_CONFIG_ASHIFT, - DATA_TYPE_UINT64, NULL, &ashift) == 0) + DATA_TYPE_UINT64, NULL, &ashift, NULL) == 0) vdev->v_ashift = ashift; if (nvlist_find(nvlist, ZPOOL_CONFIG_ASIZE, - DATA_TYPE_UINT64, NULL, &asize) == 0) { + DATA_TYPE_UINT64, NULL, &asize, NULL) == 0) { vdev->v_psize = asize + VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE; } if (nvlist_find(nvlist, ZPOOL_CONFIG_NPARITY, - DATA_TYPE_UINT64, NULL, &nparity) == 0) + DATA_TYPE_UINT64, NULL, &nparity, NULL) == 0) vdev->v_nparity = nparity; if (nvlist_find(nvlist, ZPOOL_CONFIG_PATH, - DATA_TYPE_STRING, NULL, &path) == 0) { - if (strncmp(path, "/dev/dsk/", 9) == 0) - path += 9; - vdev->v_name = strdup(path); + DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { + char prefix[] = "/dev/dsk/"; + + len = strlen(prefix); + if (len < pathlen && memcmp(path, prefix, len) == 0) { + path += len; + pathlen -= len; + } + name = malloc(pathlen + 1); + if (name != NULL) { + bcopy(path, name, pathlen); + name[pathlen] = '\0'; + } + vdev->v_name = name; + vdev->v_phys_path = NULL; + vdev->v_devid = NULL; if (nvlist_find(nvlist, ZPOOL_CONFIG_PHYS_PATH, - DATA_TYPE_STRING, NULL, &path) == 0) { - vdev->v_phys_path = strdup(path); - } else { - vdev->v_phys_path = NULL; + DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { + name = malloc(pathlen + 1); + if (name != NULL) { + bcopy(path, name, pathlen); + name[pathlen] = '\0'; + vdev->v_phys_path = name; + } } if (nvlist_find(nvlist, ZPOOL_CONFIG_DEVID, - DATA_TYPE_STRING, NULL, &path) == 0) { - vdev->v_devid = strdup(path); - } else { - vdev->v_devid = NULL; + DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { + name = malloc(pathlen + 1); + if (name != NULL) { + bcopy(path, name, pathlen); + name[pathlen] = '\0'; + vdev->v_devid = name; + } } } else { - char *name; - name = NULL; - if (strcmp(type, "raidz") == 0) { + if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) { if (vdev->v_nparity < 1 || vdev->v_nparity > 3) { printf("ZFS: invalid raidz parity: %d\n", vdev->v_nparity); return (EIO); } - (void) asprintf(&name, "%s%d-%" PRIu64, type, + (void) asprintf(&name, "%.*s%d-%" PRIu64, len, type, vdev->v_nparity, id); } else { - (void) asprintf(&name, "%s-%" PRIu64, type, id); + (void) asprintf(&name, "%.*s-%" PRIu64, len, type, id); } vdev->v_name = name; } @@ -1321,13 +1342,13 @@ vdev_from_nvlist(spa_t *spa, uint64_t top_guid, const unsigned char *nvlist) /* Add children if there are any. */ rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, - &nkids, &kids); + &nkids, &kids, NULL); if (rc == 0) { for (int i = 0; i < nkids; i++) { uint64_t guid; rc = nvlist_find(kids, ZPOOL_CONFIG_GUID, - DATA_TYPE_UINT64, NULL, &guid); + DATA_TYPE_UINT64, NULL, &guid, NULL); if (rc != 0) return (rc); rc = vdev_init(guid, kids, &vdev); @@ -1358,11 +1379,11 @@ vdev_init_from_label(spa_t *spa, const unsigned char *nvlist) const unsigned char *vdevs; if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, - NULL, &pool_guid) || + NULL, &pool_guid, NULL) || nvlist_find(nvlist, ZPOOL_CONFIG_TOP_GUID, DATA_TYPE_UINT64, - NULL, &top_guid) || + NULL, &top_guid, NULL) || nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, - NULL, &vdevs)) { + NULL, &vdevs, NULL)) { printf("ZFS: can't find vdev details\n"); return (ENOENT); } @@ -1429,13 +1450,13 @@ vdev_update_from_nvlist(uint64_t top_guid, const unsigned char *nvlist) /* Update children if there are any. */ rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, - &nkids, &kids); + &nkids, &kids, NULL); if (rc == 0) { for (int i = 0; i < nkids; i++) { uint64_t guid; rc = nvlist_find(kids, ZPOOL_CONFIG_GUID, - DATA_TYPE_UINT64, NULL, &guid); + DATA_TYPE_UINT64, NULL, &guid, NULL); if (rc != 0) break; @@ -1460,11 +1481,11 @@ vdev_init_from_nvlist(spa_t *spa, const unsigned char *nvlist) int rc, nkids; if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, - NULL, &pool_guid) || + NULL, &pool_guid, NULL) || nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_CHILDREN, DATA_TYPE_UINT64, - NULL, &vdev_children) || + NULL, &vdev_children, NULL) || nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, - NULL, &vdevs)) { + NULL, &vdevs, NULL)) { printf("ZFS: can't find vdev details\n"); return (ENOENT); } @@ -1476,7 +1497,7 @@ vdev_init_from_nvlist(spa_t *spa, const unsigned char *nvlist) spa->spa_root_vdev->v_nchildren = vdev_children; rc = nvlist_find(vdevs, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, - &nkids, &kids); + &nkids, &kids, NULL); /* * MOS config has at least one child for root vdev. @@ -1489,7 +1510,7 @@ vdev_init_from_nvlist(spa_t *spa, const unsigned char *nvlist) vdev_t *vdev; rc = nvlist_find(kids, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, - NULL, &guid); + NULL, &guid, NULL); if (rc != 0) break; vdev = vdev_find(guid); @@ -1837,7 +1858,7 @@ vdev_label_read_config(vdev_t *vd, uint64_t txg) nvlist = (const unsigned char *) label->vp_nvlist + 4; error = nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, - DATA_TYPE_UINT64, NULL, &label_txg); + DATA_TYPE_UINT64, NULL, &label_txg, NULL); if (error != 0 || label_txg == 0) { memcpy(nvl, nvlist, nvl_size); goto done; @@ -1852,7 +1873,7 @@ vdev_label_read_config(vdev_t *vd, uint64_t txg) * because we can get bad value from BIOS. */ if (nvlist_find(nvlist, ZPOOL_CONFIG_ASIZE, - DATA_TYPE_UINT64, NULL, &asize) == 0) { + DATA_TYPE_UINT64, NULL, &asize, NULL) == 0) { vd->v_psize = asize + VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE; } @@ -1905,7 +1926,7 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) uint64_t pool_txg, pool_guid; const char *pool_name; const unsigned char *features; - int rc; + int rc, namelen; /* * Load the vdev label and figure out which @@ -1926,7 +1947,7 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) return (EIO); if (nvlist_find(nvlist, ZPOOL_CONFIG_VERSION, DATA_TYPE_UINT64, - NULL, &val) != 0) { + NULL, &val, NULL) != 0) { free(nvlist); return (EIO); } @@ -1940,14 +1961,14 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) /* Check ZFS features for read */ if (nvlist_find(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ, - DATA_TYPE_NVLIST, NULL, &features) == 0 && + DATA_TYPE_NVLIST, NULL, &features, NULL) == 0 && nvlist_check_features_for_read(features) != 0) { free(nvlist); return (EIO); } if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_STATE, DATA_TYPE_UINT64, - NULL, &val) != 0) { + NULL, &val, NULL) != 0) { free(nvlist); return (EIO); } @@ -1959,11 +1980,11 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) } if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64, - NULL, &pool_txg) != 0 || + NULL, &pool_txg, NULL) != 0 || nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, - NULL, &pool_guid) != 0 || + NULL, &pool_guid, NULL) != 0 || nvlist_find(nvlist, ZPOOL_CONFIG_POOL_NAME, DATA_TYPE_STRING, - NULL, &pool_name) != 0) { + NULL, &pool_name, &namelen) != 0) { /* * Cache and spare devices end up here - just ignore * them. @@ -1977,9 +1998,19 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) */ spa = spa_find_by_guid(pool_guid); if (spa == NULL) { + char *name; + nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_CHILDREN, - DATA_TYPE_UINT64, NULL, &vdev_children); - spa = spa_create(pool_guid, pool_name); + DATA_TYPE_UINT64, NULL, &vdev_children, NULL); + name = malloc(namelen + 1); + if (name == NULL) { + free(nvlist); + return (ENOMEM); + } + bcopy(pool_name, name, namelen); + name[namelen] = '\0'; + spa = spa_create(pool_guid, name); + free(name); if (spa == NULL) { free(nvlist); return (ENOMEM); @@ -1996,7 +2027,7 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) * disks etc). */ if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, - NULL, &guid) != 0) { + NULL, &guid, NULL) != 0) { free(nvlist); return (EIO); } diff --git a/usr/src/cmd/sgs/error/common/errorinput.c b/usr/src/cmd/sgs/error/common/errorinput.c index eae36879aa..1f02ab6923 100644 --- a/usr/src/cmd/sgs/error/common/errorinput.c +++ b/usr/src/cmd/sgs/error/common/errorinput.c @@ -25,8 +25,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <ctype.h> #include <string.h> @@ -129,7 +127,7 @@ erroradd(int errorlength, char **errorv, Errorclass errorclass, #ifdef FULLDEBUG if (errorclass != C_TRUE) printf("The 2nd word, \"%s\" is not a number.\n", - errorv[1]); + errorv[1]); #endif } if (errorlength > 0) { @@ -143,10 +141,10 @@ erroradd(int errorlength, char **errorv, Errorclass errorclass, newerror->error_s_class = errorsubclass; switch (newerror->error_e_class = discardit(newerror)) { case C_SYNC: nsyncerrors++; break; - case C_DISCARD: ndiscard++; break; + case C_DISCARD: ndiscard++; break; case C_NULLED: nnulled++; break; case C_NONSPEC: nnonspec++; break; - case C_THISFILE: nthisfile++; break; + case C_THISFILE: nthisfile++; break; case C_TRUE: ntrue++; break; case C_UNKNOWN: nunknown++; break; case C_IGNORE: nignore++; break; @@ -315,7 +313,7 @@ Errorclass lint0(void) { char **nwordv; - char *line, *file; + char *line, *file; /* * Attempt a match for the new lint style normal compiler * error messages, of the form @@ -453,8 +451,8 @@ f77(void) return (C_UNKNOWN); if ((lastchar(wordv[6]) == ':') && ((wordvcmp(wordv+1, 3, F77_fatal) == 0) || - (wordvcmp(wordv+1, 3, F77_error) == 0) || - (wordvcmp(wordv+1, 3, F77_warning) == 0))) { + (wordvcmp(wordv+1, 3, F77_error) == 0) || + (wordvcmp(wordv+1, 3, F77_warning) == 0))) { language = INF77; nwordv = wordvsplice(2, wordc, wordv+1); nwordv[0] = wordv[6]; @@ -564,10 +562,10 @@ mod2(void) */ if (((strcmp(wordv[1], "!!!") == 0) || /* early version */ (strcmp(wordv[1], "File") == 0)) && /* later version */ - (lastchar(wordv[2]) == ',') && /* file name */ - (strcmp(wordv[3], "line") == 0) && - (isdigit(firstchar(wordv[4]))) && /* line number */ - (lastchar(wordv[4]) == ':')) { /* line number */ + (lastchar(wordv[2]) == ',') && /* file name */ + (strcmp(wordv[3], "line") == 0) && + (isdigit(firstchar(wordv[4]))) && /* line number */ + (lastchar(wordv[4]) == ':')) { /* line number */ clob_last(wordv[2], '\0'); /* drop last , on file name */ clob_last(wordv[4], '\0'); /* drop last : on line number */ wordv[3] = wordv[2]; /* file name on top of "line" */ @@ -596,10 +594,10 @@ sunf77(void) (strcmp(wordv[2], "line") == 0) && (isdigit(firstchar(wordv[3]))) && (lastchar(wordv[3]) == ':') && - ((strcmp(wordv[4], "Error:") == 0) || - (strcmp(wordv[4], "Warning:") == 0) || - ((strcmp(wordv[4], "ANSI") == 0) && - (strcmp(wordv[5], "extension:") == 0)))) { + ((strcmp(wordv[4], "Error:") == 0) || + (strcmp(wordv[4], "Warning:") == 0) || + ((strcmp(wordv[4], "ANSI") == 0) && + (strcmp(wordv[5], "extension:") == 0)))) { clob_last(wordv[1], '\0'); /* drop last , */ clob_last(wordv[1], '\0'); /* drop last " */ wordv[1]++; /* drop first " */ diff --git a/usr/src/cmd/sgs/error/common/errorsubr.c b/usr/src/cmd/sgs/error/common/errorsubr.c index e2d0828a4f..17bc104c01 100644 --- a/usr/src/cmd/sgs/error/common/errorsubr.c +++ b/usr/src/cmd/sgs/error/common/errorsubr.c @@ -101,10 +101,12 @@ int position(char *string, char ch) { int i; - if (string) - for (i = 1; *string; string++, i++) { - if (*string == ch) - return (i); + + if (string) { + for (i = 1; *string; string++, i++) { + if (*string == ch) + return (i); + } } return (-1); } @@ -116,13 +118,14 @@ substitute(char *string, char chold, char chnew) { char *cp = string; - if (cp) - while (*cp) { - if (*cp == chold) { - *cp = chnew; - break; + if (cp) { + while (*cp) { + if (*cp == chold) { + *cp = chnew; + break; + } + cp++; } - cp++; } return (string); } @@ -283,7 +286,7 @@ wordvprint(FILE *fyle, int wordc, char *wordv[]) void wordvbuild(char *string, int *r_wordc, char ***r_wordv) { - char *cp; + char *cp; char *saltedbuffer; char **wordv; int wordcount; diff --git a/usr/src/cmd/sgs/error/common/errortouch.c b/usr/src/cmd/sgs/error/common/errortouch.c index 6773fc0476..fcc3ce9499 100644 --- a/usr/src/cmd/sgs/error/common/errortouch.c +++ b/usr/src/cmd/sgs/error/common/errortouch.c @@ -164,14 +164,14 @@ filenames(int nfiles, Eptr **files) if (nfiles) { someerrors++; (void) fprintf(stdout, terse - ? "%d file%s" - : "%d file%s contain%s errors", - nfiles, plural(nfiles), verbform(nfiles)); + ? "%d file%s" + : "%d file%s contain%s errors", + nfiles, plural(nfiles), verbform(nfiles)); if (!terse) { FILEITERATE(fi, 1) { (void) fprintf(stdout, "%s\"%s\" (%d)", - sep, (*files[fi])->error_text[0], - files[fi+1] - files[fi]); + sep, (*files[fi])->error_text[0], + files[fi+1] - files[fi]); sep = ", "; } } @@ -201,10 +201,10 @@ nopertain(Eptr **files) someerrors++; if (terse) { (void) fprintf(stdout, "\t%d %s errors NOT PRINTED\n", - class_count[type], class_table[type]); + class_count[type], class_table[type]); } else { (void) fprintf(stdout, "\n\t%d %s errors follow\n", - class_count[type], class_table[type]); + class_count[type], class_table[type]); EITERATE(erpp, files, 0) { errorp = *erpp; if (errorp->error_e_class == type) { @@ -232,9 +232,9 @@ touchfiles(int nfiles, Eptr **files, int *r_edargc, char ***r_edargv) name = (*files[fi])->error_text[0]; spread = files[fi+1] - files[fi]; (void) fprintf(stdout, terse - ? "\"%s\" has %d error%s, " - : "\nFile \"%s\" has %d error%s.\n", - name, spread, plural(spread)); + ? "\"%s\" has %d error%s, " + : "\nFile \"%s\" has %d error%s.\n", + name, spread, plural(spread)); /* * First, iterate through all error messages in this file * to see how many of the error messages really will @@ -336,9 +336,9 @@ settotouch(char *name) if (query) { switch (touchstatus = inquire(terse - ? "Touch? " - : "Do you want to touch file \"%s\"? ", - name)) { + ? "Touch? " + : "Do you want to touch file \"%s\"? ", + name)) { case Q_NO: case Q_no: return (dest); @@ -351,23 +351,23 @@ settotouch(char *name) case F_NOTREAD: dest = TOSTDOUT; (void) fprintf(stdout, terse - ? "\"%s\" unreadable\n" - : "File \"%s\" is unreadable\n", - name); + ? "\"%s\" unreadable\n" + : "File \"%s\" is unreadable\n", + name); break; case F_NOTWRITE: dest = TOSTDOUT; (void) fprintf(stdout, terse - ? "\"%s\" unwritable\n" - : "File \"%s\" is unwritable\n", - name); + ? "\"%s\" unwritable\n" + : "File \"%s\" is unwritable\n", + name); break; case F_NOTEXIST: dest = TOSTDOUT; (void) fprintf(stdout, terse ? "\"%s\" not found\n" : - "Can't find file \"%s\" to insert error " - "messages into.\n", + "Can't find file \"%s\" to insert error " + "messages into.\n", name); break; default: @@ -389,9 +389,9 @@ diverterrors(char *name, int dest, Eptr **files, int ix, if ((nerrors != nterrors) && (!previewed)) { (void) fprintf(stdout, terse - ? "Uninserted errors\n" - : ">>Uninserted errors for file \"%s\" follow.\n", - name); + ? "Uninserted errors\n" + : ">>Uninserted errors for file \"%s\" follow.\n", + name); } EITERATE(erpp, files, ix) { @@ -422,7 +422,7 @@ oktotouch(char *filename) extern char *suffixlist; char *src; char *pat; - char *osrc; + char *osrc; pat = suffixlist; if (pat == 0) @@ -558,8 +558,8 @@ text(Eptr p, boolean use_all) (void) fputs(lang_table[p->error_language].lang_incomment, n_touchedfile); (void) fprintf(n_touchedfile, "%d [%s] ", - p->error_line, - lang_table[p->error_language].lang_name); + p->error_line, + lang_table[p->error_language].lang_name); wordvprint(n_touchedfile, p->error_lgtext-offset, p->error_text+offset); (void) fputs(lang_table[p->error_language].lang_outcomment, n_touchedfile); @@ -605,8 +605,8 @@ writetouched(int overwrite) tmpfile = NULL; if ((localfile = fopen(o_name, "w")) == NULL) { (void) fprintf(stderr, - "%s: Can't open file \"%s\" to overwrite.\n", - processname, o_name); + "%s: Can't open file \"%s\" to overwrite.\n", + processname, o_name); botch++; } if ((tmpfile = fopen(n_name, "r")) == NULL) { diff --git a/usr/src/cmd/sgs/rtld/common/a.out.c b/usr/src/cmd/sgs/rtld/common/a.out.c index 6ea37918ad..693b4f59bc 100644 --- a/usr/src/cmd/sgs/rtld/common/a.out.c +++ b/usr/src/cmd/sgs/rtld/common/a.out.c @@ -356,7 +356,7 @@ aout_find_com(struct nlist *sp, const char *name) (void) strcpy(rs->rtc_sp->n_un.n_name, name); rs->rtc_sp->n_type = N_COMM; if ((rs->rtc_sp->n_value = - (long)calloc(rs->rtc_sp->n_value, 1)) == NULL) + (long)calloc(rs->rtc_sp->n_value, 1)) == (long)NULL) return (NULL); return (rs->rtc_sp); } @@ -419,7 +419,7 @@ aout_findsb(const char *aname, Rt_map *lmp, int flag) if (*name++ == '\0') return (sp); /* found */ } - if (p->next == NULL) + if (p->next == 0) return (NULL); /* not found */ else continue; diff --git a/usr/src/cmd/sgs/rtld/common/cache_a.out.c b/usr/src/cmd/sgs/rtld/common/cache_a.out.c index 0afdcdb5e5..994edaa2fd 100644 --- a/usr/src/cmd/sgs/rtld/common/cache_a.out.c +++ b/usr/src/cmd/sgs/rtld/common/cache_a.out.c @@ -38,16 +38,16 @@ #include "_rtld.h" #include "msg.h" -static int stol(); -static int rest_ok(); -static int verscmp(); -static void fix_lo(); -static int extract_name(); -static int hash(); +static int stol(char *, char, char **, int *); +static int rest_ok(char *); +static int verscmp(const char *, const char *); +static void fix_lo(struct db *); +static int extract_name(char **); +static int hash(char *, int, int); -static struct link_object *get_lo(); -static struct dbd *new_dbd(); -static struct db *find_so(); +static struct link_object *get_lo(struct db *, char *, int, int, int); +static struct dbd *new_dbd(struct dbd **, struct db *); +static struct db *find_so(const char *); #define SKIP_DOT(str) ((*str == '.') ? ++str : str) #define EMPTY(str) ((str == NULL) || (*str == '\0')) @@ -62,9 +62,7 @@ static struct dbd *dbd_head = NULL; /* head of data bases */ * but the highest minor number */ char * -ask_db(dbp, file) - struct db *dbp; - const char *file; +ask_db(struct db *dbp, const char *file) { char *libname, *n; char *mnp; @@ -82,7 +80,7 @@ ask_db(dbp, file) if ((libname = malloc(liblen + 1)) == 0) return (NULL); (void) strncpy(libname, n, liblen); - libname[liblen] = NULL; + libname[liblen] = '\0'; if (strncmp(MSG_ORIG(MSG_FIL_DOTSODOT), (n + liblen), MSG_FIL_DOTSODOT_SIZE)) @@ -245,7 +243,7 @@ find_so(const char *ds) */ index = hash(cp, cplen, m); ep = &(dbp->db_hash[index]); - if (ep->dbe_lop == NULL) { + if (ep->dbe_lop == 0) { ep->dbe_lop = (long)get_lo(dbp, cp, cplen, m, to_min); /* LINTED */ @@ -278,7 +276,7 @@ find_so(const char *ds) dp->d_name); break; } - if (ep->dbe_next == NULL) { + if (ep->dbe_next == 0) { ep->dbe_next = RELPTR(dbp, calloc(sizeof (struct dbe), 1)); /* LINTED */ @@ -302,14 +300,15 @@ find_so(const char *ds) /* * Allocate and fill in the fields for a link_object + * Arguments: + * struct db *dbp; data base + * char *cp; ptr. to X of libX + * int cplen; length of X + * int m; major version + * int n; index to minor version */ static struct link_object * -get_lo(dbp, cp, cplen, m, n) - struct db *dbp; /* data base */ - char *cp; /* ptr. to X of libX */ - int cplen; /* length of X */ - int m; /* major version */ - int n; /* index to minor version */ +get_lo(struct db *dbp, char *cp, int cplen, int m, int n) { struct link_object *lop; /* link_object to be returned */ struct link_object *tlop; /* working copy of the above */ @@ -353,8 +352,7 @@ get_lo(dbp, cp, cplen, m, n) * length of X */ static int -extract_name(name) - char **name; +extract_name(char **name) { char *ls; /* string after LIB root */ char *dp; /* string before first delimiter */ @@ -375,8 +373,7 @@ extract_name(name) * but only one will be chosen. */ static void -fix_lo(dbp) - struct db *dbp; +fix_lo(struct db *dbp) { int i; /* loop temporary */ int dirlen = strlen(&AP(dbp)[dbp->db_name]); @@ -408,11 +405,12 @@ fix_lo(dbp) /* * Allocate a new dbd, append it after dbdpp and set the dbd_dbp to dbp. + * Arguments: + * struct dbd **dbdpp; insertion point + * struct db *dbp; db associated with this dbd */ static struct dbd * -new_dbd(dbdpp, dbp) - struct dbd **dbdpp; /* insertion point */ - struct db *dbp; /* db associated with this dbd */ +new_dbd(struct dbd **dbdpp, struct db *dbp) { struct dbd *dbdp; /* working dbd ptr. */ @@ -426,12 +424,13 @@ new_dbd(dbdpp, dbp) /* * Calculate hash index for link object. * This is based on X.major from libX.so.major.minor. + * Arguments: + * char *np; X of libX + * int nchrs; no of chrs. to hash on + * int m; the major version */ static int -hash(np, nchrs, m) - char *np; /* X of libX */ - int nchrs; /* no of chrs. to hash on */ - int m; /* the major version */ +hash(char *np, int nchrs, int m) { int h; /* for loop counter */ char *cp; /* working (char *) ptr */ @@ -447,8 +446,7 @@ hash(np, nchrs, m) * Test whether the string is of digit[.digit]* format */ static int -rest_ok(str) - char *str; /* input string */ +rest_ok(char *str) { int dummy; /* integer place holder */ int legal = 1; /* return flag */ @@ -509,14 +507,15 @@ verscmp(const char *c1p, const char *c2p) * as a decimal digit. It stops interpreting when it reaches a delimiter or * when character does not represent a digit. In the first case it returns * success and the latter failure. + * Arguments: + * char *cp; ptr to input string + * char delimit; delimiter + * char **ptr; left pointing to next del. or + * illegal character + * int *i; digit that the string represents */ static int -stol(cp, delimit, ptr, i) - char *cp; /* ptr to input string */ - char delimit; /* delimiter */ - char **ptr; /* left pointing to next del. or */ - /* illegal character */ - int *i; /* digit that the string represents */ +stol(char *cp, char delimit, char **ptr, int *i) { int c = 0; /* current char */ int n = 0; /* working copy of i */ diff --git a/usr/src/pkg/manifests/system-test-ostest.mf b/usr/src/pkg/manifests/system-test-ostest.mf index e7de55cfe6..1abad62de8 100644 --- a/usr/src/pkg/manifests/system-test-ostest.mf +++ b/usr/src/pkg/manifests/system-test-ostest.mf @@ -13,6 +13,7 @@ # Copyright (c) 2012, 2016 by Delphix. All rights reserved. # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2020 Joyent, Inc. +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. # set name=pkg.fmri value=pkg:/system/test/ostest@$(PKGVERS) @@ -91,6 +92,8 @@ file path=opt/os-tests/tests/sockfs/conn mode=0555 file path=opt/os-tests/tests/sockfs/dgram mode=0555 file path=opt/os-tests/tests/sockfs/drop_priv mode=0555 file path=opt/os-tests/tests/sockfs/nosignal mode=0555 +file path=opt/os-tests/tests/sockfs/rights.32 mode=0555 +file path=opt/os-tests/tests/sockfs/rights.64 mode=0555 file path=opt/os-tests/tests/sockfs/sockpair mode=0555 file path=opt/os-tests/tests/spoof-ras mode=0555 file path=opt/os-tests/tests/stress/dladm-kstat mode=0555 diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run index 322c26d6ff..bcb8468ec5 100644 --- a/usr/src/test/os-tests/runfiles/default.run +++ b/usr/src/test/os-tests/runfiles/default.run @@ -12,6 +12,7 @@ # # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright 2020 Joyent, Inc. +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. # [DEFAULT] @@ -72,7 +73,8 @@ tests = ['runtests.32', 'runtests.64'] [/opt/os-tests/tests/sockfs] user = root -tests = ['conn', 'dgram', 'drop_priv', 'nosignal', 'sockpair'] +tests = ['conn', 'dgram', 'drop_priv', 'nosignal', 'rights.32', 'rights.64', + 'sockpair'] [/opt/os-tests/tests/pf_key] user = root diff --git a/usr/src/test/os-tests/tests/sockfs/Makefile b/usr/src/test/os-tests/tests/sockfs/Makefile index 638250a400..267c8bbe4e 100644 --- a/usr/src/test/os-tests/tests/sockfs/Makefile +++ b/usr/src/test/os-tests/tests/sockfs/Makefile @@ -13,16 +13,18 @@ # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright 2017 Gordon W. Ross # Copyright (c) 2018, Joyent, Inc. +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. # include $(SRC)/cmd/Makefile.cmd include $(SRC)/test/Makefile.com -PROG = conn dgram drop_priv nosignal sockpair - -LINTS = $(PROGS:%=%.ln) +PROG = conn dgram drop_priv nosignal sockpair \ + rights.32 rights.64 LDLIBS += -lsocket +LDLIBS64 += -lsocket + CSTD = $(CSTD_GNU99) CPPFLAGS += -D_XOPEN_SOURCE=600 -D__EXTENSIONS__ @@ -30,7 +32,8 @@ CPPFLAGS += -D_XOPEN_SOURCE=600 -D__EXTENSIONS__ SMOFF += all_func_returns nosignal := LDLIBS += -lnsl -nosignal.ln := LDLIBS += -lnsl +rights.32 := LDLIBS += -lproc +rights.64 := LDLIBS64 += -lproc ROOTOPTPKG = $(ROOT)/opt/os-tests TESTDIR = $(ROOTOPTPKG)/tests/sockfs @@ -42,8 +45,6 @@ all: $(PROG) install: $(CMDS) -lint: $(LINTS) - clobber: clean -$(RM) $(PROG) @@ -51,11 +52,16 @@ clean: $(CMDS): $(TESTDIR) $(PROG) -%.ln : %.c - $(LINT.c) $*.c $(UTILS) $(LDLIBS) - $(TESTDIR): $(INS.dir) $(TESTDIR)/%: % $(INS.file) + +%.64: %.c + $(LINK64.c) -o $@ $< $(LDLIBS64) + $(POST_PROCESS) + +%.32: %.c + $(LINK.c) -o $@ $< $(LDLIBS) + $(POST_PROCESS) diff --git a/usr/src/test/os-tests/tests/sockfs/rights.c b/usr/src/test/os-tests/tests/sockfs/rights.c new file mode 100644 index 0000000000..97987d62c5 --- /dev/null +++ b/usr/src/test/os-tests/tests/sockfs/rights.c @@ -0,0 +1,700 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + */ + +/* + * Test file descriptor passing via SCM_RIGHTS, and in particular what happens + * on message truncation in terms of the represented size of the data in the + * control message. Ensure that no file descriptors are leaked - the kernel + * must close any that would not fit in the available buffer space and the + * userland application must close the rest. + */ + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include <libproc.h> + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <assert.h> +#include <alloca.h> +#include <err.h> + +static boolean_t debug; + +typedef struct cmsg_test { + char *name; /* Name of the test */ + uint_t send; /* Number of FDs to send */ + uint_t recv; /* Size receive buffer for this number of FDs */ + size_t predata; /* Prepend dummy cmsg of this size */ + int bufsize; /* Explicitly set receive buffer size. */ + /* Overrides 'recv' if non-zero */ + uint_t x_controllen; /* Expected received msg_controllen */ + uint_t x_cmsg_datalen; /* Expected received cmsg data length */ + uint32_t x_flags; /* Expected received msf_flags */ +} cmsg_test_t; + +static cmsg_test_t tests[] = { + { + .name = "send 1, recv 1", + .send = 1, + .recv = 1, + .predata = 0, + .bufsize = 0, + .x_controllen = 16, + .x_cmsg_datalen = 4, + .x_flags = 0, + }, + { + .name = "send 10, recv 10", + .send = 10, + .recv = 10, + .predata = 0, + .bufsize = 0, + .x_controllen = 52, + .x_cmsg_datalen = 40, + .x_flags = 0, + }, + { + .name = "send 2, recv 1", + .send = 2, + .recv = 1, + .predata = 0, + .bufsize = 0, + .x_controllen = 16, + .x_cmsg_datalen = 4, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, buffer 5", + .send = 2, + .recv = 1, + .predata = 0, + .bufsize = sizeof (int) * 2 - 3, + .x_controllen = 17, + .x_cmsg_datalen = 5, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, buffer 6", + .send = 2, + .recv = 1, + .predata = 0, + .bufsize = sizeof (int) * 2 - 2, + .x_controllen = 18, + .x_cmsg_datalen = 6, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, buffer 7", + .send = 2, + .recv = 1, + .predata = 0, + .bufsize = sizeof (int) * 2 - 1, + .x_controllen = 19, + .x_cmsg_datalen = 7, + .x_flags = MSG_CTRUNC, + }, + + /* Tests where there is no room allowed for data */ + + { + .name = "send 2, recv 0, hdronly", + .send = 2, + .recv = 0, + .predata = 0, + .bufsize = 0, + .x_controllen = 12, + .x_cmsg_datalen = 0, + .x_flags = MSG_CTRUNC, + }, + + { + .name = "send 2, recv 0, hdr - 1", + .send = 2, + .recv = 0, + .predata = 0, + .bufsize = -1, + .x_controllen = 11, + .x_cmsg_datalen = 0, + .x_flags = MSG_CTRUNC, + }, + + { + .name = "send 2, recv 0, hdr - 5", + .send = 2, + .recv = 0, + .predata = 0, + .bufsize = -5, + .x_controllen = 7, + .x_cmsg_datalen = 0, + .x_flags = MSG_CTRUNC, + }, + + /* Tests where SCM_RIGHTS is not the first message */ + + { + .name = "send 1, recv 1, pre 8", + .send = 1, + .recv = 1, + .predata = 8, + .bufsize = 0, + .x_controllen = 36, + .x_cmsg_datalen = 4, + .x_flags = 0, + }, + { + .name = "send 1, recv 1, pre 7", + .send = 1, + .recv = 1, + .predata = 7, + .bufsize = 0, + .x_controllen = 35, + .x_cmsg_datalen = 4, + .x_flags = 0, + }, + { + .name = "send 1, recv 1, pre 6", + .send = 1, + .recv = 1, + .predata = 6, + .bufsize = 0, + .x_controllen = 34, + .x_cmsg_datalen = 4, + .x_flags = 0, + }, + { + .name = "send 1, recv 1, pre 5", + .send = 1, + .recv = 1, + .predata = 5, + .bufsize = 0, + .x_controllen = 33, + .x_cmsg_datalen = 4, + .x_flags = 0, + }, + + { + .name = "send 2, recv 1, pre 8", + .send = 2, + .recv = 1, + .predata = 8, + .bufsize = 0, + .x_controllen = 36, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 7", + .send = 2, + .recv = 1, + .predata = 7, + .bufsize = 0, + .x_controllen = 36, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 6", + .send = 2, + .recv = 1, + .predata = 6, + .bufsize = 0, + .x_controllen = 36, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 5", + .send = 2, + .recv = 1, + .predata = 5, + .bufsize = 0, + .x_controllen = 36, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 4", + .send = 2, + .recv = 1, + .predata = 4, + .bufsize = 0, + .x_controllen = 32, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 3", + .send = 2, + .recv = 1, + .predata = 3, + .bufsize = 0, + .x_controllen = 32, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 2", + .send = 2, + .recv = 1, + .predata = 2, + .bufsize = 0, + .x_controllen = 32, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 1", + .send = 2, + .recv = 1, + .predata = 1, + .bufsize = 0, + .x_controllen = 32, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + + { + .name = "send 2, recv 1, pre 8, buffer 5", + .send = 2, + .recv = 1, + .predata = 8, + .bufsize = sizeof (int) * 2 - 3, + .x_controllen = 37, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 8, buffer 6", + .send = 2, + .recv = 1, + .predata = 8, + .bufsize = sizeof (int) * 2 - 2, + .x_controllen = 38, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 2, recv 1, pre 8, buffer 7", + .send = 2, + .recv = 1, + .predata = 8, + .bufsize = sizeof (int) * 2 - 1, + .x_controllen = 39, + .x_cmsg_datalen = 8, + .x_flags = MSG_CTRUNC, + }, + { + .name = "send 10, recv 1, pre 8", + .send = 10, + .recv = 1, + .predata = 8, + .bufsize = 0, + .x_controllen = 36, + .x_cmsg_datalen = 24, + .x_flags = MSG_CTRUNC, + }, + + /* End of tests */ + + { + .name = NULL + } +}; + +static int sock = -1, testfd = -1, cfd = -1; +static int fdcount; + +static int +fdwalkcb(const prfdinfo_t *info, void *arg) +{ + if (!S_ISDIR(info->pr_mode) && info->pr_fd > 2 && + info->pr_fd != sock && info->pr_fd != testfd && + info->pr_fd != cfd) { + if (debug) { + fprintf(stderr, "%s: unexpected fd: %d\n", + (char *)arg, info->pr_fd); + } + fdcount++; + } + + return (0); + +} + +static void +check_fds(char *tag) +{ + fdcount = 0; + proc_fdwalk(getpid(), fdwalkcb, tag); +} + +static void +send_and_wait(pid_t pid, sigset_t *set, int osig, int isig) +{ + int sig; + + if (osig > 0) + kill(pid, osig); + + if (isig > 0) { + if (sigwait(set, &sig) != 0) { + err(EXIT_FAILURE, + "sigwait failed waiting for %d", isig); + } + if (sig == SIGINT) { + exit(1); + } + if (sig != isig) { + err(EXIT_FAILURE, + "sigwait returned unexpected signal %d", sig); + } + } +} + +static void +sendtest(cmsg_test_t *t) +{ + struct msghdr msg; + struct cmsghdr *cm; + struct iovec iov; + ssize_t nbytes; + char c = '*'; + int i, *p; + + bzero(&msg, sizeof (msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + iov.iov_base = &c; + iov.iov_len = sizeof (c); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_flags = 0; + + msg.msg_controllen = CMSG_SPACE(sizeof (int) * t->send); + + if (t->predata > 0) { + /* A dummy cmsg will be inserted at the head of the data */ + msg.msg_controllen += CMSG_SPACE(t->predata); + } + + msg.msg_control = alloca(msg.msg_controllen); + bzero(msg.msg_control, msg.msg_controllen); + + cm = CMSG_FIRSTHDR(&msg); + + if (t->predata > 0) { + /* Insert the dummy cmsg */ + cm->cmsg_len = CMSG_LEN(t->predata); + cm->cmsg_level = SOL_SOCKET; + cm->cmsg_type = 0; + cm = CMSG_NXTHDR(&msg, cm); + } + + cm->cmsg_len = CMSG_LEN(sizeof (int) * t->send); + cm->cmsg_level = SOL_SOCKET; + cm->cmsg_type = SCM_RIGHTS; + + p = (int *)CMSG_DATA(cm); + for (i = 0; i < t->send; i++) { + int s = dup(testfd); + if (s == -1) + err(EXIT_FAILURE, "dup()"); + *p++ = s; + } + + if (debug) + printf("Sending: controllen=%u\n", msg.msg_controllen); + + nbytes = sendmsg(cfd, &msg, 0); + if (nbytes == -1) + err(EXIT_FAILURE, "sendmsg()"); + + p = (int *)CMSG_DATA(cm); + for (i = 0; i < t->send; i++) + (void) close(*p++); +} + +static int +server(const char *sockpath, pid_t pid) +{ + struct sockaddr_un addr; + sigset_t set; + cmsg_test_t *t; + + sigemptyset(&set); + sigaddset(&set, SIGUSR2); + sigaddset(&set, SIGINT); + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock == -1) + err(EXIT_FAILURE, "failed to create socket"); + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, sockpath, sizeof (addr.sun_path)); + if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) == -1) + err(EXIT_FAILURE, "bind failed"); + if (listen(sock, 0) == -1) + err(EXIT_FAILURE, "listen failed"); + + if ((testfd = open("/dev/null", O_RDONLY)) == -1) + err(EXIT_FAILURE, "/dev/null"); + + check_fds("server"); + + /* Signal the child to connect to the socket */ + send_and_wait(pid, &set, SIGUSR1, SIGUSR2); + + if ((cfd = accept(sock, NULL, 0)) == -1) + err(EXIT_FAILURE, "accept failed"); + + for (t = tests; t->name != NULL; t++) { + if (debug) + printf("\n>>> Starting test %s\n", t->name); + + sendtest(t); + check_fds("server"); + + send_and_wait(pid, &set, SIGUSR1, SIGUSR2); + } + + close(cfd); + close(testfd); + close(sock); + + return (0); +} + +static boolean_t pass; + +static void +check(uint_t actual, uint_t expected, char *tag) +{ + if (actual != expected) { + fprintf(stderr, " !!!: " + "%1$s = %2$u(%2$#x) (expected %3$u(%3$#x))\n", + tag, actual, expected); + pass = _B_FALSE; + } else if (debug) { + fprintf(stderr, " : " + "%1$s = %2$u(%2$#x)\n", + tag, actual); + } +} + +static boolean_t +recvtest(cmsg_test_t *t) +{ + struct msghdr msg; + struct cmsghdr *cm; + struct iovec iov; + size_t bufsize; + ssize_t nbytes; + char c = '*'; + + bzero(&msg, sizeof (msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + iov.iov_base = &c; + iov.iov_len = sizeof (c); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_flags = 0; + + /* + * If the test does not specify a receive buffer size, calculate one + * from the number of file descriptors to receive. + */ + if (t->bufsize == 0) { + bufsize = sizeof (int) * t->recv; + bufsize = CMSG_SPACE(bufsize); + } else { + /* + * Use the specific buffer size provided but add in + * space for the header + */ + bufsize = t->bufsize + CMSG_LEN(0); + } + + if (t->predata > 0) { + /* A dummy cmsg will be found at the head of the data */ + bufsize += CMSG_SPACE(t->predata); + } + + msg.msg_controllen = bufsize; + msg.msg_control = alloca(bufsize); + bzero(msg.msg_control, msg.msg_controllen); + + pass = _B_TRUE; + + if (debug) + printf("Receiving: controllen=%u, \n", msg.msg_controllen); + + nbytes = recvmsg(sock, &msg, 0); + + if (nbytes == -1) { + pass = _B_FALSE; + fprintf(stderr, "recvmsg() failed: %s\n", strerror(errno)); + goto out; + } + + if (debug) { + printf("Received: controllen=%u, flags=%#x\n", + msg.msg_controllen, msg.msg_flags); + } + + check(msg.msg_flags, t->x_flags, "msg_flags"); + check(msg.msg_controllen, t->x_controllen, "msg_controllen"); + + for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) { + void *data, *end; + + if (debug) { + printf(" >> : Got cmsg %x/%x - %u\n", cm->cmsg_level, + cm->cmsg_type, cm->cmsg_len); + } + + if (cm->cmsg_type != SCM_RIGHTS) { + if (debug) + printf(" : skipping cmsg\n"); + continue; + } + + check(cm->cmsg_len - CMSG_LEN(0), + t->x_cmsg_datalen, "cmsg_len"); + + /* Close any received file descriptors */ + data = CMSG_DATA(cm); + + if ((msg.msg_flags & MSG_CTRUNC) && + CMSG_NXTHDR(&msg, cm) == NULL) { + /* + * illumos did not previously adjust cmsg_len on + * truncation. This is the last cmsg, derive the + * length from msg_controllen + */ + end = msg.msg_control + msg.msg_controllen; + } else { + end = data + cm->cmsg_len - CMSG_LEN(0); + } + + while (data <= end - sizeof (int)) { + int *a = (int *)data; + if (debug) + printf(" : close(%d)\n", *a); + if (close(*a) == -1) { + pass = _B_FALSE; + fprintf(stderr, " !!!: " + "failed to close fd %d - %s\n", *a, + strerror(errno)); + } + data += sizeof (int); + } + } + +out: + + check_fds("client"); + check(fdcount, 0, "client descriptors"); + printf(" + : %s %s\n", pass ? "PASS" : "FAIL", t->name); + + return (pass); +} + +static int +client(const char *sockpath, pid_t pid) +{ + struct sockaddr_un addr; + sigset_t set; + cmsg_test_t *t; + int ret = 0; + + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + sigaddset(&set, SIGINT); + + send_and_wait(pid, &set, 0, SIGUSR1); + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock == -1) + err(EXIT_FAILURE, "failed to create socket"); + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, sockpath, sizeof (addr.sun_path)); + if (connect(sock, (struct sockaddr *)&addr, sizeof (addr)) == -1) + err(EXIT_FAILURE, "could not connect to server socket"); + + for (t = tests; t->name != NULL; t++) { + send_and_wait(pid, &set, SIGUSR2, SIGUSR1); + if (!recvtest(t)) + ret = 1; + } + + close(sock); + + return (ret); +} + +int +main(int argc, const char **argv) +{ + char sockpath[] = "/tmp/cmsg.testsock.XXXXXX"; + pid_t pid, ppid; + sigset_t set; + int ret = 0; + + if (argc > 1 && strcmp(argv[1], "-d") == 0) + debug = _B_TRUE; + + sigfillset(&set); + sigdelset(&set, SIGINT); + sigdelset(&set, SIGTSTP); + sigprocmask(SIG_BLOCK, &set, NULL); + + if (mktemp(sockpath) == NULL) + err(EXIT_FAILURE, "Failed to make temporary socket path"); + + ppid = getpid(); + pid = fork(); + switch (pid) { + case -1: + err(EXIT_FAILURE, "fork failed"); + case 0: + return (server(sockpath, ppid)); + default: + break; + } + + ret = client(sockpath, pid); + kill(pid, SIGINT); + + unlink(sockpath); + + return (ret); +} diff --git a/usr/src/uts/common/fs/sockfs/socksubr.c b/usr/src/uts/common/fs/sockfs/socksubr.c index 2c010343bb..2a03f0073d 100644 --- a/usr/src/uts/common/fs/sockfs/socksubr.c +++ b/usr/src/uts/common/fs/sockfs/socksubr.c @@ -23,8 +23,8 @@ * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2015, Joyent, Inc. All rights reserved. * Copyright 2016 Nexenta Systems, Inc. All rights reserved. - * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. * Copyright 2015, Joyent, Inc. All rights reserved. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #include <sys/types.h> @@ -962,7 +962,46 @@ so_closefds(void *control, t_uscalar_t controllen, int oldflg, (int)CMSG_CONTENTLEN(cmsg), startoff - (int)sizeof (struct cmsghdr)); } - startoff -= cmsg->cmsg_len; + startoff -= ROUNDUP_cmsglen(cmsg->cmsg_len); + } +} + +/* + * Handle truncation of a cmsg when the receive buffer is not big enough. + * Adjust the cmsg_len header field in the last cmsg that will be included in + * the buffer to reflect the number of bytes included. + */ +void +so_truncatecmsg(void *control, t_uscalar_t controllen, uint_t maxlen) +{ + struct cmsghdr *cmsg; + uint_t len = 0; + + if (control == NULL) + return; + + for (cmsg = control; + CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); + cmsg = CMSG_NEXT(cmsg)) { + + len += ROUNDUP_cmsglen(cmsg->cmsg_len); + + if (len > maxlen) { + /* + * This cmsg is the last one that will be included in + * the truncated buffer. + */ + socklen_t diff = len - maxlen; + + if (diff < CMSG_CONTENTLEN(cmsg)) { + dprint(1, ("so_truncatecmsg: %d -> %d\n", + cmsg->cmsg_len, cmsg->cmsg_len - diff)); + cmsg->cmsg_len -= diff; + } else { + cmsg->cmsg_len = sizeof (struct cmsghdr); + } + break; + } } } diff --git a/usr/src/uts/common/fs/sockfs/socksyscalls.c b/usr/src/uts/common/fs/sockfs/socksyscalls.c index 6a049b1828..30666f73ca 100644 --- a/usr/src/uts/common/fs/sockfs/socksyscalls.c +++ b/usr/src/uts/common/fs/sockfs/socksyscalls.c @@ -24,6 +24,7 @@ * Copyright 2015, Joyent, Inc. All rights reserved. * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #include <sys/types.h> @@ -831,7 +832,7 @@ recvit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags, void *name; socklen_t namelen; void *control; - socklen_t controllen; + socklen_t controllen, free_controllen; ssize_t len; int error; @@ -858,6 +859,8 @@ recvit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags, lwp_stat_update(LWP_STAT_MSGRCV, 1); releasef(sock); + free_controllen = msg->msg_controllen; + error = copyout_name(name, namelen, namelenp, msg->msg_name, msg->msg_namelen); if (error) @@ -887,11 +890,7 @@ recvit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags, goto err; } } - /* - * Note: This MUST be done last. There can be no "goto err" after this - * point since it could make so_closefds run twice on some part - * of the file descriptor array. - */ + if (controllen != 0) { if (!(flags & MSG_XPG4_2)) { /* @@ -900,36 +899,65 @@ recvit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags, */ controllen &= ~((int)sizeof (uint32_t) - 1); } + + if (msg->msg_controllen > controllen || control == NULL) { + /* + * If the truncated part contains file descriptors, + * then they must be closed in the kernel as they + * will not be included in the data returned to + * user space. Close them now so that the header size + * can be safely adjusted prior to copyout. In case of + * an error during copyout, the remaining file + * descriptors will be closed in the error handler + * below. + */ + so_closefds(msg->msg_control, msg->msg_controllen, + !(flags & MSG_XPG4_2), + control == NULL ? 0 : controllen); + + /* + * In the case of a truncated control message, the last + * cmsg header that fits into the available buffer + * space must be adjusted to reflect the actual amount + * of associated data that will be returned. This only + * needs to be done for XPG4 messages as non-XPG4 + * messages are not structured (they are just a + * buffer and a length - msg_accrights(len)). + */ + if (control != NULL && (flags & MSG_XPG4_2)) { + so_truncatecmsg(msg->msg_control, + msg->msg_controllen, controllen); + msg->msg_controllen = controllen; + } + } + error = copyout_arg(control, controllen, controllenp, msg->msg_control, msg->msg_controllen); + if (error) goto err; - if (msg->msg_controllen > controllen || control == NULL) { - if (control == NULL) - controllen = 0; - so_closefds(msg->msg_control, msg->msg_controllen, - !(flags & MSG_XPG4_2), controllen); - } } if (msg->msg_namelen != 0) kmem_free(msg->msg_name, (size_t)msg->msg_namelen); - if (msg->msg_controllen != 0) - kmem_free(msg->msg_control, (size_t)msg->msg_controllen); + if (free_controllen != 0) + kmem_free(msg->msg_control, (size_t)free_controllen); return (len - uiop->uio_resid); err: /* * If we fail and the control part contains file descriptors - * we have to close the fd's. + * we have to close them. For a truncated control message, the + * descriptors which were cut off have already been closed and the + * length adjusted so that they will not be closed again. */ if (msg->msg_controllen != 0) so_closefds(msg->msg_control, msg->msg_controllen, !(flags & MSG_XPG4_2), 0); if (msg->msg_namelen != 0) kmem_free(msg->msg_name, (size_t)msg->msg_namelen); - if (msg->msg_controllen != 0) - kmem_free(msg->msg_control, (size_t)msg->msg_controllen); + if (free_controllen != 0) + kmem_free(msg->msg_control, (size_t)free_controllen); return (set_errno(error)); } diff --git a/usr/src/uts/common/sys/socketvar.h b/usr/src/uts/common/sys/socketvar.h index 55a182fa68..910f2a839a 100644 --- a/usr/src/uts/common/sys/socketvar.h +++ b/usr/src/uts/common/sys/socketvar.h @@ -38,7 +38,7 @@ */ /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. - * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #ifndef _SYS_SOCKETVAR_H @@ -930,6 +930,8 @@ extern void fdbuf_free(struct fdbuf *); extern mblk_t *fdbuf_allocmsg(int, struct fdbuf *); extern int fdbuf_create(void *, int, struct fdbuf **); extern void so_closefds(void *, t_uscalar_t, int, int); +extern void so_truncatecmsg(void *, t_uscalar_t, uint_t); + extern int so_getfdopt(void *, t_uscalar_t, int, void **, int *); t_uscalar_t so_optlen(void *, t_uscalar_t, int); extern void so_cmsg2opt(void *, t_uscalar_t, int, mblk_t *); |