diff options
| author | Pau Espin Pedrol <pespin@sysmocom.de> | 2018-05-04 18:20:35 +0200 | 
|---|---|---|
| committer | Pau Espin Pedrol <pespin@sysmocom.de> | 2018-05-04 18:29:26 +0200 | 
| commit | 686eba9bfcdd229bc1e40c75a220cfd379d15b8c (patch) | |
| tree | 100ce5f90fd3caf399f0c0c6c7835a9b2489b7c1 /src | |
| parent | 13154ffabd35a7b6d017e54bd92ab2b984ba5066 (diff) | |
control_if: Avoid heap-use-after-free in osmo_wqueue_bfd_cb
Imagine following scenario:
1- client connects to CTRL iface, a new conn is created with POLL_READ
enabled.
2- A non-related event happens which triggers a TRAP to be sent. As a
result, the wqueue for the conn has now enabled POLL_WRITE, and message
will be sent next time we go through osmo_main_select().
3- At the same time, we receive the GET cmd from the CTRL client, which
means POLL_READ event will be also triggered next time we call
osmo_main_select().
4- osmo_main_select triggers osmo_wqueue_bfd_cb with both READ/WRITE
flags set.
5- The read_cb of wqueue is executed first. The handler closes the CTRL
conn for some reason, freeing the osmo_fd struct and returns.
6- osmo_qeueue_bfd_cb keeps using the already freed osmo_fd and calls
write_cb.
So in step 6 we get a heap-use-after-free catched by AddressSanitizer:
[0;m20180424135406115 [1;32mDLCTRL[0;m <0018> control_if.c:506 accept()ed new CTRL connection from (r=10.42.42.1:53910<->l=10.42.42.7:4249)
[0;m20180424135406116 [1;34mDLCTRL[0;m <0018> control_cmd.c:378 Command: GET bts.0.oml-connection-state
[0;m20180424135406117 [1;34mDLINP[0;m <0013> bts_ipaccess_nanobts.c:417 Identified BTS 1/0/0
[0;m[1;36m20180424135406118 [1;34mDNM[0;m[1;36m <0005> abis_nm.c:1628 Get Attr (bts=0)
[0;m[1;36m20180424135406118 [1;34mDNM[0;m[1;36m <0005> abis_nm.c:1628 Get Attr (bts=0)
[0;m20180424135406118 [1;34mDCTRL[0;m <000e> osmo_bsc_ctrl.c:158 BTS connection (re)established, sending TRAP.
[0;m20180424135406119 [1;32mDLCTRL[0;m <0018> control_if.c:173 close()d CTRL connection (r=10.42.42.1:53910<->l=10.42.42.7:4249)
[0;m=================================================================
==12301==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000003e04 at pc 0x7f23091c3a2f bp 0x7ffc0cb73ff0 sp 0x7ffc0cb73fe8
READ of size 4 at 0x611000003e04 thread T0
    #0 0x7f23091c3a2e in osmo_wqueue_bfd_cb /home/osmocom-build/jenkins/workspace/osmo-gsm-tester_build-osmo-bsc/libosmocore/src/write_queue.c:65
    #1 0x7f23091ad5d8 in osmo_fd_disp_fds /home/osmocom-build/jenkins/workspace/osmo-gsm-tester_build-osmo-bsc/libosmocore/src/select.c:216
    #2 0x7f23091ad5d8 in osmo_select_main /home/osmocom-build/jenkins/workspace/osmo-gsm-tester_build-osmo-bsc/libosmocore/src/select.c:256
    #3 0x56538bdb7a26 in main /home/osmocom-build/jenkins/workspace/osmo-gsm-tester_build-osmo-bsc/osmo-bsc/src/osmo-bsc/osmo_bsc_main.c:532
    #4 0x7f23077532e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
    #5 0x56538bdb8999 in _start (/home/jenkins/workspace/osmo-gsm-tester_run-prod/trial-896/inst/osmo-bsc/bin/osmo-bsc+0x259999)
Fixes: OS#3206
Change-Id: I84d10caaadcfa6bd46ba8756ca89aa0badcfd2e3
Diffstat (limited to 'src')
| -rw-r--r-- | src/ctrl/control_if.c | 41 | 
1 files changed, 22 insertions, 19 deletions
| diff --git a/src/ctrl/control_if.c b/src/ctrl/control_if.c index cc613ee7..0ba25125 100644 --- a/src/ctrl/control_if.c +++ b/src/ctrl/control_if.c @@ -327,7 +327,7 @@ err:  static int handle_control_read(struct osmo_fd * bfd)  { -	int ret = -1; +	int ret;  	struct osmo_wqueue *queue;  	struct ctrl_connection *ccon;  	struct msgb *msg = NULL; @@ -337,27 +337,28 @@ static int handle_control_read(struct osmo_fd * bfd)  	ccon = container_of(queue, struct ctrl_connection, write_queue);  	ret = ipa_msg_recv_buffered(bfd->fd, &msg, &ccon->pending_msg); -	if (ret <= 0) { -		if (ret == -EAGAIN) -			/* received part of a message, it is stored in ccon->pending_msg and there's -			 * nothing left to do now. */ -			return 0; +	if (ret == 0) {  		/* msg was already discarded. */ -		if (ret == 0) { -			control_close_conn(ccon); -			ret = -EIO; -		} -		else -			LOGP(DLCTRL, LOGL_ERROR, "Failed to parse ip access message: %d\n", ret); - -		return ret; +		goto close_fd; +	} else if (ret == -EAGAIN) { +		/* received part of a message, it is stored in ccon->pending_msg and there's +		 * nothing left to do now. */ +		return 0; +	} else if (ret < 0) { +		LOGP(DLCTRL, LOGL_ERROR, "Failed to parse ip access message: %d\n", ret); +		return 0;  	}  	ret = ctrl_handle_msg(ctrl, ccon, msg);  	msgb_free(msg);  	if (ret) -		control_close_conn(ccon); -	return ret; +		goto close_fd; + +	return 0; + +close_fd: +	control_close_conn(ccon); +	return -EBADF;  }  int ctrl_handle_msg(struct ctrl_handle *ctrl, struct ctrl_connection *ccon, struct msgb *msg) @@ -435,12 +436,14 @@ static int control_write_cb(struct osmo_fd *bfd, struct msgb *msg)  	ccon = container_of(queue, struct ctrl_connection, write_queue);  	rc = write(bfd->fd, msg->data, msg->len); -	if (rc == 0) +	if (rc == 0) {  		control_close_conn(ccon); -	else if (rc != msg->len) +		return -EBADF; +	} +	if (rc != msg->len)  		LOGP(DLCTRL, LOGL_ERROR, "Failed to write message to the CTRL connection.\n"); -	return rc; +	return 0;  }  /*! Allocate CTRL connection | 
