In case the length is 2^31+4 or larger we compute a negative value to
read in rdlen (since it is a signed int). This results in read failing
with EFAULT.
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
(SSIZE_MAX).
To reproduce the issue run:
echo -e "\x80\x00\x00\x05\x00" |socat stdin tcp:localhost:2775
---
openbsc/src/libmsc/smpp_smsc.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/openbsc/src/libmsc/smpp_smsc.c b/openbsc/src/libmsc/smpp_smsc.c
index a3dc311..23acfc2 100644
--- a/openbsc/src/libmsc/smpp_smsc.c
+++ b/openbsc/src/libmsc/smpp_smsc.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <stdint.h>
#include <errno.h>
+#include <limits.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -770,8 +771,7 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
uint8_t *lenptr = (uint8_t *) &len;
uint8_t *cur;
struct msgb *msg;
- int rdlen;
- int rc;
+ ssize_t rdlen, rc;
switch (esme->read_state) {
case READ_ST_IN_LEN:
@@ -781,7 +781,7 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
/* EINTR is a non-fatal error, just try again */
if (errno == EINTR)
return 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));
goto dead_socket;
} else if (rc == 0) {
@@ -790,8 +790,8 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
esme->read_idx += rc;
if (esme->read_idx >= sizeof(uint32_t)) {
esme->read_len = ntohl(len);
- if (esme->read_len <= 4) {
- LOGP(DSMPP, LOGL_ERROR, "[%s] read length too small %d\n",
+ if (esme->read_len <= 4 || esme->read_len > SSIZE_MAX) {
+ LOGP(DSMPP, LOGL_ERROR, "[%s] length invalid %d\n",
esme->system_id, esme->read_len);
goto dead_socket;
}
@@ -811,7 +811,7 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
rdlen = esme->read_len - esme->read_idx;
rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
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));
goto dead_socket;
} else if (rc == 0) {
--
1.8.4.2