smpp_smsc: Fix integer overflow in read return value and msgb_alloc()
The size parameter of msgb_alloc is uint16_t so any length value above 65535 will allocate a msgb with incorrect size. This patch changes the type of rdlen and rc to ssize_t (the return value of read) and guards against the read length being larger than UINT16_MAX. To reproduce the issue run: echo -en "\x00\x01\x00\x01\x01" |socat stdin tcp:localhost:2775
This commit is contained in:
parent
b6f01e77b1
commit
1fc8ec66a3
|
@ -23,6 +23,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
@ -787,15 +788,14 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
|
||||||
uint8_t *lenptr = (uint8_t *) &len;
|
uint8_t *lenptr = (uint8_t *) &len;
|
||||||
uint8_t *cur;
|
uint8_t *cur;
|
||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
int rdlen;
|
ssize_t rdlen, rc;
|
||||||
int rc;
|
|
||||||
|
|
||||||
switch (esme->read_state) {
|
switch (esme->read_state) {
|
||||||
case READ_ST_IN_LEN:
|
case READ_ST_IN_LEN:
|
||||||
rdlen = sizeof(uint32_t) - esme->read_idx;
|
rdlen = sizeof(uint32_t) - esme->read_idx;
|
||||||
rc = read(ofd->fd, lenptr + esme->read_idx, rdlen);
|
rc = read(ofd->fd, lenptr + esme->read_idx, rdlen);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %d (%s)\n",
|
LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %zd (%s)\n",
|
||||||
esme->system_id, rc, strerror(errno));
|
esme->system_id, rc, strerror(errno));
|
||||||
OSMO_FD_CHECK_READ(rc, dead_socket);
|
OSMO_FD_CHECK_READ(rc, dead_socket);
|
||||||
|
|
||||||
|
@ -803,8 +803,8 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
|
||||||
|
|
||||||
if (esme->read_idx >= sizeof(uint32_t)) {
|
if (esme->read_idx >= sizeof(uint32_t)) {
|
||||||
esme->read_len = ntohl(len);
|
esme->read_len = ntohl(len);
|
||||||
if (esme->read_len < 8) {
|
if (esme->read_len < 8 || esme->read_len > UINT16_MAX) {
|
||||||
LOGP(DSMPP, LOGL_ERROR, "[%s] read length too small %u\n",
|
LOGP(DSMPP, LOGL_ERROR, "[%s] length invalid %u\n",
|
||||||
esme->system_id, esme->read_len);
|
esme->system_id, esme->read_len);
|
||||||
goto dead_socket;
|
goto dead_socket;
|
||||||
}
|
}
|
||||||
|
@ -824,7 +824,7 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
|
||||||
rdlen = esme->read_len - esme->read_idx;
|
rdlen = esme->read_len - esme->read_idx;
|
||||||
rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
|
rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %d (%s)\n",
|
LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %zd (%s)\n",
|
||||||
esme->system_id, rc, strerror(errno));
|
esme->system_id, rc, strerror(errno));
|
||||||
OSMO_FD_CHECK_READ(rc, dead_socket);
|
OSMO_FD_CHECK_READ(rc, dead_socket);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue