[asterisk-commits] bebuild: tag 1.8.24.1 r403961 - in /tags/1.8.24.1: ./ apps/ configs/ funcs/ i...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Dec 16 13:17:20 CST 2013
Author: bebuild
Date: Mon Dec 16 13:17:17 2013
New Revision: 403961
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=403961
Log:
Update 1.8.24.1
* Merge AST-2013-006
* Merge AST-2013-007
Modified:
tags/1.8.24.1/ (props changed)
tags/1.8.24.1/ChangeLog
tags/1.8.24.1/README-SERIOUSLY.bestpractices.txt
tags/1.8.24.1/UPGRADE.txt
tags/1.8.24.1/apps/app_sms.c
tags/1.8.24.1/configs/asterisk.conf.sample
tags/1.8.24.1/funcs/func_db.c
tags/1.8.24.1/funcs/func_env.c
tags/1.8.24.1/funcs/func_lock.c
tags/1.8.24.1/funcs/func_realtime.c
tags/1.8.24.1/funcs/func_shell.c
tags/1.8.24.1/include/asterisk/pbx.h
tags/1.8.24.1/main/asterisk.c
tags/1.8.24.1/main/pbx.c
tags/1.8.24.1/main/tcptls.c
Propchange: tags/1.8.24.1/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Dec 16 13:17:17 2013
@@ -1,1 +1,1 @@
-/branches/1.8:401178
+/branches/1.8:401178,403853,403913
Modified: tags/1.8.24.1/ChangeLog
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/ChangeLog?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/ChangeLog (original)
+++ tags/1.8.24.1/ChangeLog Mon Dec 16 13:17:17 2013
@@ -1,3 +1,32 @@
+2013-12-16 Asterisk Development Team <asteriskteam at digium.com>
+
+ * Asterisk 1.8.24.1 Released.
+
+ * AST-2013-006 - app_sms: BufferOverflow when receiving odd length 16
+ bit message
+
+ This patch prevents an infinite loop overwriting memory when a
+ message is received into the unpacksms16() function, where the length
+ of the message is an odd number of bytes.
+ (closes issue ASTERISK-22590)
+
+ * AST-2013-007 - security: Inhibit execution of privilege escalating
+ functions
+
+ This patch allows individual dialplan functions to be marked as
+ 'dangerous', to inhibit their execution from external sources.
+
+ A 'dangerous' function is one which results in a privilege
+ escalation. For example, if one were to read the channel variable
+ SHELL(rm -rf /) Bad Things(TM) could happen; even if the external
+ source has only read permissions.
+
+ Execution from external sources may be enabled by setting
+ 'live_dangerously' to 'yes' in the [options] section of
+ asterisk.conf. Although doing so is not recommended.
+
+ (closes issue ASTERISK-22905)
+
2013-10-21 Asterisk Development Team <asteriskteam at digium.com>
* Asterisk 1.8.24.0 Released.
Modified: tags/1.8.24.1/README-SERIOUSLY.bestpractices.txt
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/README-SERIOUSLY.bestpractices.txt?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/README-SERIOUSLY.bestpractices.txt (original)
+++ tags/1.8.24.1/README-SERIOUSLY.bestpractices.txt Mon Dec 16 13:17:17 2013
@@ -25,6 +25,9 @@
* Manager Class Authorizations:
Recognizing potential issues with certain classes of authorization
+
+* Avoid Privilege Escalations:
+ Disable the ability to execute functions that may escalate privileges
----------------
Additional Links
@@ -344,3 +347,24 @@
not running Asterisk as root, can prevent serious problems from arising when
allowing external connections to originate calls into Asterisk.
+===========================
+Avoid Privilege Escalations
+===========================
+
+External control protocols, such as Manager, often have the ability to get and
+set channel variables; which allows the execution of dialplan functions.
+
+Dialplan functions within Asterisk are incredibly powerful, which is wonderful
+for building applications using Asterisk. But during the read or write
+execution, certain diaplan functions do much more. For example, reading the
+SHELL() function can execute arbitrary commands on the system Asterisk is
+running on. Writing to the FILE() function can change any file that Asterisk has
+write access to.
+
+When these functions are executed from an external protocol, that execution
+could result in a privilege escalation. Asterisk can inhibit the execution of
+these functions, if live_dangerously in the [options] section of asterisk.conf
+is set to no.
+
+For backwards compatibility, live_dangerously defaults to yes, and must be
+explicitly set to no to enable this privilege escalation protection.
Modified: tags/1.8.24.1/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/UPGRADE.txt?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/UPGRADE.txt (original)
+++ tags/1.8.24.1/UPGRADE.txt Mon Dec 16 13:17:17 2013
@@ -23,6 +23,14 @@
the function will be RESULT_FAILURE instead of the prior behavior of always
returning RESULT_SUCCESS even if there was an error.
+* Certain dialplan functions have been marked as 'dangerous', and may only be
+ executed from the dialplan. Execution from extenal sources (AMI's GetVar and
+ SetVar actions; etc.) may be inhibited by setting live_dangerously in the
+ [options] section of asterisk.conf to no. SHELL(), channel locking, and direct
+ file read/write functions are marked as dangerous. DB_DELETE() and
+ REALTIME_DESTROY() are marked as dangerous for reads, but can now safely
+ accept writes (which ignore the provided value).
+
from 1.8.22.0 to 1.8.23.0:
* The default settings for chan_sip are now overriden properly by the general
settings in sip.conf. Please look over your settings upon upgrading.
Modified: tags/1.8.24.1/apps/app_sms.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/apps/app_sms.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/apps/app_sms.c (original)
+++ tags/1.8.24.1/apps/app_sms.c Mon Dec 16 13:17:17 2013
@@ -696,7 +696,7 @@
}
while (l--) {
int v = *i++;
- if (l--) {
+ if (l && l--) {
v = (v << 8) + *i++;
}
*o++ = v;
@@ -714,6 +714,7 @@
} else if (is8bit(dcs)) {
unpacksms8(i, l, udh, udhl, ud, udl, udhi);
} else {
+ l += l % 2;
unpacksms16(i, l, udh, udhl, ud, udl, udhi);
}
return l + 1;
Modified: tags/1.8.24.1/configs/asterisk.conf.sample
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/configs/asterisk.conf.sample?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/configs/asterisk.conf.sample (original)
+++ tags/1.8.24.1/configs/asterisk.conf.sample Mon Dec 16 13:17:17 2013
@@ -73,6 +73,12 @@
;lockconfdir = no ; Protect the directory containing the
; configuration files (/etc/asterisk) with a
; lock.
+;live_dangerously = no ; Enable the execution of 'dangerous' dialplan
+ ; functions from external sources (AMI,
+ ; etc.) These functions (such as SHELL) are
+ ; considered dangerous because they can allow
+ ; privilege escalation.
+ ; Default yes, for backward compatability.
; Changing the following lines may compromise your security.
;[files]
Modified: tags/1.8.24.1/funcs/func_db.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/funcs/func_db.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/funcs/func_db.c (original)
+++ tags/1.8.24.1/funcs/func_db.c Mon Dec 16 13:17:17 2013
@@ -97,6 +97,12 @@
<para>This function will retrieve a value from the Asterisk database
and then remove that key from the database. <variable>DB_RESULT</variable>
will be set to the key's value if it exists.</para>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be read from the
+ dialplan, and not directly from external protocols. It can, however, be
+ executed as a write operation (<literal>DB_DELETE(family, key)=ignored</literal>)</para>
+ </note>
</description>
<see-also>
<ref type="application">DBdel</ref>
@@ -243,10 +249,22 @@
return 0;
}
+/*!
+ * \brief Wrapper to execute DB_DELETE from a write operation. Allows execution
+ * even if live_dangerously is disabled.
+ */
+static int function_db_delete_write(struct ast_channel *chan, const char *cmd, char *parse,
+ const char *value)
+{
+ /* Throwaway to hold the result from the read */
+ char buf[128];
+ return function_db_delete(chan, cmd, parse, buf, sizeof(buf));
+}
static struct ast_custom_function db_delete_function = {
.name = "DB_DELETE",
.read = function_db_delete,
+ .write = function_db_delete_write,
};
static int unload_module(void)
@@ -266,7 +284,7 @@
res |= ast_custom_function_register(&db_function);
res |= ast_custom_function_register(&db_exists_function);
- res |= ast_custom_function_register(&db_delete_function);
+ res |= ast_custom_function_register_escalating(&db_delete_function, AST_CFE_READ);
return res;
}
Modified: tags/1.8.24.1/funcs/func_env.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/funcs/func_env.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/funcs/func_env.c (original)
+++ tags/1.8.24.1/funcs/func_env.c Mon Dec 16 13:17:17 2013
@@ -71,6 +71,11 @@
<parameter name="filename" required="true" />
</syntax>
<description>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be executed from the
+ dialplan, and not directly from external protocols.</para>
+ </note>
</description>
</function>
<function name="FILE" language="en_US">
@@ -167,6 +172,11 @@
<para> Set(FILE(/tmp/foo.txt,-1,,l)=bar)</para>
<para> ; Append "bar" to the file with a newline</para>
<para> Set(FILE(/tmp/foo.txt,,,al)=bar)</para>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be executed from the
+ dialplan, and not directly from external protocols.</para>
+ </note>
</description>
<see-also>
<ref type="function">FILE_COUNT_LINE</ref>
@@ -197,6 +207,11 @@
</syntax>
<description>
<para>Returns the number of lines, or <literal>-1</literal> on error.</para>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be executed from the
+ dialplan, and not directly from external protocols.</para>
+ </note>
</description>
<see-also>
<ref type="function">FILE</ref>
@@ -216,6 +231,11 @@
<para>'d' - DOS "\r\n" format</para>
<para>'m' - Macintosh "\r" format</para>
<para>'x' - Cannot be determined</para>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be executed from the
+ dialplan, and not directly from external protocols.</para>
+ </note>
</description>
<see-also>
<ref type="function">FILE</ref>
@@ -1258,10 +1278,10 @@
int res = 0;
res |= ast_custom_function_register(&env_function);
- res |= ast_custom_function_register(&stat_function);
- res |= ast_custom_function_register(&file_function);
- res |= ast_custom_function_register(&file_count_line_function);
- res |= ast_custom_function_register(&file_format_function);
+ res |= ast_custom_function_register_escalating(&stat_function, AST_CFE_READ);
+ res |= ast_custom_function_register_escalating(&file_function, AST_CFE_BOTH);
+ res |= ast_custom_function_register_escalating(&file_count_line_function, AST_CFE_READ);
+ res |= ast_custom_function_register_escalating(&file_format_function, AST_CFE_READ);
return res;
}
Modified: tags/1.8.24.1/funcs/func_lock.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/funcs/func_lock.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/funcs/func_lock.c (original)
+++ tags/1.8.24.1/funcs/func_lock.c Mon Dec 16 13:17:17 2013
@@ -59,6 +59,11 @@
Returns <literal>1</literal> if the lock was obtained or <literal>0</literal> on error.</para>
<note><para>To avoid the possibility of a deadlock, LOCK will only attempt to
obtain the lock for 3 seconds if the channel already has another lock.</para></note>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be executed from the
+ dialplan, and not directly from external protocols.</para>
+ </note>
</description>
</function>
<function name="TRYLOCK" language="en_US">
@@ -72,6 +77,11 @@
<para>Attempts to grab a named lock exclusively, and prevents other channels
from obtaining the same lock. Returns <literal>1</literal> if the lock was
available or <literal>0</literal> otherwise.</para>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be executed from the
+ dialplan, and not directly from external protocols.</para>
+ </note>
</description>
</function>
<function name="UNLOCK" language="en_US">
@@ -86,6 +96,11 @@
had a lock or <literal>0</literal> otherwise.</para>
<note><para>It is generally unnecessary to unlock in a hangup routine, as any locks
held are automatically freed when the channel is destroyed.</para></note>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be executed from the
+ dialplan, and not directly from external protocols.</para>
+ </note>
</description>
</function>
***/
@@ -502,9 +517,9 @@
static int load_module(void)
{
- int res = ast_custom_function_register(&lock_function);
- res |= ast_custom_function_register(&trylock_function);
- res |= ast_custom_function_register(&unlock_function);
+ int res = ast_custom_function_register_escalating(&lock_function, AST_CFE_READ);
+ res |= ast_custom_function_register_escalating(&trylock_function, AST_CFE_READ);
+ res |= ast_custom_function_register_escalating(&unlock_function, AST_CFE_READ);
if (ast_pthread_create_background(&broker_tid, NULL, lock_broker, NULL)) {
ast_log(LOG_ERROR, "Failed to start lock broker thread. Unloading func_lock module.\n");
Modified: tags/1.8.24.1/funcs/func_realtime.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/funcs/func_realtime.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/funcs/func_realtime.c (original)
+++ tags/1.8.24.1/funcs/func_realtime.c Mon Dec 16 13:17:17 2013
@@ -115,6 +115,12 @@
<description>
<para>This function acts in the same way as REALTIME(....) does, except that
it destroys the matched record in the RT engine.</para>
+ <note>
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be read from the
+ dialplan, and not directly from external protocols. It can, however, be
+ executed as a write operation (<literal>REALTIME_DESTROY(family, fieldmatch)=ignored</literal>)</para>
+ </note>
</description>
<see-also>
<ref type="function">REALTIME</ref>
@@ -439,28 +445,32 @@
return -1;
}
- resultslen = 0;
- n = 0;
- for (var = head; var; n++, var = var->next)
- resultslen += strlen(var->name) + strlen(var->value);
- /* add space for delimiters and final '\0' */
- resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
-
- if (resultslen > len) {
- /* Unfortunately this does mean that we cannot destroy the row
- * anymore. But OTOH, we're not destroying someones data without
- * giving him the chance to look at it. */
- ast_log(LOG_WARNING, "Failed to fetch/destroy. Realtime data is too large: need %zu, have %zu.\n", resultslen, len);
- return -1;
- }
-
- /* len is going to be sensible, so we don't need to check for stack
- * overflows here. */
- out = ast_str_alloca(resultslen);
- for (var = head; var; var = var->next) {
- ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
- }
- ast_copy_string(buf, ast_str_buffer(out), len);
+ if (len > 0) {
+ resultslen = 0;
+ n = 0;
+ for (var = head; var; n++, var = var->next) {
+ resultslen += strlen(var->name) + strlen(var->value);
+ }
+ /* add space for delimiters and final '\0' */
+ resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
+
+ if (resultslen > len) {
+ /* Unfortunately this does mean that we cannot destroy
+ * the row anymore. But OTOH, we're not destroying
+ * someones data without giving him the chance to look
+ * at it. */
+ ast_log(LOG_WARNING, "Failed to fetch/destroy. Realtime data is too large: need %zu, have %zu.\n", resultslen, len);
+ return -1;
+ }
+
+ /* len is going to be sensible, so we don't need to check for
+ * stack overflows here. */
+ out = ast_str_alloca(resultslen);
+ for (var = head; var; var = var->next) {
+ ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
+ }
+ ast_copy_string(buf, ast_str_buffer(out), len);
+ }
ast_destroy_realtime(args.family, args.fieldmatch, args.value, SENTINEL);
ast_variables_destroy(head);
@@ -469,6 +479,15 @@
ast_autoservice_stop(chan);
return 0;
+}
+
+/*!
+ * \brief Wrapper to execute REALTIME_DESTROY from a write operation. Allows
+ * execution even if live_dangerously is disabled.
+ */
+static int function_realtime_writedestroy(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ return function_realtime_readdestroy(chan, cmd, data, NULL, 0);
}
static struct ast_custom_function realtime_function = {
@@ -496,6 +515,7 @@
static struct ast_custom_function realtime_destroy_function = {
.name = "REALTIME_DESTROY",
.read = function_realtime_readdestroy,
+ .write = function_realtime_writedestroy,
};
static int unload_module(void)
@@ -514,7 +534,7 @@
int res = 0;
res |= ast_custom_function_register(&realtime_function);
res |= ast_custom_function_register(&realtime_store_function);
- res |= ast_custom_function_register(&realtime_destroy_function);
+ res |= ast_custom_function_register_escalating(&realtime_destroy_function, AST_CFE_READ);
res |= ast_custom_function_register(&realtimefield_function);
res |= ast_custom_function_register(&realtimehash_function);
return res;
Modified: tags/1.8.24.1/funcs/func_shell.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/funcs/func_shell.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/funcs/func_shell.c (original)
+++ tags/1.8.24.1/funcs/func_shell.c Mon Dec 16 13:17:17 2013
@@ -88,11 +88,17 @@
</syntax>
<description>
<para>Collects the output generated by a command executed by the system shell</para>
- <para>Example: <literal>Set(foo=${SHELL(echo \bar\)})</literal></para>
- <note><para>The command supplied to this function will be executed by the
- system's shell, typically specified in the SHELL environment variable. There
- are many different system shells available with somewhat different behaviors,
- so the output generated by this function may vary between platforms.</para></note>
+ <para>Example: <literal>Set(foo=${SHELL(echo bar)})</literal></para>
+ <note>
+ <para>The command supplied to this function will be executed by the
+ system's shell, typically specified in the SHELL environment variable. There
+ are many different system shells available with somewhat different behaviors,
+ so the output generated by this function may vary between platforms.</para>
+
+ <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
+ is set to <literal>no</literal>, this function can only be executed from the
+ dialplan, and not directly from external protocols.</para>
+ </note>
</description>
</function>
@@ -109,7 +115,7 @@
static int load_module(void)
{
- return ast_custom_function_register(&shell_function);
+ return ast_custom_function_register_escalating(&shell_function, AST_CFE_READ);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Collects the output generated by a command executed by the system shell");
Modified: tags/1.8.24.1/include/asterisk/pbx.h
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/include/asterisk/pbx.h?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/include/asterisk/pbx.h (original)
+++ tags/1.8.24.1/include/asterisk/pbx.h Mon Dec 16 13:17:17 2013
@@ -1139,14 +1139,42 @@
int ast_custom_function_unregister(struct ast_custom_function *acf);
/*!
+ * \brief Description of the ways in which a function may escalate privileges.
+ */
+enum ast_custom_function_escalation {
+ AST_CFE_NONE,
+ AST_CFE_READ,
+ AST_CFE_WRITE,
+ AST_CFE_BOTH,
+};
+
+/*!
* \brief Register a custom function
*/
#define ast_custom_function_register(acf) __ast_custom_function_register(acf, ast_module_info->self)
/*!
+ * \brief Register a custom function which requires escalated privileges.
+ *
+ * Examples would be SHELL() (for which a read needs permission to execute
+ * arbitrary code) or FILE() (for which write needs permission to change files
+ * on the filesystem).
+ */
+#define ast_custom_function_register_escalating(acf, escalation) __ast_custom_function_register_escalating(acf, escalation, ast_module_info->self)
+
+/*!
* \brief Register a custom function
*/
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod);
+
+/*!
+ * \brief Register a custom function which requires escalated privileges.
+ *
+ * Examples would be SHELL() (for which a read needs permission to execute
+ * arbitrary code) or FILE() (for which write needs permission to change files
+ * on the filesystem).
+ */
+int __ast_custom_function_register_escalating(struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod);
/*!
* \brief Retrieve the number of active calls
@@ -1261,6 +1289,32 @@
*/
char *ast_complete_applications(const char *line, const char *word, int state);
+/*!
+ * \brief Enable/disable the execution of 'dangerous' functions from external
+ * protocols (AMI, etc.).
+ *
+ * These dialplan functions (such as \c SHELL) provide an opportunity for
+ * privilege escalation. They are okay to invoke from the dialplan, but external
+ * protocols with permission controls should not normally invoke them.
+ *
+ * This function can globally enable/disable the execution of dangerous
+ * functions from external protocols.
+ *
+ * \param new_live_dangerously If true, enable the execution of escalating
+ * functions from external protocols.
+ */
+void pbx_live_dangerously(int new_live_dangerously);
+
+/*!
+ * \brief Inhibit (in the current thread) the execution of dialplan functions
+ * which cause privilege escalations. If pbx_live_dangerously() has been
+ * called, this function has no effect.
+ *
+ * \return 0 if successfuly marked current thread.
+ * \return Non-zero if marking current thread failed.
+ */
+int ast_thread_inhibit_escalations(void);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
Modified: tags/1.8.24.1/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/main/asterisk.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/main/asterisk.c (original)
+++ tags/1.8.24.1/main/asterisk.c Mon Dec 16 13:17:17 2013
@@ -3030,6 +3030,8 @@
unsigned int dbdir:1;
unsigned int keydir:1;
} found = { 0, 0 };
+ /* Default to true for backward compatibility */
+ int live_dangerously = 1;
if (ast_opt_override_config) {
cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
@@ -3239,8 +3241,11 @@
ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
} else if (!strcasecmp(v->name, "lockconfdir")) {
ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
- }
- }
+ } else if (!strcasecmp(v->name, "live_dangerously")) {
+ live_dangerously = ast_true(v->value);
+ }
+ }
+ pbx_live_dangerously(live_dangerously);
for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
float version;
if (sscanf(v->value, "%30f", &version) != 1) {
Modified: tags/1.8.24.1/main/pbx.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/main/pbx.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/main/pbx.c (original)
+++ tags/1.8.24.1/main/pbx.c Mon Dec 16 13:17:17 2013
@@ -821,6 +821,17 @@
AST_THREADSTORAGE(switch_data);
AST_THREADSTORAGE(extensionstate_buf);
+/*!
+ * \brief A thread local indicating whether the current thread can run
+ * 'dangerous' dialplan functions.
+ */
+AST_THREADSTORAGE(thread_inhibit_escalations_tl);
+
+/*!
+ * \brief Set to true (non-zero) to globally allow all dangerous dialplan
+ * functions to run.
+ */
+static int live_dangerously;
/*!
\brief ast_exten: An extension
@@ -1165,6 +1176,19 @@
static int totalcalls;
static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
+
+/*!
+ * \brief Extra information for an \ref ast_custom_function holding privilege
+ * escalation information. Kept in a separate structure for ABI compatibility.
+ */
+struct ast_custom_escalating_function {
+ AST_RWLIST_ENTRY(ast_custom_escalating_function) list;
+ const struct ast_custom_function *acf;
+ unsigned int read_escalates:1;
+ unsigned int write_escalates:1;
+};
+
+static AST_RWLIST_HEAD_STATIC(escalation_root, ast_custom_escalating_function);
/*! \brief Declaration of builtin applications */
static struct pbx_builtin {
@@ -3739,6 +3763,7 @@
int ast_custom_function_unregister(struct ast_custom_function *acf)
{
struct ast_custom_function *cur;
+ struct ast_custom_escalating_function *cur_escalation;
if (!acf) {
return -1;
@@ -3755,7 +3780,62 @@
}
AST_RWLIST_UNLOCK(&acf_root);
+ /* Remove from the escalation list */
+ AST_RWLIST_WRLOCK(&escalation_root);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&escalation_root, cur_escalation, list) {
+ if (cur_escalation->acf == acf) {
+ AST_RWLIST_REMOVE_CURRENT(list);
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&escalation_root);
+
return cur ? 0 : -1;
+}
+
+/*!
+ * \brief Returns true if given custom function escalates privileges on read.
+ *
+ * \param acf Custom function to query.
+ * \return True (non-zero) if reads escalate privileges.
+ * \return False (zero) if reads just read.
+ */
+static int read_escalates(const struct ast_custom_function *acf) {
+ int res = 0;
+ struct ast_custom_escalating_function *cur_escalation;
+
+ AST_RWLIST_RDLOCK(&escalation_root);
+ AST_RWLIST_TRAVERSE(&escalation_root, cur_escalation, list) {
+ if (cur_escalation->acf == acf) {
+ res = cur_escalation->read_escalates;
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&escalation_root);
+ return res;
+}
+
+/*!
+ * \brief Returns true if given custom function escalates privileges on write.
+ *
+ * \param acf Custom function to query.
+ * \return True (non-zero) if writes escalate privileges.
+ * \return False (zero) if writes just write.
+ */
+static int write_escalates(const struct ast_custom_function *acf) {
+ int res = 0;
+ struct ast_custom_escalating_function *cur_escalation;
+
+ AST_RWLIST_RDLOCK(&escalation_root);
+ AST_RWLIST_TRAVERSE(&escalation_root, cur_escalation, list) {
+ if (cur_escalation->acf == acf) {
+ res = cur_escalation->write_escalates;
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&escalation_root);
+ return res;
}
/*! \internal
@@ -3859,6 +3939,50 @@
return 0;
}
+int __ast_custom_function_register_escalating(struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod)
+{
+ struct ast_custom_escalating_function *acf_escalation = NULL;
+ int res;
+
+ res = __ast_custom_function_register(acf, mod);
+ if (res != 0) {
+ return -1;
+ }
+
+ if (escalation == AST_CFE_NONE) {
+ /* No escalations; no need to do anything else */
+ return 0;
+ }
+
+ acf_escalation = ast_calloc(1, sizeof(*acf_escalation));
+ if (!acf_escalation) {
+ ast_custom_function_unregister(acf);
+ return -1;
+ }
+
+ acf_escalation->acf = acf;
+ switch (escalation) {
+ case AST_CFE_NONE:
+ break;
+ case AST_CFE_READ:
+ acf_escalation->read_escalates = 1;
+ break;
+ case AST_CFE_WRITE:
+ acf_escalation->write_escalates = 1;
+ break;
+ case AST_CFE_BOTH:
+ acf_escalation->read_escalates = 1;
+ acf_escalation->write_escalates = 1;
+ break;
+ }
+
+ AST_RWLIST_WRLOCK(&escalation_root);
+ AST_RWLIST_INSERT_TAIL(&escalation_root, acf_escalation, list);
+ AST_RWLIST_UNLOCK(&escalation_root);
+
+ return 0;
+}
+
/*! \brief return a pointer to the arguments of the function,
* and terminates the function name with '\\0'
*/
@@ -3880,6 +4004,124 @@
return args;
}
+void pbx_live_dangerously(int new_live_dangerously)
+{
+ if (new_live_dangerously && !live_dangerously) {
+ ast_log(LOG_WARNING, "Privilege escalation protection disabled!\n"
+ "See https://wiki.asterisk.org/wiki/x/1gKfAQ for more details.\n");
+ }
+
+ if (!new_live_dangerously && live_dangerously) {
+ ast_log(LOG_NOTICE, "Privilege escalation protection enabled.\n");
+ }
+ live_dangerously = new_live_dangerously;
+}
+
+int ast_thread_inhibit_escalations(void)
+{
+ int *thread_inhibit_escalations;
+
+ thread_inhibit_escalations = ast_threadstorage_get(
+ &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
+
+ if (thread_inhibit_escalations == NULL) {
+ ast_log(LOG_ERROR, "Error inhibiting privilege escalations for current thread\n");
+ return -1;
+ }
+
+ *thread_inhibit_escalations = 1;
+ return 0;
+}
+
+/*!
+ * \brief Indicates whether the current thread inhibits the execution of
+ * dangerous functions.
+ *
+ * \return True (non-zero) if dangerous function execution is inhibited.
+ * \return False (zero) if dangerous function execution is allowed.
+ */
+static int thread_inhibits_escalations(void)
+{
+ int *thread_inhibit_escalations;
+
+ thread_inhibit_escalations = ast_threadstorage_get(
+ &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
+
+ if (thread_inhibit_escalations == NULL) {
+ ast_log(LOG_ERROR, "Error checking thread's ability to run dangerous functions\n");
+ /* On error, assume that we are inhibiting */
+ return 1;
+ }
+
+ return *thread_inhibit_escalations;
+}
+
+/*!
+ * \brief Determines whether execution of a custom function's read function
+ * is allowed.
+ *
+ * \param acfptr Custom function to check
+ * \return True (non-zero) if reading is allowed.
+ * \return False (zero) if reading is not allowed.
+ */
+static int is_read_allowed(struct ast_custom_function *acfptr)
+{
+ if (!acfptr) {
+ return 1;
+ }
+
+ if (!read_escalates(acfptr)) {
+ return 1;
+ }
+
+ if (!thread_inhibits_escalations()) {
+ return 1;
+ }
+
+ if (live_dangerously) {
+ /* Global setting overrides the thread's preference */
+ ast_debug(2, "Reading %s from a dangerous context\n",
+ acfptr->name);
+ return 1;
+ }
+
+ /* We have no reason to allow this function to execute */
+ return 0;
+}
+
+/*!
+ * \brief Determines whether execution of a custom function's write function
+ * is allowed.
+ *
+ * \param acfptr Custom function to check
+ * \return True (non-zero) if writing is allowed.
+ * \return False (zero) if writing is not allowed.
+ */
+static int is_write_allowed(struct ast_custom_function *acfptr)
+{
+ if (!acfptr) {
+ return 1;
+ }
+
+ if (!write_escalates(acfptr)) {
+ return 1;
+ }
+
+ if (!thread_inhibits_escalations()) {
+ return 1;
+ }
+
+ if (live_dangerously) {
+ /* Global setting overrides the thread's preference */
+ ast_debug(2, "Writing %s from a dangerous context\n",
+ acfptr->name);
+ return 1;
+ }
+
+ /* We have no reason to allow this function to execute */
+ return 0;
+}
+
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
{
char *copy = ast_strdupa(function);
@@ -3892,6 +4134,8 @@
ast_log(LOG_ERROR, "Function %s not registered\n", copy);
} else if (!acfptr->read && !acfptr->read2) {
ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
+ } else if (!is_read_allowed(acfptr)) {
+ ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
} else if (acfptr->read) {
if (acfptr->mod) {
u = __ast_module_user_add(acfptr->mod, chan);
@@ -3929,6 +4173,8 @@
ast_log(LOG_ERROR, "Function %s not registered\n", copy);
} else if (!acfptr->read && !acfptr->read2) {
ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
+ } else if (!is_read_allowed(acfptr)) {
+ ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
} else {
if (acfptr->mod) {
u = __ast_module_user_add(acfptr->mod, chan);
@@ -3968,11 +4214,13 @@
char *args = func_args(copy);
struct ast_custom_function *acfptr = ast_custom_function_find(copy);
- if (acfptr == NULL)
+ if (acfptr == NULL) {
ast_log(LOG_ERROR, "Function %s not registered\n", copy);
- else if (!acfptr->write)
+ } else if (!acfptr->write) {
ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
- else {
+ } else if (!is_write_allowed(acfptr)) {
+ ast_log(LOG_ERROR, "Dangerous function %s write blocked\n", copy);
+ } else {
int res;
struct ast_module_user *u = NULL;
if (acfptr->mod)
Modified: tags/1.8.24.1/main/tcptls.c
URL: http://svnview.digium.com/svn/asterisk/tags/1.8.24.1/main/tcptls.c?view=diff&rev=403961&r1=403960&r2=403961
==============================================================================
--- tags/1.8.24.1/main/tcptls.c (original)
+++ tags/1.8.24.1/main/tcptls.c Mon Dec 16 13:17:17 2013
@@ -48,6 +48,7 @@
#include "asterisk/options.h"
#include "asterisk/manager.h"
#include "asterisk/astobj2.h"
+#include "asterisk/pbx.h"
/*! \brief
* replacement read/write functions for SSL support.
@@ -160,6 +161,16 @@
int ret;
char err[256];
#endif
+
+ /* TCP/TLS connections are associated with external protocols, and
+ * should not be allowed to execute 'dangerous' functions. This may
+ * need to be pushed down into the individual protocol handlers, but
+ * this seems like a good general policy.
+ */
+ if (ast_thread_inhibit_escalations()) {
+ ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection\n");
+ return NULL;
+ }
/*
* open a FILE * as appropriate.
More information about the asterisk-commits
mailing list