Changeset 37
- 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
| r35 |
r37 |
|
| 123 | 123 | if (errno == ENOMSG) |
|---|
| 124 | 124 | return 0; |
|---|
| | 125 | return -1; |
|---|
| 125 | 126 | } |
|---|
| 126 | 127 | |
|---|
| r36 |
r37 |
|
| 2 | 2 | * |
|---|
| 3 | 3 | * Copyright (C) 2006, 2007 Tresys Technology, LLC |
|---|
| 4 | | * Developed Under US JFCOM Sponsorship |
|---|
| | 4 | * Developed Under US JFCOM Sponsorship |
|---|
| 5 | 5 | * |
|---|
| 6 | 6 | * This library is free software; you can redistribute it and/or |
|---|
| r36 |
r37 |
|
| 28 | 28 | |
|---|
| 29 | 29 | /* 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 |
|---|
| 33 | 33 | #define SIPC_MSG_LEN 0x09 |
|---|
| 34 | | #define SIPC_END_XMIT 0x0c |
|---|
| | 34 | #define SIPC_END_XMIT 0x0c |
|---|
| 35 | 35 | |
|---|
| 36 | 36 | /* Invalid message length */ |
|---|
| r36 |
r37 |
|
| 205 | 205 | /* Receive and validate the length of message marker */ |
|---|
| 206 | 206 | 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) { |
|---|
| 208 | 208 | sipc_error(sipc, "msgrcv: %s\n", strerror(errno)); |
|---|
| 209 | 209 | goto err; |
|---|
| … | … | |
| 232 | 232 | * Stop when we have received the total number of bytes |
|---|
| 233 | 233 | * 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) { |
|---|
| 235 | 235 | sipc_error(sipc, "msgrcv: %s\n", strerror(errno)); |
|---|
| 236 | 236 | goto err; |
|---|
| … | … | |
| 256 | 256 | idx += recv_sz; |
|---|
| 257 | 257 | |
|---|
| 258 | | /* Check to see if we have received the entire message */ |
|---|
| 259 | | if (*len >= sipc->msg_len) |
|---|
| 260 | | break; |
|---|
| 261 | | |
|---|
| 262 | 258 | /* 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) { |
|---|
| 264 | 260 | sipc_error(sipc, "msgrcv: %s\n", strerror(errno)); |
|---|
| 265 | 261 | goto err; |
|---|
| r36 |
r37 |
|
| 78 | 78 | goto err; |
|---|
| 79 | 79 | |
|---|
| 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) |
|---|
| 82 | 82 | goto err; |
|---|
| 83 | 83 | |
|---|
| … | … | |
| 151 | 151 | } |
|---|
| 152 | 152 | |
|---|
| 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 | */ |
|---|
| 154 | 166 | int sipc_shm_send_data(sipc_t *sipc, int msg_len) |
|---|
| 155 | 167 | { |
|---|
| 156 | 168 | if (!sipc) |
|---|
| 157 | 169 | 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 | } |
|---|
| 158 | 176 | |
|---|
| 159 | 177 | /* Send a DATA_READY marker */ |
|---|
| … | … | |
| 163 | 181 | } |
|---|
| 164 | 182 | |
|---|
| 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 | | |
|---|
| 171 | 183 | /* Send another NULL marker */ |
|---|
| 172 | 184 | if (mqueue_send_msg_type(sipc->s.msqid, SIPC_NOP, MQ_BLOCK) < 0) { |
|---|
| … | … | |
| 179 | 191 | |
|---|
| 180 | 192 | /* Receive a DATA_READY marker from sender and pass |
|---|
| 181 | | * the shm pointer to the caller. |
|---|
| | 193 | * the shm pointer to the caller. |
|---|
| 182 | 194 | * This function will block if the DATA_READY marker is not |
|---|
| 183 | 195 | * present on the queue. */ |
|---|
| … | … | |
| 189 | 201 | return -1; |
|---|
| 190 | 202 | |
|---|
| 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); |
|---|
| 193 | 208 | if (mtype == SIPC_DATA_READY) { |
|---|
| 194 | 209 | /* It is now OK to read shared memory */ |
|---|
| … | … | |
| 196 | 211 | *len = sipc->len; |
|---|
| 197 | 212 | return 0; |
|---|
| 198 | | } else { |
|---|
| | 213 | } else if (mtype < 0) { |
|---|
| 199 | 214 | sipc_error(sipc, "Received a message of unknown type\n"); |
|---|
| 200 | 215 | return -1; |
|---|
| r36 |
r37 |
|
| 44 | 44 | static void do_parent(void); |
|---|
| 45 | 45 | static void do_child(void); |
|---|
| | 46 | static int verify_data(char *filename, char *recv_data); |
|---|
| 46 | 47 | static inline int is_end_xmit(char *data); |
|---|
| 47 | 48 | |
|---|
| … | … | |
| 137 | 138 | CU_ASSERT(sipc_send_data(writer_ipc, message_len) == 0); |
|---|
| 138 | 139 | CU_ASSERT(sipc_recv_data(reader_ipc, &recv_data, &recv_len) == 0); |
|---|
| | 140 | CU_ASSERT_PTR_NOT_NULL_FATAL(recv_data); |
|---|
| 139 | 141 | CU_ASSERT(recv_len >= message_len); |
|---|
| 140 | 142 | CU_ASSERT(memcmp(recv_data, message, message_len) == 0); |
|---|
| | 143 | free(recv_data); |
|---|
| 141 | 144 | CU_ASSERT(sipc_shm_recv_done(reader_ipc) == 0); |
|---|
| 142 | 145 | } |
|---|
| … | … | |
| 178 | 181 | int len = 0; |
|---|
| 179 | 182 | |
|---|
| 180 | | /* Get pointer to IPC's data member */ |
|---|
| 181 | | data = sipc_get_data_ptr(reader_ipc); |
|---|
| 182 | | CU_ASSERT_PTR_NOT_NULL(data); |
|---|
| 183 | | |
|---|
| 184 | 183 | 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); |
|---|
| 186 | 187 | 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); |
|---|
| 187 | 195 | } |
|---|
| 188 | 196 | } |
|---|
| … | … | |
| 237 | 245 | } |
|---|
| 238 | 246 | |
|---|
| | 247 | /* Read DATA_LEN bytes from a file and determine if |
|---|
| | 248 | * the read contents match the provided character string */ |
|---|
| | 249 | static 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 | |
|---|
| 239 | 274 | static inline int is_end_xmit(char *data) |
|---|
| 240 | 275 | { |
|---|
| r36 |
r37 |
|
| 245 | 245 | int len = 0; |
|---|
| 246 | 246 | |
|---|
| | 247 | memset(recv_data, 0, sizeof(recv_data)); |
|---|
| 247 | 248 | while (!sipc_recv_data(reader_ipc, &data, &len)) { |
|---|
| | 249 | CU_ASSERT_PTR_NOT_NULL_FATAL(data); |
|---|
| 248 | 250 | if (END_XMIT(data)) { |
|---|
| 249 | 251 | sipc_shm_recv_done(reader_ipc); |
|---|
| … | … | |
| 252 | 254 | |
|---|
| 253 | 255 | /* Copy received data for verification later */ |
|---|
| 254 | | strncpy(recv_data, data, DATA_LEN); |
|---|
| | 256 | memcpy(recv_data, data, len); |
|---|
| 255 | 257 | sipc_shm_recv_done(reader_ipc); |
|---|
| 256 | 258 | } |
|---|
| … | … | |
| 262 | 264 | CU_FAIL("Sent data does not match received data!"); |
|---|
| 263 | 265 | } |
|---|
| 264 | | |
|---|
| 265 | 266 | } |
|---|
| 266 | 267 | |
|---|
| … | … | |
| 301 | 302 | int len = 0, i; |
|---|
| 302 | 303 | |
|---|
| | 304 | memset(recv_data, 0, sizeof(recv_data)); |
|---|
| 303 | 305 | while (!sipc_recv_data(reader_ipc, &data, &len)) { |
|---|
| 304 | 306 | if (END_XMIT(data)) { |
|---|
Download in other formats:
* Generating other formats may take time.