Changeset 37

Show
Ignore:
Timestamp:
05/30/08 17:23:36 (6 months ago)
Author:
jtang
Message:

Fixed buffer overflows in message queue code.
Fixing race condition with shm, due to ordering of messages within side-channel queue.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libsipc/src/mqueue_internal.c

    r35 r37  
    123123                if (errno == ENOMSG) 
    124124                        return 0; 
     125                return -1; 
    125126        } 
    126127 
  • trunk/libsipc/src/shm_internal.c

    r36 r37  
    22* 
    33* Copyright (C) 2006, 2007 Tresys Technology, LLC 
    4 * Developed Under US JFCOM Sponsorship  
     4* Developed Under US JFCOM Sponsorship 
    55* 
    66*  This library is free software; you can redistribute it and/or 
  • trunk/libsipc/src/sipc_internal.h

    r36 r37  
    2828 
    2929/* Control message types */ 
    30 #define SIPC_ANY        0x00 
    31 #define SIPC_DATA_READY 0x03 
    32 #define SIPC_NOP        0x06 
     30#define SIPC_ANY       0x00 
     31#define SIPC_DATA_READY        0x03 
     32#define SIPC_NOP       0x06 
    3333#define SIPC_MSG_LEN    0x09 
    34 #define SIPC_END_XMIT   0x0c 
     34#define SIPC_END_XMIT  0x0c 
    3535 
    3636/* Invalid message length */ 
  • trunk/libsipc/src/sipc_mqueue.c

    r36 r37  
    205205        /* Receive and validate the length of message marker */ 
    206206        if (sipc->msg_len == SIPC_MSGLEN_NOT_SET) { 
    207                 if (msgrcv(sipc->msqid, mbuf, SIPC_MQUEUE_MSG_SZ, SIPC_ANY, 0) < 0) { 
     207                if (msgrcv(sipc->msqid, mbuf, SIPC_MQUEUE_MSG_SZ - sizeof(long), SIPC_ANY, 0) < 0) { 
    208208                        sipc_error(sipc, "msgrcv: %s\n", strerror(errno)); 
    209209                        goto err; 
     
    232232         * Stop when we have received the total number of bytes 
    233233         * or upon receiving the end of message marker. */ 
    234         if ((recv_sz = msgrcv(sipc->msqid, mbuf, SIPC_MQUEUE_MSG_SZ, SIPC_ANY, 0)) < 0) { 
     234        if ((recv_sz = msgrcv(sipc->msqid, mbuf, SIPC_MQUEUE_MSG_SZ - sizeof(long), SIPC_ANY, 0)) < 0) { 
    235235                sipc_error(sipc, "msgrcv: %s\n", strerror(errno)); 
    236236                goto err; 
     
    256256                idx += recv_sz; 
    257257 
    258                 /* Check to see if we have received the entire message */ 
    259                 if (*len >= sipc->msg_len) 
    260                         break; 
    261  
    262258                /* Receive the next message */ 
    263                 if ((recv_sz = msgrcv(sipc->msqid, mbuf, SIPC_MQUEUE_MSG_SZ, SIPC_ANY, 0)) < 0) { 
     259                if ((recv_sz = msgrcv(sipc->msqid, mbuf, SIPC_MQUEUE_MSG_SZ - sizeof(long), SIPC_ANY, 0)) < 0) { 
    264260                        sipc_error(sipc, "msgrcv: %s\n", strerror(errno)); 
    265261                        goto err; 
  • trunk/libsipc/src/sipc_shm.c

    r36 r37  
    7878                goto err; 
    7979 
    80         /* Set capacity of side channel to 1 message */ 
    81         if (sipc->role == SIPC_SENDER && mqueue_set_capacity(sipc->s.msqid, sizeof(struct msgbuf)) < 0) 
     80        /* Set capacity of side channel to 3 messages */ 
     81        if (mqueue_set_capacity(sipc->s.msqid, 3) < 0) 
    8282                goto err; 
    8383 
     
    151151} 
    152152 
    153 /* Sends a DATA_READY marker, followed by 2 NOP markers */ 
     153/* Send a NOP, then the data, then another NOP.  This is because after 
     154 * the data is received, there will be 2 NOPs still in the queue.  A 
     155 * subsequent send will then add a NOP, but then block on DATA_READY 
     156 * until sipc_shm_recv_done() is called. 
     157 * 
     158 * NOPs are needed because there is a potential race condition.  A 
     159 * reader could receive a message, but not have time to copy the data 
     160 * before the writer sends another message. 
     161 * 
     162 * Keeping NOPs, but decreasing the queue size to 1 will also not 
     163 * work.  This is because the writer should be able to send at least 
     164 * one message without blocking itself. 
     165 */ 
    154166int sipc_shm_send_data(sipc_t *sipc, int msg_len) 
    155167{ 
    156168        if (!sipc) 
    157169                return -1; 
     170 
     171        /* Send a NULL marker; this should block at first */ 
     172        if (mqueue_send_msg_type(sipc->s.msqid, SIPC_NOP, MQ_BLOCK) < 0) { 
     173                sipc_error(sipc, "Could not send NOP marker\n"); 
     174                return -1; 
     175        } 
    158176 
    159177        /* Send a DATA_READY marker */ 
     
    163181        } 
    164182 
    165         /* Send a NULL marker; this should block at first */ 
    166         if (mqueue_send_msg_type(sipc->s.msqid, SIPC_NOP, MQ_BLOCK) < 0) { 
    167                 sipc_error(sipc, "Could not send NOP marker\n"); 
    168                 return -1; 
    169         } 
    170  
    171183        /* Send another NULL marker */ 
    172184        if (mqueue_send_msg_type(sipc->s.msqid, SIPC_NOP, MQ_BLOCK) < 0) { 
     
    179191 
    180192/* Receive a DATA_READY marker from sender and pass 
    181  * the shm pointer to the caller.  
     193 * the shm pointer to the caller. 
    182194 * This function will block if the DATA_READY marker is not 
    183195 * present on the queue. */ 
     
    189201                return -1; 
    190202 
    191         /* Get a message from the side channel; exit when it's END_XMIT */ 
    192         mtype = mqueue_get_msg_type(sipc->s.msqid, SIPC_ANY, MQ_BLOCK); 
     203        *data = NULL; 
     204        *len = 0; 
     205 
     206        /* Get a message from the side channel. */ 
     207        mtype = mqueue_get_msg_type(sipc->s.msqid, SIPC_DATA_READY, MQ_BLOCK); 
    193208        if (mtype == SIPC_DATA_READY) { 
    194209                /* It is now OK to read shared memory */ 
     
    196211                *len = sipc->len; 
    197212                return 0; 
    198         } else
     213        } else if (mtype < 0)
    199214                sipc_error(sipc, "Received a message of unknown type\n"); 
    200215                return -1; 
  • trunk/libsipc/tests/mqueue.c

    r36 r37  
    4444static void do_parent(void); 
    4545static void do_child(void); 
     46static int verify_data(char *filename, char *recv_data); 
    4647static inline int is_end_xmit(char *data); 
    4748 
     
    137138        CU_ASSERT(sipc_send_data(writer_ipc, message_len) == 0); 
    138139        CU_ASSERT(sipc_recv_data(reader_ipc, &recv_data, &recv_len) == 0); 
     140        CU_ASSERT_PTR_NOT_NULL_FATAL(recv_data); 
    139141        CU_ASSERT(recv_len >= message_len); 
    140142        CU_ASSERT(memcmp(recv_data, message, message_len) == 0); 
     143        free(recv_data); 
    141144        CU_ASSERT(sipc_shm_recv_done(reader_ipc) == 0); 
    142145} 
     
    178181        int len = 0; 
    179182 
    180         /* Get pointer to IPC's data member */ 
    181         data = sipc_get_data_ptr(reader_ipc); 
    182         CU_ASSERT_PTR_NOT_NULL(data); 
    183  
    184183        while (!sipc_recv_data(reader_ipc, &data, &len)) { 
    185                 if (data != NULL && is_end_xmit(data)) 
     184                CU_ASSERT_PTR_NOT_NULL_FATAL(data); 
     185                if (is_end_xmit(data)) { 
     186                        free(data); 
    186187                        break; 
     188                } 
     189                if (verify_data(IN_FILE, data) != 1) { 
     190                        CU_PASS("Sent data matches received data"); 
     191                } else { 
     192                        CU_FAIL("Sent data does not match received data!"); 
     193                } 
     194                free(data); 
    187195        } 
    188196} 
     
    237245} 
    238246 
     247/* Read DATA_LEN bytes from a file and determine if 
     248 * the read contents match the provided character string */ 
     249static int verify_data(char *filename, char *recv_data) 
     250{ 
     251        FILE *ifile = NULL; 
     252        char data[DATA_LEN]; 
     253        int rbytes = 0; 
     254 
     255        ifile = fopen(filename, "r"); 
     256        if (!ifile) { 
     257                fprintf(stderr, "fopen: %s\n", strerror(errno)); 
     258                return -1; 
     259        } 
     260 
     261        rbytes = fread(data, sizeof(char), DATA_LEN - 1, ifile); 
     262        if (rbytes < 0) { 
     263                fclose(ifile); 
     264                return -1; 
     265        } 
     266        fclose(ifile); 
     267 
     268        if (memcmp(data, recv_data, rbytes)) 
     269                return 1; 
     270 
     271        return -1; 
     272} 
     273 
    239274static inline int is_end_xmit(char *data) 
    240275{ 
  • trunk/libsipc/tests/shm.c

    r36 r37  
    245245        int len = 0; 
    246246 
     247        memset(recv_data, 0, sizeof(recv_data)); 
    247248        while (!sipc_recv_data(reader_ipc, &data, &len)) { 
     249                CU_ASSERT_PTR_NOT_NULL_FATAL(data); 
    248250                if (END_XMIT(data)) { 
    249251                        sipc_shm_recv_done(reader_ipc); 
     
    252254 
    253255                /* Copy received data for verification later */ 
    254                 strncpy(recv_data, data, DATA_LEN); 
     256                memcpy(recv_data, data, len); 
    255257                sipc_shm_recv_done(reader_ipc); 
    256258        } 
     
    262264                CU_FAIL("Sent data does not match received data!"); 
    263265        } 
    264  
    265266} 
    266267 
     
    301302        int len = 0, i; 
    302303 
     304        memset(recv_data, 0, sizeof(recv_data)); 
    303305        while (!sipc_recv_data(reader_ipc, &data, &len)) { 
    304306                if (END_XMIT(data)) {