Changeset 47

Show
Ignore:
Timestamp:
06/30/08 17:33:55 (2 months ago)
Author:
jtang
Message:

Fixed error in sipc_send_data(), where a send of data with length 0 would cause undefined behavior.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libsipc/man/man3/sipc_recv_data.3

    r45 r47  
    2424.TP 
    2525.I len 
    26 Pointer to the total number of bytes received 
     26Pointer to the total number of bytes received (which could be 0). 
    2727.PP 
    2828If the IPC channel is a message queue, \fBsipc_recv_data\fR() 
  • trunk/libsipc/src/Makefile

    r44 r47  
    1919        ln -sf $@ $(TARGET) 
    2020 
    21 %.o: %.c 
     21%.o: %.c sipc_internal.h 
    2222        $(CC) $(AM_CFLAGS) $(CFLAGS) $(INCLUDEDIRS) -c -o $@ $< 
    2323 
  • trunk/libsipc/src/sipc.c

    r46 r47  
    152152                return -1; 
    153153        } 
     154        if (msg_len < 0) { 
     155                errno = EINVAL; 
     156                return -1; 
     157        } 
     158        if (sipc->role != SIPC_SENDER) { 
     159                sipc_error(sipc, "sipc_send_data called without sender flag enabled in IPC structure\n"); 
     160                errno = EBADF; 
     161                return -1; 
     162        } 
     163        if (msg_len > sipc->data_size) { 
     164                sipc_error(sipc, "sipc_send_data: cannot send buffer of size %d, can only receive %zd\n", msg_len, sipc->data_size); 
     165                errno = ENOMEM; 
     166                return -1; 
     167        } 
    154168 
    155169        return sipc->funcs->sipc_send_data(sipc, msg_len); 
     
    158172int sipc_recv_data(sipc_t *sipc, char **data, int *len) 
    159173{ 
    160         if (!sipc) 
    161                 return -1; 
     174        if (data) 
     175                *data = NULL;          /* Pointer to a buffer created here */ 
     176        if (len) 
     177                *len = 0;              /* Bytes received so far */ 
     178        if (!sipc || !data || !len) { 
     179                errno = EINVAL; 
     180                return -1; 
     181        } 
     182        if (sipc->role != SIPC_RECEIVER) { 
     183                sipc_error(sipc, "sipc_recv_data called without receiver flag enabled in IPC structure\n"); 
     184                errno = EBADF; 
     185                return -1; 
     186        } 
    162187 
    163188        return sipc->funcs->sipc_recv_data(sipc, data, len); 
  • trunk/libsipc/src/sipc_mqueue.c

    r46 r47  
    5454static int mqueue_send_msg_len(sipc_t *sipc, int msg_len); 
    5555static int mqueue_send_end_xmit(sipc_t *sipc); 
    56 static char *split_data(sipc_t *sipc, size_t packet_sz); 
    5756static int is_msg_len(struct msgbuf *mbuf); 
    5857static int is_end_xmit(struct msgbuf *mbuf); 
    59 static int msg_done(sipc_t *sipc); 
    60 static size_t next_packet_sz(int recv, int max_packet_sz, int msg_len); 
    6158static size_t next_alloc_sz(int recv, int recv_sz, int max_packet_sz, int msg_len); 
    6259 
     
    142139int sipc_mqueue_send_data(sipc_t *sipc, int msg_len) 
    143140{ 
    144         int max_packet_sz = SIPC_MQUEUE_MSG_SZ - sizeof(struct msgbuf); 
     141        size_t max_packet_sz = SIPC_MQUEUE_MSG_SZ - sizeof(long); 
    145142        int error = 0; 
    146         size_t packet_sz; 
    147         char *packet = NULL; 
    148  
    149         if (!sipc) { 
    150                 error = EINVAL; 
    151                 goto err; 
    152         } 
    153         if (sipc->role != SIPC_SENDER) { 
    154                 error = EINVAL; 
    155                 goto err; 
    156         } 
    157143 
    158144        struct msgbuf *mbuf = sipc->mbuf; 
    159145        assert(mbuf); 
    160146        memset(mbuf, 0, SIPC_MQUEUE_MSG_SZ); 
    161         sipc->msg_len = msg_len; 
    162147        if (mqueue_send_msg_len(sipc, msg_len) < 0) { 
    163148                error = errno; 
     
    165150        } 
    166151 
    167         sipc->copied = 0;              /* Reset copied data counter */ 
    168         do { 
    169                 packet_sz = next_packet_sz(sipc->copied, max_packet_sz, msg_len); 
    170  
    171                 if ((packet = split_data(sipc, packet_sz)) == NULL) { 
    172                         error = errno; 
    173                         sipc_error(sipc, "%s\n", "Unable to fragment message data"); 
    174                         goto err; 
    175                 } 
    176  
    177                 bzero(mbuf->mtext, packet_sz); 
     152        size_t amount_written = 0; 
     153        while (amount_written < msg_len) { 
     154                size_t amount_to_write = msg_len - amount_written > max_packet_sz ? max_packet_sz : msg_len - amount_written; 
     155 
    178156                mbuf->mtype = SIPC_DATA_READY; 
    179                 memcpy(mbuf->mtext, packet, packet_sz); 
     157                memcpy(mbuf->mtext, sipc->data + amount_written, amount_to_write); 
    180158 
    181159                /* Send the message */ 
    182                 while (msgsnd(sipc->msqid, mbuf, packet_sz, 0) < 0) { 
     160                while (msgsnd(sipc->msqid, mbuf, amount_to_write, 0) < 0) { 
    183161                        error = errno; 
    184162                        if (error != EINTR) { 
     
    187165                        } 
    188166                } 
    189                 free(packet)
    190         } while (!msg_done(sipc)); 
     167                amount_written += amount_to_write
     168        } 
    191169 
    192170        /* Send end of message marker */ 
     
    195173                goto err; 
    196174        } 
    197         sipc->msg_len = SIPC_MSGLEN_NOT_SET; 
    198175        return 0; 
    199176 
    200177      err: 
    201         free(packet); 
    202         sipc->msg_len = SIPC_MSGLEN_NOT_SET; 
    203178        errno = error; 
    204179        return -1; 
     
    434409} 
    435410 
    436 /* Returns 1 if the message has been completely fragmented, 
    437  * 0 otherwise. */ 
    438 static int msg_done(sipc_t *sipc) 
    439 { 
    440         return sipc->copied >= sipc->msg_len ? 1 : 0; 
    441 } 
    442  
    443 /* Splits data in sipc into a chunk the size of the maximum 
    444  * allowed for a message in a message queue. 
    445  * This function allocates space for the fragmented piece of data. 
    446  * The caller is responsible for freeign this memory. */ 
    447 static char *split_data(sipc_t *sipc, size_t packet_sz) 
    448 { 
    449         size_t remaining = sipc->msg_len - sipc->copied; 
    450         size_t len = remaining > packet_sz ? packet_sz : remaining; 
    451         char *packet = calloc(1, len); 
    452         if (!packet) 
    453                 return NULL; 
    454  
    455         memcpy(packet, (sipc->data) + (sipc->copied), len); 
    456         sipc->copied += len; 
    457  
    458         return packet; 
    459 } 
    460  
    461 /* Determine the next packet's size. 
    462  * A packet should not contain extra padding. 
    463  * Returns the size of the next packet on success, -1 on failure. */ 
    464 static size_t next_packet_sz(int recv, int max_packet_sz, int msg_len) 
    465 { 
    466         if (recv < 0 || max_packet_sz <= 0 || msg_len <= 0) 
    467                 return -1; 
    468  
    469         if (recv + max_packet_sz > msg_len) 
    470                 return msg_len - recv; 
    471         else 
    472                 return max_packet_sz; 
    473  
    474 } 
    475  
    476411/* Determine how much memory to allocate for receiving a packet. 
    477412 * A packet should not contain extra padding. 
  • trunk/libsipc/src/sipc_shm.c

    r46 r47  
    161161{ 
    162162        int error; 
    163         if (!sipc) { 
    164                 errno = EINVAL; 
    165                 return -1; 
    166         } 
    167163 
    168164        /* Send a DATA_READY marker */ 
     
    204200        int block; 
    205201 
    206         if (data) 
    207                 *data = NULL;          /* Pointer to a buffer created here */ 
    208         if (len) 
    209                 *len = 0;              /* Bytes received so far */ 
    210         if (!sipc || !data || !len) { 
    211                 errno = EINVAL; 
    212                 return -1; 
    213         } 
    214202        block = (sipc->non_blocking == 0 ? 1 : 0); 
    215203 
  • trunk/libsipc/tests/Makefile

    r44 r47  
    11TESTS = test_ipc ipc_creator ipc_destroyer 
    2 AM_CFLAGS = -I../include 
    3 AM_LDFLAGS = -lsipc -lcunit -Wl,-rpath=$(TOP_BUILDDIR)/src -L$(TOP_BUILDDIR)/src 
     2AM_CFLAGS += -I../include 
     3AM_LDFLAGS += -lsipc -lcunit -Wl,-rpath=$(TOP_BUILDDIR)/src -L$(TOP_BUILDDIR)/src 
    44TOP_BUILDDIR := $(shell pwd)/.. 
    55 
     
    2222        -rm -rf $(TESTS) 
    2323 
    24 .PHONY: all install test clean 
     24.PHONY: all install tests clean 
  • trunk/libsipc/tests/mqueue.c

    r45 r47  
    284284                free(data); 
    285285        } 
     286 
     287        CU_ASSERT(sipc_recv_data(reader_ipc, &data, &len) == 0); 
     288        CU_ASSERT_PTR_NOT_NULL(data); 
     289        CU_ASSERT(len == 0); 
     290        free(data); 
    286291} 
    287292 
     
    312317        CU_ASSERT(send_end_xmit(writer_ipc) == 0); 
    313318        fclose(ifile); 
     319 
     320        /* Trying sending a zero-byte message */ 
     321        CU_ASSERT(sipc_send_data(writer_ipc, 0) == 0); 
    314322 
    315323        /* Cleanup handle here */