diff options
author | David M. Lee <dlee@digium.com> | 2013-12-16 19:11:51 +0000 |
---|---|---|
committer | David M. Lee <dlee@digium.com> | 2013-12-16 19:11:51 +0000 |
commit | 744556c01d6e28d4ae46c347f77edfb71778d924 (patch) | |
tree | bc90f83b4ec9ef0eafb3d952076bf9ea24406366 /funcs | |
parent | 00dcee2a640394ac0aae294396d96985c6c1aba1 (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.c | 20 | ||||
-rw-r--r-- | funcs/func_env.c | 28 | ||||
-rw-r--r-- | funcs/func_lock.c | 21 | ||||
-rw-r--r-- | funcs/func_realtime.c | 62 | ||||
-rw-r--r-- | funcs/func_shell.c | 18 |
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"); |