summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2012-11-18 10:38:30 +0100
committerSebastien Helleu <flashcode@flashtux.org>2012-11-18 10:38:30 +0100
commitefb795c74fe954b9544074aafcebb1be4452b03a (patch)
treead48e01d3a394f2e981f9534585b050e3b5889cc /src
parentc1389f8fe19068790d29e39c3f94b71b8c33ea03 (diff)
downloadweechat-efb795c74fe954b9544074aafcebb1be4452b03a.zip
core: do not call shell to execute command in hook_process (fix security problem when a plugin/script gives untrusted command) (bug #37764)
Diffstat (limited to 'src')
-rw-r--r--src/core/wee-hook.c22
-rw-r--r--src/core/wee-string.c190
-rw-r--r--src/core/wee-string.h1
3 files changed, 209 insertions, 4 deletions
diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c
index d2d77da31..5e708d0d6 100644
--- a/src/core/wee-hook.c
+++ b/src/core/wee-hook.c
@@ -1388,9 +1388,9 @@ hook_process (struct t_weechat_plugin *plugin,
void
hook_process_child (struct t_hook *hook_process)
{
- char *exec_args[4] = { "sh", "-c", NULL, NULL };
+ char **exec_args;
const char *ptr_url;
- int rc;
+ int rc, i;
/*
* close stdin, so that process will fail to read stdin (process reading
@@ -1429,10 +1429,24 @@ hook_process_child (struct t_hook *hook_process)
else
{
/* launch command */
- exec_args[2] = HOOK_PROCESS(hook_process, command);
- execvp (exec_args[0], exec_args);
+ exec_args = string_split_shell (HOOK_PROCESS(hook_process, command));
+ if (exec_args)
+ {
+ if (weechat_debug_core >= 1)
+ {
+ log_printf ("hook_process, command='%s'",
+ HOOK_PROCESS(hook_process, command));
+ for (i = 0; exec_args[i]; i++)
+ {
+ log_printf (" args[%02d] == '%s'", i, exec_args[i]);
+ }
+ }
+ execvp (exec_args[0], exec_args);
+ }
/* should not be executed if execvp was ok */
+ if (exec_args)
+ string_free_split (exec_args);
fprintf (stderr, "Error with command '%s'\n",
HOOK_PROCESS(hook_process, command));
rc = EXIT_FAILURE;
diff --git a/src/core/wee-string.c b/src/core/wee-string.c
index 269663cb8..38dde2de1 100644
--- a/src/core/wee-string.c
+++ b/src/core/wee-string.c
@@ -1138,6 +1138,196 @@ string_split (const char *string, const char *separators, int keep_eol,
}
/*
+ * string_split_shell: split a string like the shell does for a command with
+ * arguments.
+ * Note: result must be freed with string_free_split.
+ * This function is a C conversion of python class "shlex"
+ * (file: Lib/shlex.py in python repository)
+ * Doc: http://docs.python.org/3/library/shlex.html
+ * Copyrights in shlex.py:
+ * Module and documentation by Eric S. Raymond, 21 Dec 1998
+ * Input stacking and error message cleanup added by ESR, March 2000
+ * push_source() and pop_source() made explicit by ESR, January 2001.
+ * Posix compliance, split(), string arguments, and
+ * iterator interface by Gustavo Niemeyer, April 2003.
+ */
+
+char **
+string_split_shell (const char *string)
+{
+ int temp_len, num_args, add_char_to_temp, add_temp_to_args, quoted;
+ char *string2, *temp, **args, **args2, state, escapedstate;
+ char *ptr_string, *ptr_next, saved_char;
+
+ if (!string)
+ return NULL;
+
+ string2 = strdup (string);
+ if (!string2)
+ return NULL;
+
+ /*
+ * prepare "args" with one pointer to NULL, the "args" will be reallocated
+ * later, each time a new argument is added
+ */
+ num_args = 0;
+ args = malloc ((num_args + 1) * sizeof (args[0]));
+ if (!args)
+ {
+ free (string2);
+ return NULL;
+ }
+ args[0] = NULL;
+
+ /* prepare a temp string for working (adding chars one by one) */
+ temp = malloc ((2 * strlen (string)) + 1);
+ if (!temp)
+ {
+ free (string2);
+ free (args);
+ return NULL;
+ }
+ temp[0] = '\0';
+ temp_len = 0;
+
+ state = ' ';
+ escapedstate = ' ';
+ quoted = 0;
+ ptr_string = string2;
+ while (ptr_string[0])
+ {
+ add_char_to_temp = 0;
+ add_temp_to_args = 0;
+ ptr_next = utf8_next_char (ptr_string);
+ saved_char = ptr_next[0];
+ ptr_next[0] = '\0';
+ if (state == ' ')
+ {
+ if ((ptr_string[0] == ' ') || (ptr_string[0] == '\t')
+ || (ptr_string[0] == '\r') || (ptr_string[0] == '\n'))
+ {
+ if (temp[0] || quoted)
+ add_temp_to_args = 1;
+ }
+ else if (ptr_string[0] == '\\')
+ {
+ escapedstate = 'a';
+ state = ptr_string[0];
+ }
+ else if ((ptr_string[0] == '\'') || (ptr_string[0] == '"'))
+ {
+ state = ptr_string[0];
+ }
+ else
+ {
+ add_char_to_temp = 1;
+ state = 'a';
+ }
+ }
+ else if ((state == '\'') || (state == '"'))
+ {
+ quoted = 1;
+ if (ptr_string[0] == state)
+ {
+ state = 'a';
+ }
+ else if ((state == '"') && (ptr_string[0] == '\\'))
+ {
+ escapedstate = state;
+ state = ptr_string[0];
+ }
+ else
+ {
+ add_char_to_temp = 1;
+ }
+ }
+ else if (state == '\\')
+ {
+ if (((escapedstate == '\'') || (escapedstate == '"'))
+ && (ptr_string[0] != state) && (ptr_string[0] != escapedstate))
+ {
+ temp[temp_len] = state;
+ temp_len++;
+ temp[temp_len] = '\0';
+ }
+ add_char_to_temp = 1;
+ state = escapedstate;
+ }
+ else if (state == 'a')
+ {
+ if ((ptr_string[0] == ' ') || (ptr_string[0] == '\t')
+ || (ptr_string[0] == '\r') || (ptr_string[0] == '\n'))
+ {
+ state = ' ';
+ if (temp[0] || quoted)
+ add_temp_to_args = 1;
+ }
+ else if (ptr_string[0] == '\\')
+ {
+ escapedstate = 'a';
+ state = ptr_string[0];
+ }
+ else if ((ptr_string[0] == '\'') || (ptr_string[0] == '"'))
+ {
+ state = ptr_string[0];
+ }
+ else
+ {
+ add_char_to_temp = 1;
+ }
+ }
+ if (add_char_to_temp)
+ {
+ memcpy (temp + temp_len, ptr_string, ptr_next - ptr_string);
+ temp_len += (ptr_next - ptr_string);
+ temp[temp_len] = '\0';
+ }
+ if (add_temp_to_args)
+ {
+ num_args++;
+ args2 = realloc (args, (num_args + 1) * sizeof (args[0]));
+ if (!args2)
+ {
+ free (string2);
+ free (temp);
+ return args;
+ }
+ args = args2;
+ args[num_args - 1] = strdup (temp);
+ args[num_args] = NULL;
+ temp[0] = '\0';
+ temp_len = 0;
+ escapedstate = ' ';
+ quoted = 0;
+ }
+ ptr_next[0] = saved_char;
+ ptr_string = ptr_next;
+ }
+
+ if (temp[0] || (state != ' '))
+ {
+ num_args++;
+ args2 = realloc (args, (num_args + 1) * sizeof (args[0]));
+ if (!args2)
+ {
+ free (string2);
+ free (temp);
+ return args;
+ }
+ args = args2;
+ args[num_args - 1] = strdup (temp);
+ args[num_args] = NULL;
+ temp[0] = '\0';
+ temp_len = 0;
+ }
+
+ free (string2);
+ free (temp);
+
+ return args;
+}
+
+/*
* string_free_split: free a split string
*/
diff --git a/src/core/wee-string.h b/src/core/wee-string.h
index a9fc76ea8..c0d017b17 100644
--- a/src/core/wee-string.h
+++ b/src/core/wee-string.h
@@ -59,6 +59,7 @@ extern int string_has_highlight_regex_compiled (const char *string,
extern int string_has_highlight_regex (const char *string, const char *regex);
extern char **string_split (const char *string, const char *separators,
int keep_eol, int num_items_max, int *num_items);
+extern char **string_split_shell (const char *string);
extern void string_free_split (char **split_string);
extern char *string_build_with_split_string (const char **split_string,
const char *separator);