[Pkg-voip-commits] r8882 - in /asterisk/branches/lenny-security/debian: changelog patches/AST-2011-006 patches/series

tzafrir at alioth.debian.org tzafrir at alioth.debian.org
Thu Apr 21 21:22:08 UTC 2011


Author: tzafrir
Date: Thu Apr 21 21:22:02 2011
New Revision: 8882

URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=8882
Log:
Patch AST-2011-006: Resource exhaustion in chan_skinny and AJAM

Added:
    asterisk/branches/lenny-security/debian/patches/AST-2011-006
Modified:
    asterisk/branches/lenny-security/debian/changelog
    asterisk/branches/lenny-security/debian/patches/series

Modified: asterisk/branches/lenny-security/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/lenny-security/debian/changelog?rev=8882&op=diff
==============================================================================
--- asterisk/branches/lenny-security/debian/changelog (original)
+++ asterisk/branches/lenny-security/debian/changelog Thu Apr 21 21:22:02 2011
@@ -3,11 +3,12 @@
   * AST-2011-002 (CVE-2011-1147): Multiple crash vulnerabilities in UDPTL code
     (Closes: #614580).
   * Patch AST-2011-005: Resource exhaustion in Asterisk Manager Interface
+  * Patch AST-2011-006: Resource exhaustion in chan_skinny and AJAM
     (Closes: #618790).
   * Patches AST-2011-003, manager_manager_bugfix_reload - its pre-requirements.
   * My new @debian.org address
 
- -- Tzafrir Cohen <tzafrir at debian.org>  Thu, 17 Mar 2011 12:21:06 +0200
+ -- Tzafrir Cohen <tzafrir at debian.org>  Fri, 22 Apr 2011 00:21:22 +0300
 
 asterisk (1:1.4.21.2~dfsg-3+lenny2) oldstable-security; urgency=high
 

Added: asterisk/branches/lenny-security/debian/patches/AST-2011-006
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/lenny-security/debian/patches/AST-2011-006?rev=8882&op=file
==============================================================================
--- asterisk/branches/lenny-security/debian/patches/AST-2011-006 (added)
+++ asterisk/branches/lenny-security/debian/patches/AST-2011-006 Thu Apr 21 21:22:02 2011
@@ -1,0 +1,344 @@
+From: Matthew Nicholson <mnicholson at digium.com>
+Date: Thu, 21 Apr 2011 18:19:21 +0000
+Bug: https://issues.asterisk.org/view.php?id=18787
+Origin: http://svnview.digium.com/svn/asterisk?view=rev&rev=314607
+Subject: limits unauthenticated TCP sessions
+
+Added limits to the number of unauthenticated sessions TCP based protocols
+are allowed to have open simultaneously.  Also added timeouts for
+unauthenticated sessions where it made sense to do so.
+
+Unrelated, the manager interface now properly checks if the user has the
+"system" privilege before executing shell commands via the Originate action.
+
+This is a followup to AST-2011-005. It applies a similar fix to chan_skinny
+and to manager interface over HTTP.
+
+Skinny, or SCCP, is enabled by default (though not used in most settings).
+To disable: 'noload => chan_skinny.so' in /etc/asterisk/modules.conf .
+
+Manager over HTTP is not enabled by default on Debian.
+
+See also:
+  https://issues.asterisk.org/view.php?id=18996
+  http://downloads.asterisk.org/pub/security/AST-2011-005.html
+  http://downloads.asterisk.org/pub/security/AST-2011-006.html
+
+---
+ channels/chan_skinny.c     |   75 +++++++++++++++++++++++++++++++++++++++++--
+ configs/http.conf.sample   |    7 +++-
+ configs/skinny.conf.sample |    9 +++++
+ main/http.c                |   25 ++++++++++++++-
+ main/manager.c             |   18 ++++++++++
+ 5 files changed, 128 insertions(+), 6 deletions(-)
+
+diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
+index 59e8cfa..f6bce77 100644
+--- a/channels/chan_skinny.c
++++ b/channels/chan_skinny.c
+@@ -96,8 +96,13 @@ enum skinny_codecs {
+ #define DEFAULT_SKINNY_PORT	2000
+ #define DEFAULT_SKINNY_BACKLOG	2
+ #define SKINNY_MAX_PACKET	1000
++#define DEFAULT_AUTH_TIMEOUT	30
++#define DEFAULT_AUTH_LIMIT	50
+ 
+ static int keep_alive = 120;
++static int auth_timeout = DEFAULT_AUTH_TIMEOUT;
++static int auth_limit = DEFAULT_AUTH_LIMIT;
++static int unauth_sessions = 0;
+ static char date_format[6] = "D-M-Y";
+ static char version_id[16] = "P002F202";
+ 
+@@ -1060,6 +1065,7 @@ struct skinny_paging_device {
+ static struct skinnysession {
+ 	pthread_t t;
+ 	ast_mutex_t lock;
++	time_t start;
+ 	struct sockaddr_in sin;
+ 	int fd;
+ 	char inbuf[SKINNY_MAX_PACKET];
+@@ -3064,6 +3070,7 @@ static int handle_register_message(struct skinny_req *req, struct skinnysession
+ 		transmit_response(s, req);
+ 		return 0;
+ 	}
++	ast_atomic_fetchadd_int(&unauth_sessions, -1);
+ 	if (option_verbose > 2)
+ 		ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfully registered\n", name);
+ 
+@@ -4427,6 +4434,9 @@ static void destroy_session(struct skinnysession *s)
+ 		if (s->fd > -1) {
+ 			close(s->fd);
+ 		}
++		if (!s->device) {
++			ast_atomic_fetchadd_int(&unauth_sessions, -1);
++		}
+ 		ast_mutex_destroy(&s->lock);
+ 		free(s);
+ 	} else {
+@@ -4439,12 +4449,29 @@ static int get_input(struct skinnysession *s)
+ {
+ 	int res;
+ 	int dlen = 0;
++	int timeout = keep_alive * 1100;
++	time_t now;
+ 	struct pollfd fds[1];
+ 
++	if (!s->device) {
++		if(time(&now) == -1) {
++			ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
++			return -1;
++		}
++
++		timeout = (auth_timeout - (now - s->start)) * 1000;
++		if (timeout < 0) {
++			/* we have timed out */
++			if (skinnydebug)
++				ast_verbose("Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
++			return -1;
++		}
++	}
++
+  	fds[0].fd = s->fd;
+ 	fds[0].events = POLLIN;
+ 	fds[0].revents = 0;
+-	res = poll(fds, 1, (keep_alive * 1100)); /* If nothing has happen, client is dead */
++	res = poll(fds, 1, timeout); /* If nothing has happen, client is dead */
+ 						 /* we add 10% to the keep_alive to deal */
+ 						 /* with network delays, etc */
+ 	if (res < 0) {
+@@ -4454,8 +4481,13 @@ static int get_input(struct skinnysession *s)
+ 			return res;
+ 		}
+  	} else if (res == 0) {
+-		if (skinnydebug)
+-			ast_verbose("Skinny Client was lost, unregistering\n");
++		if (skinnydebug) {
++			if (s->device) {
++				ast_verbose("Skinny Client was lost, unregistering\n");
++			} else {
++				ast_verbose("Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
++			}
++		}
+ 		skinny_unregister(NULL, s);
+ 		return -1;
+ 	}
+@@ -4594,18 +4626,35 @@ static void *accept_thread(void *ignore)
+ 			ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
+ 			continue;
+ 		}
++
++		if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= auth_limit) {
++			close(as);
++			ast_atomic_fetchadd_int(&unauth_sessions, -1);
++			continue;
++		}
++
+ 		p = getprotobyname("tcp");
+ 		if(p) {
+ 			if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
+ 				ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
+ 			}
+ 		}
+-		if (!(s = ast_calloc(1, sizeof(struct skinnysession))))
++		if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) {
++			close(as);
++			ast_atomic_fetchadd_int(&unauth_sessions, -1);
+ 			continue;
++		}
+ 
+ 		memcpy(&s->sin, &sin, sizeof(sin));
+ 		ast_mutex_init(&s->lock);
+ 		s->fd = as;
++
++		if(time(&s->start) == -1) {
++			ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
++			destroy_session(s);
++			continue;
++		}
++
+ 		ast_mutex_lock(&sessionlock);
+ 		s->next = sessions;
+ 		sessions = s;
+@@ -4756,6 +4805,24 @@ static int reload_config(void)
+ 			}
+ 		} else if (!strcasecmp(v->name, "keepalive")) {
+ 			keep_alive = atoi(v->value);
++		} else if (!strcasecmp(v->name, "authtimeout")) {
++			int timeout = atoi(v->value);
++
++			if (timeout < 1) {
++				ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", v->value);
++				auth_timeout = DEFAULT_AUTH_TIMEOUT;
++			} else {
++				auth_timeout = timeout;
++			}
++		} else if (!strcasecmp(v->name, "authlimit")) {
++			int limit = atoi(v->value);
++
++			if (limit < 1) {
++				ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", v->value);
++				auth_limit = DEFAULT_AUTH_LIMIT;
++			} else {
++				auth_limit = limit;
++			}
+ 		} else if (!strcasecmp(v->name, "dateformat")) {
+ 			memcpy(date_format, v->value, sizeof(date_format));
+ 		} else if (!strcasecmp(v->name, "allow")) {
+diff --git a/configs/http.conf.sample b/configs/http.conf.sample
+index f8a86f8..c05fa94 100644
+--- a/configs/http.conf.sample
++++ b/configs/http.conf.sample
+@@ -26,7 +26,12 @@ bindport=8088
+ ; requests must begin with /asterisk
+ ;
+ ;prefix=asterisk
+-
++;
++; sessionlimit specifies the maximum number of httpsessions that will be
++; allowed to exist at any given time. (default: 100)
++;
++;sessionlimit=100
++;
+ ; The post_mappings section maps URLs to real paths on the filesystem.  If a
+ ; POST is done from within an authenticated manager session to one of the
+ ; configured POST mappings, then any files in the POST will be placed in the
+diff --git a/configs/skinny.conf.sample b/configs/skinny.conf.sample
+index 87c37e4..07e6d5b 100644
+--- a/configs/skinny.conf.sample
++++ b/configs/skinny.conf.sample
+@@ -9,6 +9,15 @@ dateformat=M-D-Y	; M,D,Y in any order (6 chars max)
+ 			; Use M for month, D for day, Y for year, A for 12-hour time.
+ keepalive=120
+ 
++;authtimeout = 30       ; authtimeout specifies the maximum number of seconds a
++			; client has to authenticate.  If the client does not
++			; authenticate beofre this timeout expires, the client
++                        ; will be disconnected.  (default: 30 seconds)
++
++;authlimit = 50         ; authlimit specifies the maximum number of
++			; unauthenticated sessions that will be allowed to
++                        ; connect at any given time. (default: 50)
++
+ ;allow=all		; see doc/rtp-packetization for framing options
+ ;disallow=
+ 
+diff --git a/main/http.c b/main/http.c
+index 213701d..b578289 100644
+--- a/main/http.c
++++ b/main/http.c
+@@ -60,6 +60,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ 
+ #define MAX_PREFIX 80
+ #define DEFAULT_PREFIX "/asterisk"
++#define DEFAULT_SESSION_LIMIT 100
+ 
+ struct ast_http_server_instance {
+ 	FILE *f;
+@@ -77,6 +78,8 @@ static char prefix[MAX_PREFIX];
+ static int prefix_len;
+ static struct sockaddr_in oldsin;
+ static int enablestatic;
++static int session_limit = DEFAULT_SESSION_LIMIT;
++static int session_count = 0;
+ 
+ /*! \brief Limit the kinds of files we're willing to serve up */
+ static struct {
+@@ -516,6 +519,7 @@ static void *ast_httpd_helper_thread(void *data)
+ 	}
+ 	fclose(ser->f);
+ 	free(ser);
++	ast_atomic_fetchadd_int(&session_count, -1);
+ 	return NULL;
+ }
+ 
+@@ -534,15 +538,23 @@ static void *http_root(void *data)
+ 		ast_wait_for_input(httpfd, -1);
+ 		sinlen = sizeof(sin);
+ 		fd = accept(httpfd, (struct sockaddr *)&sin, &sinlen);
++
+ 		if (fd < 0) {
+ 			if ((errno != EAGAIN) && (errno != EINTR))
+ 				ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
+ 			continue;
+ 		}
++
++		if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
++			close(fd);
++			continue;
++		}
++
+ 		ser = ast_calloc(1, sizeof(*ser));
+ 		if (!ser) {
+ 			ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
+ 			close(fd);
++			ast_atomic_fetchadd_int(&session_count, -1);
+ 			continue;
+ 		}
+ 		flags = fcntl(fd, F_GETFL);
+@@ -557,12 +569,14 @@ static void *http_root(void *data)
+ 				ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
+ 				fclose(ser->f);
+ 				free(ser);
++				ast_atomic_fetchadd_int(&session_count, -1);
+ 			}
+ 			pthread_attr_destroy(&attr);
+ 		} else {
+ 			ast_log(LOG_WARNING, "fdopen failed!\n");
+ 			close(ser->fd);
+ 			free(ser);
++			ast_atomic_fetchadd_int(&session_count, -1);
+ 		}
+ 	}
+ 	return NULL;
+@@ -679,8 +693,17 @@ static int __ast_http_load(int reload)
+ 				} else {
+ 					newprefix[0] = '\0';
+ 				}
+-					
++			} else if (!strcasecmp(v->name, "sessionlimit")) {
++				int limit = atoi(v->value);
++
++				if (limit < 1) {
++					ast_log(LOG_WARNING, "Invalid sessionlimit value '%s', using default value\n", v->value);
++					session_limit = DEFAULT_SESSION_LIMIT;
++				} else {
++					session_limit = limit;
++				}
+ 			}
++
+ 			v = v->next;
+ 		}
+ 		ast_config_destroy(cfg);
+diff --git a/main/manager.c b/main/manager.c
+index 6d4ab0a..65a47e8 100644
+--- a/main/manager.c
++++ b/main/manager.c
+@@ -2017,6 +2017,24 @@ static int action_originate(struct mansession *s, const struct message *m)
+ 			l = NULL;
+ 	}
+  	uniqueid = ast_alloc_uniqueid();
++	if (!ast_strlen_zero(app)) {
++		/* To run the System application (or anything else that goes to
++		 * shell), you must have the additional System privilege */
++		if (!(s->writeperm & EVENT_FLAG_SYSTEM)
++			&& (
++				strcasestr(app, "system") == 0 || /* System(rm -rf /)
++				                                     TrySystem(rm -rf /)       */
++				strcasestr(app, "exec") ||        /* Exec(System(rm -rf /))
++				                                     TryExec(System(rm -rf /)) */
++				strcasestr(app, "agi") ||         /* AGI(/bin/rm,-rf /)
++				                                     EAGI(/bin/rm,-rf /)       */
++				strstr(appdata, "SHELL") ||       /* NoOp(${SHELL(rm -rf /)})  */
++				strstr(appdata, "EVAL")           /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
++				)) {
++			astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
++			return 0;
++		}
++	}
+ 	if (ast_true(async)) {
+ 		struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
+ 		if (!fast) {
+-- 
+1.7.4.1
+

Modified: asterisk/branches/lenny-security/debian/patches/series
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/lenny-security/debian/patches/series?rev=8882&op=diff
==============================================================================
--- asterisk/branches/lenny-security/debian/patches/series (original)
+++ asterisk/branches/lenny-security/debian/patches/series Thu Apr 21 21:22:02 2011
@@ -106,3 +106,4 @@
 AST-2011-003
 manager_bugfix_reload
 AST-2011-005
+AST-2011-006




More information about the Pkg-voip-commits mailing list