Dr. Werner Fink 2014-09-30 12:41:44 +00:00 committed by Git OBS Bridge
parent 8e99efa814
commit 5a51f53431
7 changed files with 126 additions and 241 deletions

View File

@ -1,147 +0,0 @@
--- ../bash-4.2-orig/variables.c 2014-09-25 13:07:59.313209541 +0200
+++ variables.c 2014-09-25 13:15:29.869420719 +0200
@@ -268,7 +268,7 @@
static void propagate_temp_var __P((PTR_T));
static void dispose_temporary_env __P((sh_free_func_t *));
-static inline char *mk_env_string __P((const char *, const char *));
+static inline char *mk_env_string __P((const char *, const char *, int));
static char **make_env_array_from_var_list __P((SHELL_VAR **));
static char **make_var_export_array __P((VAR_CONTEXT *));
static char **make_func_export_array __P((void));
@@ -301,6 +301,14 @@
#endif
}
+/* Prefix and suffix for environment variable names which contain
+ shell functions. */
+#define FUNCDEF_PREFIX "BASH_FUNC_"
+#define FUNCDEF_PREFIX_LEN (strlen (FUNCDEF_PREFIX))
+#define FUNCDEF_SUFFIX "()"
+#define FUNCDEF_SUFFIX_LEN (strlen (FUNCDEF_SUFFIX))
+
+
/* Initialize the shell variables from the current environment.
If PRIVMODE is nonzero, don't import functions from ENV or
parse $SHELLOPTS. */
@@ -338,27 +346,39 @@
/* If exported function, define it now. Don't import functions from
the environment in privileged mode. */
- if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
- {
- string_length = strlen (string);
- temp_string = (char *)xmalloc (3 + string_length + char_index);
+ if (privmode == 0 && read_but_dont_execute == 0
+ && STREQN (FUNCDEF_PREFIX, name, FUNCDEF_PREFIX_LEN)
+ && STREQ (name + char_index - FUNCDEF_SUFFIX_LEN, FUNCDEF_SUFFIX)
+ && STREQN ("() {", string, 4))
+ {
+ size_t name_length
+ = char_index - (FUNCDEF_PREFIX_LEN + FUNCDEF_SUFFIX_LEN);
+ char *temp_name = name + FUNCDEF_PREFIX_LEN;
+ /* Temporarily remove the suffix. */
+ temp_name[name_length] = '\0';
- strcpy (temp_string, name);
- temp_string[char_index] = ' ';
- strcpy (temp_string + char_index + 1, string);
+ string_length = strlen (string);
+ temp_string = (char *)xmalloc (name_length + 1 + string_length + 1);
+ memcpy (temp_string, temp_name, name_length);
+ temp_string[name_length] = ' ';
+ memcpy (temp_string + name_length + 1, string, string_length + 1);
/* Don't import function names that are invalid identifiers from the
environment. */
- if (legal_identifier (name))
- parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
+ if (legal_identifier (temp_name))
+ parse_and_execute (temp_string, temp_name,
+ SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
- if (temp_var = find_function (name))
+ if (temp_var = find_function (temp_name))
{
VSETATTR (temp_var, (att_exported|att_imported));
array_needs_making = 1;
}
else
report_error (_("error importing function definition for `%s'"), name);
+
+ /* Restore the original suffix. */
+ temp_name[name_length] = FUNCDEF_SUFFIX[0];
}
#if defined (ARRAY_VARS)
# if 0
@@ -2537,7 +2557,7 @@
var->context = variable_context; /* XXX */
INVALIDATE_EXPORTSTR (var);
- var->exportstr = mk_env_string (name, value);
+ var->exportstr = mk_env_string (name, value, 0);
array_needs_making = 1;
@@ -3388,22 +3408,43 @@
/* */
/* **************************************************************** */
+/* Returns the string NAME=VALUE if !FUNCTIONP or if VALUE == NULL (in
+ which case it is treated as empty). Otherwise, decorate NAME with
+ FUNCDEF_PREFIX and FUNCDEF_SUFFIX, and return a string of the form
+ FUNCDEF_PREFIX NAME FUNCDEF_SUFFIX = VALUE (without spaces). */
static inline char *
-mk_env_string (name, value)
+mk_env_string (name, value, functionp)
const char *name, *value;
+ int functionp;
{
- int name_len, value_len;
- char *p;
+ size_t name_len, value_len;
+ char *p, *q;
name_len = strlen (name);
value_len = STRLEN (value);
- p = (char *)xmalloc (2 + name_len + value_len);
- strcpy (p, name);
- p[name_len] = '=';
+ if (functionp && value != NULL)
+ {
+ p = (char *)xmalloc (FUNCDEF_PREFIX_LEN + name_len + FUNCDEF_SUFFIX_LEN
+ + 1 + value_len + 1);
+ q = p;
+ memcpy (q, FUNCDEF_PREFIX, FUNCDEF_PREFIX_LEN);
+ q += FUNCDEF_PREFIX_LEN;
+ memcpy (q, name, name_len);
+ q += name_len;
+ memcpy (q, FUNCDEF_SUFFIX, FUNCDEF_SUFFIX_LEN);
+ q += FUNCDEF_SUFFIX_LEN;
+ }
+ else
+ {
+ p = (char *)xmalloc (name_len + 1 + value_len + 1);
+ memcpy (p, name, name_len);
+ q = p + name_len;
+ }
+ q[0] = '=';
if (value && *value)
- strcpy (p + name_len + 1, value);
+ memcpy (q + 1, value, value_len + 1);
else
- p[name_len + 1] = '\0';
+ q[1] = '\0';
return (p);
}
@@ -3489,7 +3530,7 @@
/* Gee, I'd like to get away with not using savestring() if we're
using the cached exportstr... */
list[list_index] = USE_EXPORTSTR ? savestring (value)
- : mk_env_string (var->name, value);
+ : mk_env_string (var->name, value, function_p (var));
if (USE_EXPORTSTR == 0)
SAVE_EXPORTSTR (var, list[list_index]);

View File

@ -1,72 +0,0 @@
*** ../bash-4.2.47/builtins/common.h 2010-05-30 18:31:51.000000000 -0400
--- builtins/common.h 2014-09-16 19:35:45.000000000 -0400
***************
*** 36,39 ****
--- 36,41 ----
/* Flags for describe_command, shared between type.def and command.def */
+ #define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
+ #define SEVAL_ONECMD 0x100 /* only allow a single command */
#define CDESC_ALL 0x001 /* type -a */
#define CDESC_SHORTDESC 0x002 /* command -V */
*** ../bash-4.2.47/builtins/evalstring.c 2010-11-23 08:22:15.000000000 -0500
--- builtins/evalstring.c 2014-09-16 19:35:45.000000000 -0400
***************
*** 262,265 ****
--- 262,273 ----
struct fd_bitmap *bitmap;
+ if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
+ {
+ internal_warning ("%s: ignoring function definition attempt", from_file);
+ should_jump_to_top_level = 0;
+ last_result = last_command_exit_value = EX_BADUSAGE;
+ break;
+ }
+
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
begin_unwind_frame ("pe_dispose");
***************
*** 322,325 ****
--- 330,336 ----
dispose_fd_bitmap (bitmap);
discard_unwind_frame ("pe_dispose");
+
+ if (flags & SEVAL_ONECMD)
+ break;
}
}
*** ../bash-4.2.47/variables.c 2011-03-01 16:15:20.000000000 -0500
--- variables.c 2014-09-16 19:35:45.000000000 -0400
***************
*** 348,357 ****
strcpy (temp_string + char_index + 1, string);
! parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
!
! /* Ancient backwards compatibility. Old versions of bash exported
! functions like name()=() {...} */
! if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
! name[char_index - 2] = '\0';
if (temp_var = find_function (name))
--- 348,355 ----
strcpy (temp_string + char_index + 1, string);
! /* Don't import function names that are invalid identifiers from the
! environment. */
! if (legal_identifier (name))
! parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
if (temp_var = find_function (name))
***************
*** 362,369 ****
else
report_error (_("error importing function definition for `%s'"), name);
-
- /* ( */
- if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
- name[char_index - 2] = '('; /* ) */
}
#if defined (ARRAY_VARS)
--- 360,363 ----

View File

@ -1,11 +0,0 @@
*** ../bash-20140912/parse.y 2014-08-26 15:09:42.000000000 -0400
--- parse.y 2014-09-24 22:47:28.000000000 -0400
***************
*** 2959,2962 ****
--- 2959,2964 ----
word_desc_to_read = (WORD_DESC *)NULL;
+ eol_ungetc_lookahead = 0;
+
current_token = '\n'; /* XXX */
last_read_token = '\n';

View File

@ -0,0 +1,104 @@
---
builtins/shopt.def | 2 ++
doc/bash.1 | 7 +++++++
shell.c | 2 ++
variables.c | 13 ++++++++++++-
4 files changed, 23 insertions(+), 1 deletion(-)
--- shell.c
+++ shell.c 2014-09-25 20:11:51.000000000 +0000
@@ -225,6 +225,7 @@ int posixly_correct = 1; /* Non-zero mea
#else
int posixly_correct = 0; /* Non-zero means posix.2 superset. */
#endif
+int import_functions = IMPORT_FUNCTIONS_DEF; /* Import functions from environment */
/* Some long-winded argument names. These are obviously new. */
#define Int 1
@@ -244,6 +245,7 @@ static const struct {
{ "help", Int, &want_initial_help, (char **)0x0 },
{ "init-file", Charp, (int *)0x0, &bashrc_file },
{ "login", Int, &make_login_shell, (char **)0x0 },
+ { "import-functions", Int, &import_functions, (char **)0x0 },
{ "noediting", Int, &no_line_editing, (char **)0x0 },
{ "noprofile", Int, &no_profile, (char **)0x0 },
{ "norc", Int, &no_rc, (char **)0x0 },
--- variables.c
+++ variables.c 2014-09-30 11:54:58.994735738 +0000
@@ -105,6 +105,7 @@ extern time_t shell_start_time;
extern int assigning_in_environment;
extern int executing_builtin;
extern int funcnest_max;
+extern int import_functions;
#if defined (READLINE)
extern int no_line_editing;
@@ -317,6 +318,7 @@ initialize_shell_variables (env, privmod
char *name, *string, *temp_string;
int c, char_index, string_index, string_length;
SHELL_VAR *temp_var;
+ int skipped_import;
create_variable_tables ();
@@ -341,9 +343,12 @@ initialize_shell_variables (env, privmod
temp_var = (SHELL_VAR *)NULL;
+ skipped_import = 0;
+ reval:
+
/* If exported function, define it now. Don't import functions from
the environment in privileged mode. */
- if (privmode == 0 && read_but_dont_execute == 0 &&
+ if (skipped_import == 0 && privmode == 0 && read_but_dont_execute == 0 &&
STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
STREQN ("() {", string, 4))
@@ -356,6 +361,12 @@ initialize_shell_variables (env, privmod
tname = name + BASHFUNC_PREFLEN; /* start of func name */
tname[namelen] = '\0'; /* now tname == func name */
+ if (!import_functions && !interactive_shell) {
+ skipped_import = 1;
+ report_error (_("Skipping importing function definition for `%s': --import-functions required."), tname);
+ goto reval;
+ }
+
string_length = strlen (string);
temp_string = (char *)xmalloc (namelen + string_length + 2);
--- builtins/shopt.def
+++ builtins/shopt.def 2014-09-30 11:58:13.714235365 +0000
@@ -89,6 +89,7 @@ extern int check_jobs_at_exit;
extern int autocd;
extern int glob_star;
extern int lastpipe_opt;
+extern int import_functions;
#if defined (EXTENDED_GLOB)
extern int extended_glob;
@@ -186,6 +187,7 @@ static struct {
{ "hostcomplete", &perform_hostname_completion, shopt_enable_hostname_completion },
#endif
{ "huponexit", &hup_on_exit, (shopt_set_func_t *)NULL },
+ { "import-functions", &import_functions, (shopt_set_func_t *)NULL },
{ "interactive_comments", &interactive_comments, set_shellopts_after_change },
{ "lastpipe", &lastpipe_opt, (shopt_set_func_t *)NULL },
#if defined (HISTORY)
--- doc/bash.1
+++ doc/bash.1 2014-09-30 12:09:39.698234623 +0000
@@ -235,6 +235,13 @@ The shell becomes restricted (see
.B "RESTRICTED SHELL"
below).
.TP
+.B \-\-import\-functions
+This shell is patched in such a way that shell functions in the inported environment
+will not be expanded due several security issues (e.g. CVE\-2014\-6271). This option
+can be used to enable this. It is also possible to use the
+.B shopt
+builtin to do this.
+.TP
.B \-\-verbose
Equivalent to \fB\-v\fP.
.TP

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b15040afefabd2017251ba76e7babebfa3dede73aec769923fb6662cdf909027
size 28878
oid sha256:b20d686fcaf734b53799990a1c3c734094753a08ef4b3184f76ffe8789ae4236
size 30957

View File

@ -1,3 +1,16 @@
-------------------------------------------------------------------
Tue Sep 30 11:45:52 UTC 2014 - werner@suse.de
- Remove and replace patches
bash-4.2-CVE-2014-6271.patch
bash-4.2-BSC898604.patch
bash-4.2-CVE-2014-7169.patch
with bash upstream patch 48, patch 49, and patch 50
- Add patch bash-4.2-extra-import-func.patch which is based on the
BSD patch of Christos. As further enhancements the option
import-functions is mentioned in the manual page and a shopt
switch is added to enable and disable import-functions on the fly
-------------------------------------------------------------------
Fri Sep 26 11:07:24 UTC 2014 - werner@suse.de

View File

@ -99,10 +99,9 @@ Patch42: audit-patch
Patch43: audit-rl-patch
Patch46: man2html-no-timestamp.patch
Patch47: config-guess-sub-update.patch
# PATCH-FIX-UPSTREAM bnc#895475 -- bnc#896776, CVE-2014-6271: unexpected code execution with environment variables
Patch48: bash-4.2-CVE-2014-6271.patch
Patch49: bash-4.2-BSC898604.patch
Patch50: bash-4.2-CVE-2014-7169.patch
# PATCH-FIX-SUSE CVE-2014-6271
Patch48: bash-4.2-extra-import-func.patch
# PATCH-FIX-SUSE CVE-2014-7187
Patch51: bash-4.2-CVE-2014-7187.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%global _sysconfdir /etc
@ -324,10 +323,8 @@ done
%patch42 -p1 -b .audit
%endif
%patch46 -p0 -b .notimestamp
%patch47
%patch48 -p2
%patch49 -p0
%patch50 -p0
%patch47 -p0
%patch48 -p0
%patch51 -p0
%patch0 -p0 -b .0
pushd ../readline-%{rl_vers}%{extend}
@ -435,6 +432,7 @@ pushd ../readline-%{rl_vers}%{extend}
cflags -ftree-loop-linear CFLAGS
cflags -pipe CFLAGS
cflags -DBNC382214=0 CFLAGS
cflags -DIMPORT_FUNCTIONS_DEF=0 CFLAGS
cflags -Wl,--as-needed LDFLAGS
cflags -Wl,-O2 LDFLAGS
cflags -Wl,--hash-size=8599 LDFLAGS
@ -560,10 +558,10 @@ popd
all printenv recho zecho xcase
TMPDIR=$(mktemp -d /tmp/bash.XXXXXXXXXX) || exit 1
> $SCREENLOG
tail -q -s 0.5 -f $SCREENLOG & pid=$!
env -i HOME=$PWD TERM=$TERM LD_LIBRARY_PATH=$LD_LIBRARY_PATH TMPDIR=$TMPDIR \
SCREENRC=$SCREENRC SCREENDIR=$SCREENDIR \
screen -L -D -m make TESTSCRIPT=%{SOURCE4} check
cat $SCREENLOG
make %{?do_profiling:CFLAGS="$CFLAGS %cflags_profile_feedback" clean} all
make -C examples/loadables/
make documentation