cpdup - Fix NULL pointer indirection on lost socket
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 6 Jun 2018 15:34:43 +0000 (08:34 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 6 Jun 2018 15:36:01 +0000 (08:36 -0700)
* Fix a crash which can occur due to a lost socket.  Generate a
  nice error message and exit() instead.

bin/cpdup/hclink.c
bin/cpdup/hclink.h
bin/cpdup/hcproto.c

index c0edf1c..4619884 100644 (file)
@@ -151,13 +151,15 @@ hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
 struct HCHead *
 hcc_read_command(struct HostConf *hc, hctransaction_t trans)
 {
-    hctransaction_t fill;
     struct HCHead tmp;
     int aligned_bytes;
     int need_swap;
     int n;
     int r;
 
+    if (trans == NULL)
+       fatal("cpdup hlink protocol error with %s", hc->host);
+
     n = 0;
     while (n < (int)sizeof(struct HCHead)) {
        r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
@@ -166,9 +168,9 @@ hcc_read_command(struct HostConf *hc, hctransaction_t trans)
        n += r;
     }
 
-    if (tmp.magic == HCMAGIC)
+    if (tmp.magic == HCMAGIC) {
        need_swap = 0;
-    else {
+    else {
        tmp.magic = hc_bswap32(tmp.magic);
        if (tmp.magic != HCMAGIC)
            fatal("magic mismatch with %s (%04x)", hc->host, tmp.id);
@@ -181,15 +183,12 @@ hcc_read_command(struct HostConf *hc, hctransaction_t trans)
 
     assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < HC_BUFSIZE);
 
-    if (!(fill = trans))
-       fatal("cpdup hlink protocol error with %s (%04x)", hc->host, tmp.id);
-
-    fill->swap = need_swap;
-    bcopy(&tmp, fill->rbuf, n);
+    trans->swap = need_swap;
+    bcopy(&tmp, trans->rbuf, n);
     aligned_bytes = HCC_ALIGN(tmp.bytes);
 
     while (n < aligned_bytes) {
-       r = read(hc->fdin, fill->rbuf + n, aligned_bytes - n);
+       r = read(hc->fdin, trans->rbuf + n, aligned_bytes - n);
        if (r <= 0)
            goto fail;
        n += r;
@@ -197,9 +196,10 @@ hcc_read_command(struct HostConf *hc, hctransaction_t trans)
 #ifdef DEBUG
     hcc_debug_dump(trans, head);
 #endif
-    fill->state = HCT_REPLIED;
-    return((void *)fill->rbuf);
+    trans->state = HCT_REPLIED;
+    return((void *)trans->rbuf);
 fail:
+    trans->state = HCT_FAIL;
     return(NULL);
 }
 
@@ -270,7 +270,7 @@ hcc_finish_command(hctransaction_t trans)
        errno = EIO;
 #endif
        if (whead->cmd < 0x0010)
-               return(NULL);
+           return(NULL);
        fatal("cpdup lost connection to %s", hc->host);
     }
 
index 672d482..89eb1ac 100644 (file)
@@ -26,7 +26,7 @@ typedef struct HCTransaction {
     uint16_t   id;             /* assigned transaction id */
     int                swap;           /* have to swap byte order */
     int                windex;         /* output buffer index */
-    enum { HCT_IDLE, HCT_SENT, HCT_REPLIED, HCT_DONE } state;
+    enum { HCT_IDLE, HCT_SENT, HCT_REPLIED, HCT_DONE, HCT_FAIL } state;
 } *hctransaction_t;
 
 struct HostConf {
index 6424074..3a29504 100644 (file)
@@ -510,6 +510,8 @@ hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
        free(*statpp);
        *statpp = NULL;
     }
+    if (hc->trans.state == HCT_FAIL)
+       return NULL;
     return (denbuf.d_name[0] ? &denbuf : NULL);
 }
 
@@ -569,7 +571,7 @@ hc_closedir(struct HostConf *hc, DIR *dir)
     /* skip any remaining items if the directory is closed prematurely */
     while (hcc_nextchaineditem(hc, head) != NULL)
        /*nothing*/ ;
-    if (head->error)
+    if (hc->trans.state == HCT_FAIL || head->error)
        return (-1);
     return (0);
 }
@@ -782,7 +784,7 @@ hc_close(struct HostConf *hc, int fd)
        /* skip any remaining items if the file is closed prematurely */
        while (hcc_nextchaineditem(hc, head) != NULL)
            /*nothing*/ ;
-       if (head->error)
+       if (hc->trans.state == HCT_FAIL || head->error)
            return (-1);
        return (0);
     }
@@ -852,12 +854,16 @@ hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
     if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
        head = (void *)hc->trans.rbuf;
        while (bytes) {
-           if ((offset = head->magic) != 0)
+           if ((offset = head->magic) != 0) {
                item = hcc_currentchaineditem(hc, head);
-           else
+           } else {
                item = hcc_nextchaineditem(hc, head);
-           if (item == NULL)
+           }
+           if (item == NULL) {
+               if (hc->trans.state == HCT_FAIL)
+                       r = -1;
                return (r);
+           }
            if (item->leafid != LC_DATA)
                return (-1);
            x = item->bytes - sizeof(*item) - offset;