summaryrefslogtreecommitdiff
path: root/funcs
diff options
context:
space:
mode:
authorDavid M. Lee <dlee@digium.com>2013-12-16 19:11:51 +0000
committerDavid M. Lee <dlee@digium.com>2013-12-16 19:11:51 +0000
commit744556c01d6e28d4ae46c347f77edfb71778d924 (patch)
treebc90f83b4ec9ef0eafb3d952076bf9ea24406366 /funcs
parent00dcee2a640394ac0aae294396d96985c6c1aba1 (diff)
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. Also, the ABI was changed to something more reasonable, since Asterisk 12 does not yet have a public release. (closes issue ASTERISK-22905) Review: http://reviewboard.digium.internal/r/432/ ........ Merged revisions 403913 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 403917 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 403959 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403960 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'funcs')
-rw-r--r--funcs/func_db.c20
-rw-r--r--funcs/func_env.c28
-rw-r--r--funcs/func_lock.c21
-rw-r--r--funcs/func_realtime.c62
-rw-r--r--funcs/func_shell.c18
5 files changed, 114 insertions, 35 deletions
diff --git a/funcs/func_db.c b/funcs/func_db.c
index 20c8829a6..ebe58f02e 100644
--- a/funcs/func_db.c
+++ b/funcs/func_db.c
@@ -110,6 +110,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<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>
@@ -311,10 +317,22 @@ static int function_db_delete(struct ast_channel *chan, const char *cmd,
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)
@@ -335,7 +353,7 @@ static int load_module(void)
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);
res |= ast_custom_function_register(&db_keys_function);
return res;
diff --git a/funcs/func_env.c b/funcs/func_env.c
index f413607e0..a2f7c2bd2 100644
--- a/funcs/func_env.c
+++ b/funcs/func_env.c
@@ -71,6 +71,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<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 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<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 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
</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 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<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>
@@ -1259,10 +1279,10 @@ static int load_module(void)
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;
}
diff --git a/funcs/func_lock.c b/funcs/func_lock.c
index d8db10e84..2102d5c9a 100644
--- a/funcs/func_lock.c
+++ b/funcs/func_lock.c
@@ -59,6 +59,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<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 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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 unload_module(void)
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");
diff --git a/funcs/func_realtime.c b/funcs/func_realtime.c
index 886b5b456..a870ab450 100644
--- a/funcs/func_realtime.c
+++ b/funcs/func_realtime.c
@@ -115,6 +115,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<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 @@ static int function_realtime_readdestroy(struct ast_channel *chan, const char *c
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;
- }
+ 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);
+ /* 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_copy_string(buf, ast_str_buffer(out), len);
ast_destroy_realtime(args.family, args.fieldmatch, args.value, SENTINEL);
ast_variables_destroy(head);
@@ -471,6 +481,15 @@ static int function_realtime_readdestroy(struct ast_channel *chan, const char *c
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 = {
.name = "REALTIME",
.read = function_realtime_read,
@@ -496,6 +515,7 @@ static struct ast_custom_function realtime_store_function = {
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 @@ static int load_module(void)
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;
diff --git a/funcs/func_shell.c b/funcs/func_shell.c
index bad10b381..e403efc2e 100644
--- a/funcs/func_shell.c
+++ b/funcs/func_shell.c
@@ -88,11 +88,17 @@ static int shell_helper(struct ast_channel *chan, const char *cmd, char *data,
</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 unload_module(void)
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");