mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-02 19:16:15 +00:00
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
This commit is contained in:
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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");
|
||||
|
@@ -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 (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;
|
||||
}
|
||||
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;
|
||||
|
@@ -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");
|
||||
|
Reference in New Issue
Block a user