mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-09-25 10:32:11 +02:00
fixes to the included last-ditch termcap library to avoid buffer overflows due to malicious termcap strings; rework TMOUT handling to avoid running code in a SIGALRM handler; new -L option for help builtin to display short docs one per line; send input timeout message to syslog if SYSLOG_HISTORY is defined
This commit is contained in:
@@ -13360,3 +13360,50 @@ parse.y
|
||||
builtins/history.def
|
||||
- history_builtin: history -r should increase history_lines_this_session
|
||||
only if *not* reading from $HISTFILE
|
||||
|
||||
9/8
|
||||
---
|
||||
configure.ac,config.h.in
|
||||
- check for malloc.h, malloc/malloc.h, malloc_usable_size(), and
|
||||
malloc_size()
|
||||
|
||||
9/9
|
||||
---
|
||||
lib/termcap/tparam.c
|
||||
- tparam1: takes a new argument, the number of elements in ARGS
|
||||
- tparam1: add bounds checks for overflow due to malicious termcap
|
||||
entry directives that consume or advance elements in ARGS
|
||||
Report from "monsterd0n" <kaslovdmitri1@gmail.com>
|
||||
|
||||
lib/termcap/termcap.c
|
||||
- tgetent: ignore the buffer passed to tgetent and use a locally-
|
||||
allocated buffer (TERMENTBUF), keeping track of its size in a local
|
||||
variable (ENTBUFSIZE). This prevents crashes from an excessively
|
||||
long malicious termcap entry
|
||||
- find_usable_size: new function to attempt to determine the usable
|
||||
area in the buffer passed to tgetstr; max at TERMSTR_BUFFER_MAX (1024)
|
||||
if functions aren't available
|
||||
- tgetstr: attempt to find bounds in buffer passed to tgetstr right
|
||||
after tgetent fetches a new termcap entry
|
||||
- tgetstr: if we can detect the end of the buffer passed to tgetstr,
|
||||
check for overflow when copying malicious termcap capability strings.
|
||||
This prevents crashes due to excessively long malicious capability
|
||||
strings
|
||||
Report from "monsterd0n" <kaslovdmitri1@gmail.com>
|
||||
|
||||
eval.c
|
||||
- alrm_handler: if SYSLOG_HISTORY is defined, send the timeout message
|
||||
to syslog as well
|
||||
From https://savannah.gnu.org/patch/?10542
|
||||
|
||||
builtins/help.def
|
||||
- help_builtin: new -L option to display all help topics, one per line
|
||||
- disprow, wdisprow: new functions to display one help topic per line,
|
||||
single-byte and wide-character versions
|
||||
- increase portion of short doc displayed in multi-column or single-
|
||||
column mode to 256 chars in single-byte locales (multibyte locales
|
||||
use wide chars and allocate the buffer dynamically)
|
||||
|
||||
doc/bash.1,doc/bashref.texi
|
||||
- help: document new -L option
|
||||
Feature suggestion from https://lists.gnu.org/archive/html/bug-bash/2026-06/msg00064.html
|
||||
|
||||
+91
-8
@@ -35,6 +35,8 @@ Options:
|
||||
-m display usage in pseudo-manpage format
|
||||
-s output only a short usage synopsis for each topic matching
|
||||
PATTERN
|
||||
-L when displaying the list of help topics, display one topic
|
||||
per line
|
||||
|
||||
Arguments:
|
||||
PATTERN Pattern specifying a help topic
|
||||
@@ -76,10 +78,12 @@ $END
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define MAX_SHORTDOC_WIDTH 256
|
||||
|
||||
extern const char * const bash_copyright;
|
||||
extern const char * const bash_license;
|
||||
|
||||
static void show_builtin_command_help (void);
|
||||
static void show_builtin_command_help (int);
|
||||
static int open_helpfile (const char *);
|
||||
static void show_desc (char *, int);
|
||||
static void show_manpage (char *, int);
|
||||
@@ -93,12 +97,12 @@ help_builtin (WORD_LIST *list)
|
||||
{
|
||||
int i;
|
||||
char *pattern, *name;
|
||||
int match_found, sflag, dflag, mflag, m, pass, this_found, globpat;
|
||||
int match_found, sflag, dflag, mflag, Lflag, m, pass, this_found, globpat;
|
||||
size_t plen;
|
||||
|
||||
dflag = sflag = mflag = 0;
|
||||
dflag = sflag = mflag = Lflag = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((i = internal_getopt (list, "dms")) != -1)
|
||||
while ((i = internal_getopt (list, "dmsL")) != -1)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
@@ -111,6 +115,9 @@ help_builtin (WORD_LIST *list)
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
case 'L':
|
||||
Lflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
@@ -122,7 +129,7 @@ help_builtin (WORD_LIST *list)
|
||||
if (list == 0)
|
||||
{
|
||||
show_shell_version (0);
|
||||
show_builtin_command_help ();
|
||||
show_builtin_command_help (Lflag == 0);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -408,6 +415,24 @@ dispcolumn (int i, char *buf, size_t bufsize, int width, int height)
|
||||
printf ("%s\n", buf);
|
||||
}
|
||||
|
||||
static void
|
||||
disprow (int i, char *buf, size_t bufsize, int width)
|
||||
{
|
||||
int j;
|
||||
size_t dispcols;
|
||||
char *helpdoc;
|
||||
|
||||
helpdoc = _(shell_builtins[i].short_doc);
|
||||
|
||||
buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
|
||||
if (width > bufsize)
|
||||
width = bufsize;
|
||||
strncpy (buf + 1, helpdoc, width - 2);
|
||||
buf[width - 2] = '>'; /* indicate truncation */
|
||||
buf[width - 1] = '\0';
|
||||
printf ("%s\n", buf);
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static void
|
||||
wdispcolumn (int i, char *buf, size_t bufsize, int width, int height)
|
||||
@@ -470,7 +495,7 @@ wdispcolumn (int i, char *buf, size_t bufsize, int width, int height)
|
||||
/* second column */
|
||||
helpdoc = _(shell_builtins[i+height].short_doc);
|
||||
slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
|
||||
if (slen == -1)
|
||||
if (slen == (size_t)-1)
|
||||
{
|
||||
/* for now */
|
||||
printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
|
||||
@@ -508,14 +533,56 @@ wdispcolumn (int i, char *buf, size_t bufsize, int width, int height)
|
||||
|
||||
free (wcstr);
|
||||
}
|
||||
|
||||
static void
|
||||
wdisprow (int i, char *buf, size_t bufsize, int width)
|
||||
{
|
||||
char *helpdoc;
|
||||
wchar_t *wcstr;
|
||||
size_t slen, n, j;
|
||||
int dispchars, dispcols;
|
||||
|
||||
helpdoc = _(shell_builtins[i].short_doc);
|
||||
|
||||
wcstr = 0;
|
||||
slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
|
||||
if (slen == (size_t)-1)
|
||||
{
|
||||
disprow (i, buf, bufsize, width);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate the number of characters to display similarly to multicolum view */
|
||||
if (slen >= width)
|
||||
slen = width - 2;
|
||||
wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
|
||||
n = mbstowcs (wcstr+1, helpdoc, slen + 1);
|
||||
wcstr[n+1] = L'\0';
|
||||
for (j = 1; j < n; j++)
|
||||
if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
|
||||
wcstr[j] = L' ';
|
||||
dispchars = wcsnwidth (wcstr+1, slen, width - 2);
|
||||
dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
|
||||
|
||||
wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
|
||||
|
||||
if (dispcols >= width-2)
|
||||
{
|
||||
wcstr[dispchars] = L'>'; /* indicate truncation */
|
||||
wcstr[dispchars+1] = L'\0';
|
||||
}
|
||||
|
||||
printf ("%ls\n", wcstr);
|
||||
free (wcstr);
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
static void
|
||||
show_builtin_command_help (void)
|
||||
show_builtin_command_help (int usecols)
|
||||
{
|
||||
int i;
|
||||
int height, width;
|
||||
char *t, blurb[128];
|
||||
char *t, blurb[MAX_SHORTDOC_WIDTH];
|
||||
|
||||
printf (
|
||||
_("These shell commands are defined internally. Type `help' to see this list.\n\
|
||||
@@ -528,6 +595,22 @@ A star (*) next to a name means that the command is disabled.\n\
|
||||
|
||||
width = default_columns ();
|
||||
|
||||
if (usecols == 0)
|
||||
{
|
||||
for (i = 0; i < num_shell_builtins; i++)
|
||||
{
|
||||
QUIT;
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1)
|
||||
wdisprow (i, blurb, sizeof (blurb), width);
|
||||
else
|
||||
#endif
|
||||
disprow (i, blurb, sizeof (blurb), width);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
width /= 2;
|
||||
if (width > sizeof (blurb))
|
||||
width = sizeof (blurb);
|
||||
|
||||
+12
-3
@@ -757,6 +757,12 @@
|
||||
/* Define if you have the locale_charset function. */
|
||||
#undef HAVE_LOCALE_CHARSET
|
||||
|
||||
/* Define if you have the malloc_size function. */
|
||||
#undef HAVE_MALLOC_SIZE
|
||||
|
||||
/* Define if you have the malloc_usable_size function. */
|
||||
#undef HAVE_MALLOC_USABLE_SIZE
|
||||
|
||||
/* Define if you have the mbrlen function. */
|
||||
#undef HAVE_MBRLEN
|
||||
|
||||
@@ -1050,6 +1056,12 @@
|
||||
/* Define if you have the <locale.h> header file. */
|
||||
#undef HAVE_LOCALE_H
|
||||
|
||||
/* Define if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
/* Define if you have the <malloc/malloc.h> header file (macOS). */
|
||||
#undef HAVE_MALLOC_MALLOC_H
|
||||
|
||||
/* Define if you have the <mbstr.h> header file. */
|
||||
#undef HAVE_MBSTR_H
|
||||
|
||||
@@ -1266,9 +1278,6 @@
|
||||
|
||||
#undef HAVE_INTTYPES_H_WITH_UINTMAX
|
||||
|
||||
/* Define if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
#undef HAVE_STDINT_H_WITH_UINTMAX
|
||||
|
||||
/* Define if you have the <stdio_ext.h> header file. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#! /bin/sh
|
||||
# From configure.ac for Bash 5.4, version 5.085.
|
||||
# From configure.ac for Bash 5.4, version 5.086.
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.72 for bash 5.4-devel.
|
||||
#
|
||||
@@ -15211,6 +15211,19 @@ then :
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_header_compile "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_malloc_h" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_MALLOC_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_header_compile "$LINENO" "malloc/malloc.h" "ac_cv_header_malloc_malloc_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_malloc_malloc_h" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_MALLOC_MALLOC_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
ac_fn_c_check_header_compile "$LINENO" "sys/ptem.h" "ac_cv_header_sys_ptem_h" "
|
||||
#if HAVE_SYS_STREAM_H
|
||||
@@ -16149,6 +16162,25 @@ then :
|
||||
fi
|
||||
|
||||
|
||||
if test "$opt_bash_malloc" = "no" ; then
|
||||
ac_fn_c_check_func "$LINENO" "malloc_usable_size" "ac_cv_func_malloc_usable_size"
|
||||
if test "x$ac_cv_func_malloc_usable_size" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_MALLOC_USABLE_SIZE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_func "$LINENO" "malloc_size" "ac_cv_func_malloc_size"
|
||||
if test "x$ac_cv_func_malloc_size" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_MALLOC_SIZE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
else
|
||||
printf "%s\n" "#define HAVE_MALLOC_USABLE_SIZE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd"
|
||||
if test "x$ac_cv_func_getcwd" = xyes
|
||||
then :
|
||||
@@ -16877,12 +16909,6 @@ if test "x$ac_cv_header_fcntl_h" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_header_compile "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_malloc_h" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_MALLOC_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_header_compile "$LINENO" "stdio_ext.h" "ac_cv_header_stdio_ext_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_stdio_ext_h" = xyes
|
||||
|
||||
+9
-2
@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_REVISION([for Bash 5.4, version 5.085])dnl
|
||||
AC_REVISION([for Bash 5.4, version 5.086])dnl
|
||||
|
||||
define(bashvers, 5.4)
|
||||
define(relstatus, devel)
|
||||
@@ -816,6 +816,7 @@ AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \
|
||||
sys/mman.h sys/param.h sys/random.h sys/socket.h sys/stat.h \
|
||||
sys/time.h sys/times.h sys/types.h sys/wait.h)
|
||||
AC_CHECK_HEADERS(netinet/in.h arpa/inet.h)
|
||||
AC_CHECK_HEADERS([malloc.h malloc/malloc.h])
|
||||
|
||||
dnl sys/ptem.h requires definitions from sys/stream.h on systems where it
|
||||
dnl exists
|
||||
@@ -900,6 +901,12 @@ AC_CHECK_FUNCS(strlcat)
|
||||
|
||||
AC_CHECK_FUNCS(memfd_create shm_open shm_mkstemp)
|
||||
|
||||
if test "$opt_bash_malloc" = "no" ; then
|
||||
AC_CHECK_FUNCS(malloc_usable_size malloc_size)
|
||||
else
|
||||
AC_DEFINE(HAVE_MALLOC_USABLE_SIZE)
|
||||
fi
|
||||
|
||||
AC_REPLACE_FUNCS(getcwd memset)
|
||||
AC_REPLACE_FUNCS(strcasecmp strcasestr strerror strftime strnlen strpbrk strstr)
|
||||
AC_REPLACE_FUNCS(strtod strtol strtoul strtoll strtoull strtoumax)
|
||||
@@ -952,7 +959,7 @@ dnl Checks for lib/intl and related code (uses some of the output from
|
||||
dnl BASH_GNU_GETTEXT)
|
||||
dnl
|
||||
|
||||
AC_CHECK_HEADERS([argz.h errno.h fcntl.h malloc.h stdio_ext.h])
|
||||
AC_CHECK_HEADERS([argz.h errno.h fcntl.h stdio_ext.h])
|
||||
|
||||
dnl AC_FUNC_MALLOC
|
||||
AC_DEFINE([HAVE_MALLOC])
|
||||
|
||||
+8
-3
@@ -5,7 +5,7 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet.ramey@case.edu
|
||||
.\"
|
||||
.\" Last Change: Thu Aug 27 12:59:58 EDT 2026
|
||||
.\" Last Change: Wed Sep 9 14:19:33 EDT 2026
|
||||
.\"
|
||||
.\" For bash_builtins, strip all but "SHELL BUILTIN COMMANDS" section
|
||||
.\" For rbash, strip all but "RESTRICTED SHELL" section
|
||||
@@ -22,7 +22,7 @@
|
||||
.ds zX \" empty
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2026 August 27" "GNU Bash 5.4"
|
||||
.TH BASH 1 "2026 September 9" "GNU Bash 5.4"
|
||||
.\"
|
||||
.ie \n(.g \{\
|
||||
.ds ' \(aq
|
||||
@@ -10761,7 +10761,7 @@ The return status is zero unless a
|
||||
.I name
|
||||
is not found or an invalid option is supplied.
|
||||
.TP
|
||||
\fBhelp\fP [\fB\-dms\fP] [\fIpattern\fP]
|
||||
\fBhelp\fP [\fB\-dmsL\fP] [\fIpattern\fP]
|
||||
Display helpful information about builtin commands.
|
||||
If
|
||||
.I pattern
|
||||
@@ -10785,6 +10785,11 @@ Display the description of each \fIpattern\fP in a manpage-like format
|
||||
.TP
|
||||
.B \-s
|
||||
Display only a short usage synopsis for each \fIpattern\fP
|
||||
.TP
|
||||
.B \-L
|
||||
When displaying a list of all the builtins and shell compound commands,
|
||||
display each item using a single column
|
||||
instead of using multiple columns.
|
||||
.PD
|
||||
.RE
|
||||
.IP
|
||||
|
||||
+5
-1
@@ -5391,7 +5391,7 @@ or there is an error loading a new builtin from a shared object.
|
||||
@item help
|
||||
@btindex help
|
||||
@example
|
||||
help [-dms] [@var{pattern}]
|
||||
help [-dmsL] [@var{pattern}]
|
||||
@end example
|
||||
|
||||
Display helpful information about builtin commands.
|
||||
@@ -5410,6 +5410,10 @@ Display a short description of each @var{pattern}
|
||||
Display the description of each @var{pattern} in a manpage-like format
|
||||
@item -s
|
||||
Display only a short usage synopsis for each @var{pattern}
|
||||
@item -L
|
||||
When displaying a list of all the builtins and shell compound commands,
|
||||
display each item using a single column
|
||||
instead of using multiple columns.
|
||||
@end table
|
||||
|
||||
If @var{pattern} contains pattern matching characters
|
||||
|
||||
+3
-3
@@ -2,10 +2,10 @@
|
||||
Copyright (C) 1988-2026 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Thu Aug 27 13:00:35 EDT 2026
|
||||
@set LASTCHANGE Wed Sep 9 14:20:26 EDT 2026
|
||||
|
||||
@set EDITION 5.4
|
||||
@set VERSION 5.4
|
||||
|
||||
@set UPDATED 27 August 2026
|
||||
@set UPDATED-MONTH August 2026
|
||||
@set UPDATED 9 September 2026
|
||||
@set UPDATED-MONTH September 2026
|
||||
|
||||
@@ -277,9 +277,16 @@ alrm_catcher (int i)
|
||||
static void
|
||||
alrm_handler(int i)
|
||||
{
|
||||
printf ("\007%s\n", _("timed out waiting for input: auto-logout"));
|
||||
char *msg;
|
||||
|
||||
msg = _("timed out waiting for input: auto-logout");
|
||||
printf ("\007%s\n", msg);
|
||||
fflush (stdout);
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
bash_syslog_history (msg);
|
||||
#endif
|
||||
|
||||
tcflush (fileno (stdin), TCIFLUSH);
|
||||
bash_logout (); /* run ~/.bash_logout if this is a login shell */
|
||||
jump_to_top_level (EXITPROG);
|
||||
|
||||
@@ -239,6 +239,8 @@ pid_t last_procsub_pid = NO_PID;
|
||||
where the shell would defer them. */
|
||||
int want_job_notifications = 0;
|
||||
|
||||
int waitonce = 0;
|
||||
|
||||
/* Functions local to this file. */
|
||||
|
||||
void debug_print_pgrps (void);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* jobs.h -- structures and definitions used by the jobs.c file. */
|
||||
|
||||
/* Copyright (C) 1993-2024 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1993-2026 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -232,6 +232,7 @@ extern pid_t original_pgrp, shell_pgrp, pipeline_pgrp;
|
||||
extern volatile pid_t last_made_pid, last_asynchronous_pid;
|
||||
extern int asynchronous_notification;
|
||||
extern int want_job_notifications;
|
||||
extern int waitonce;
|
||||
|
||||
extern int already_making_children;
|
||||
extern int running_in_background;
|
||||
|
||||
+110
-27
@@ -1,6 +1,6 @@
|
||||
/* termcap.c - Work-alike for termcap, plus extra features. */
|
||||
|
||||
/* Copyright (C) 1985, 1986, 1993,1994, 1995, 1998, 2001,2003,2005,2006,2008,2009 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1985, 1986, 1993,1994, 1995, 1998, 2001,2003,2005,2006,2008,2009,2026 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -46,6 +46,10 @@ extern char *realloc ();
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDDEF_H
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#else /* not HAVE_CONFIG_H */
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
@@ -66,8 +70,19 @@ char *realloc ();
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_STDDEF_H
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#endif /* not HAVE_CONFIG_H */
|
||||
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
#ifdef HAVE_MALLOC_MALLOC_H
|
||||
# include <malloc/malloc.h>
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (char *) 0
|
||||
#endif
|
||||
@@ -99,6 +114,8 @@ int bufsize = 128;
|
||||
#define TERMCAP_FILE "/etc/termcap"
|
||||
#endif
|
||||
|
||||
#define TERMSTR_BUFSIZE_MAX 1024
|
||||
|
||||
#ifndef emacs
|
||||
static void memory_out (void);
|
||||
static void *xmalloc (size_t);
|
||||
@@ -141,6 +158,28 @@ static char *term_entry;
|
||||
static char *find_capability (char *, char *);
|
||||
static char *tgetst1 (char *, char **);
|
||||
|
||||
/* This means that the data in termentbuf is valid and we should try to
|
||||
find the end of the memory buffer pointed to by *area in tgetstr so
|
||||
we can perform some bounds checking. */
|
||||
static int reset_strbuf = 0;
|
||||
|
||||
static char *tgetstr_base = NULL;
|
||||
static char *tgetstr_end = NULL;
|
||||
|
||||
static size_t area_bufsize = 0;
|
||||
|
||||
static inline size_t
|
||||
find_usable_size (char *ptr)
|
||||
{
|
||||
#if defined (HAVE_MALLOC_USABLE_SIZE)
|
||||
return (malloc_usable_size (ptr));
|
||||
#elif defined (HAVE_MALLOC_SIZE)
|
||||
return (malloc_size (ptr));
|
||||
#else
|
||||
return TERMSTR_BUFSIZE_MAX; /* cap it at 1024 */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Search entry BP for capability CAP.
|
||||
Return a pointer to the capability (in BP) if found,
|
||||
0 if not found. */
|
||||
@@ -226,10 +265,24 @@ tgetst1 (char *ptr, char **area)
|
||||
while ((c = *p++) && c != ':' && c != '\n')
|
||||
;
|
||||
ret = (char *) xmalloc (p - ptr + 1);
|
||||
reset_strbuf = 0;
|
||||
}
|
||||
else
|
||||
ret = *area;
|
||||
|
||||
if (reset_strbuf)
|
||||
{
|
||||
/* set up to detect overflow of AREA if we can */
|
||||
tgetstr_base = ret;
|
||||
area_bufsize = find_usable_size (tgetstr_base);
|
||||
tgetstr_end = tgetstr_base + area_bufsize;
|
||||
reset_strbuf = 0;
|
||||
}
|
||||
|
||||
if (tgetstr_end && ret >= tgetstr_end)
|
||||
/* catch overflow early? */
|
||||
return NULL;
|
||||
|
||||
/* Copy the string value, stopping at null or colon.
|
||||
Also process ^ and \ abbreviations. */
|
||||
p = ptr;
|
||||
@@ -267,6 +320,12 @@ tgetst1 (char *ptr, char **area)
|
||||
}
|
||||
}
|
||||
*r++ = c;
|
||||
/* check for overflow, just bail out if we can detect it */
|
||||
if (tgetstr_end && r >= tgetstr_end)
|
||||
{
|
||||
r--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*r = '\0';
|
||||
/* Update *AREA. */
|
||||
@@ -431,6 +490,9 @@ valid_filename_p (fn)
|
||||
0 if the data base is accessible but the type NAME is not defined
|
||||
in it, and some other value otherwise. */
|
||||
|
||||
static char *termentbuf = NULL;
|
||||
static size_t entbufsize = 0;
|
||||
|
||||
__private_extern__
|
||||
int
|
||||
tgetent (char *bp, char *name)
|
||||
@@ -438,10 +500,11 @@ tgetent (char *bp, char *name)
|
||||
register char *termcap_name;
|
||||
register int fd;
|
||||
struct buffer buf;
|
||||
register char *bp1;
|
||||
char *lbp, *bp1;
|
||||
char *bp2;
|
||||
ptrdiff_t bpoff;
|
||||
char *term;
|
||||
int malloc_size = 0;
|
||||
size_t malloc_size = 0;
|
||||
register int c;
|
||||
char *tcenv = NULL; /* TERMCAP value, if it contains :tc=. */
|
||||
char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */
|
||||
@@ -453,20 +516,23 @@ tgetent (char *bp, char *name)
|
||||
if (!strcmp (name, "internal"))
|
||||
{
|
||||
term = INTERNAL_TERMINAL;
|
||||
if (!bp)
|
||||
malloc_size = 1 + strlen (term);
|
||||
if (malloc_size > entbufsize)
|
||||
{
|
||||
malloc_size = 1 + strlen (term);
|
||||
bp = (char *) xmalloc (malloc_size);
|
||||
entbufsize = malloc_size;
|
||||
lbp = (char *) xrealloc (termentbuf, entbufsize);
|
||||
}
|
||||
strcpy (bp, term);
|
||||
strcpy (lbp, term);
|
||||
goto ret;
|
||||
}
|
||||
#endif /* INTERNAL_TERMINAL */
|
||||
|
||||
#if 0
|
||||
/* For compatibility with programs like `less' that want to
|
||||
put data in the termcap buffer themselves as a fallback. */
|
||||
if (bp)
|
||||
term_entry = bp;
|
||||
#endif
|
||||
|
||||
termcap_name = getenv ("TERMCAP");
|
||||
if (termcap_name && *termcap_name == '\0')
|
||||
@@ -493,10 +559,15 @@ tgetent (char *bp, char *name)
|
||||
indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
|
||||
if (!indirect)
|
||||
{
|
||||
if (!bp)
|
||||
bp = termcap_name;
|
||||
else
|
||||
strcpy (bp, termcap_name);
|
||||
/* use termentbuf to avoid overflow from a too-long environment
|
||||
termcap entry */
|
||||
malloc_size = strlen (termcap_name) + 1;
|
||||
if (malloc_size > entbufsize)
|
||||
{
|
||||
entbufsize = malloc_size;
|
||||
termentbuf = xrealloc (termentbuf, entbufsize);
|
||||
}
|
||||
lbp = strcpy (termentbuf, termcap_name);
|
||||
goto ret;
|
||||
}
|
||||
else
|
||||
@@ -527,17 +598,19 @@ tgetent (char *bp, char *name)
|
||||
buf.beg = (char *) xmalloc (buf.size + 1);
|
||||
term = indirect ? indirect : name;
|
||||
|
||||
if (!bp)
|
||||
malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
|
||||
if (malloc_size > entbufsize)
|
||||
{
|
||||
malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
|
||||
bp = (char *) xmalloc (malloc_size);
|
||||
entbufsize = malloc_size;
|
||||
lbp = (char *)xrealloc (termentbuf, entbufsize);
|
||||
}
|
||||
bp1 = bp;
|
||||
lbp = termentbuf;
|
||||
bp1 = lbp;
|
||||
|
||||
if (indirect)
|
||||
/* Copy the data from the environment variable. */
|
||||
{
|
||||
strcpy (bp, tcenv);
|
||||
strcpy (lbp, tcenv);
|
||||
bp1 += strlen (tcenv);
|
||||
}
|
||||
|
||||
@@ -548,8 +621,13 @@ tgetent (char *bp, char *name)
|
||||
{
|
||||
close (fd);
|
||||
free (buf.beg);
|
||||
if (malloc_size)
|
||||
free (bp);
|
||||
if (entbufsize)
|
||||
{
|
||||
free (termentbuf); /* XXX */
|
||||
lbp = termentbuf = NULL;
|
||||
entbufsize = 0;
|
||||
}
|
||||
term_entry = bp; /* XXX */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -557,13 +635,14 @@ tgetent (char *bp, char *name)
|
||||
if (term != name)
|
||||
free (term);
|
||||
|
||||
/* If BP is malloc'd by us, make sure it is big enough. */
|
||||
if (malloc_size)
|
||||
/* LBP is malloc'd by us, so make sure it is big enough. */
|
||||
bpoff = bp1 - lbp; /* bp1 = end of data in termentbuf */
|
||||
malloc_size = bpoff + buf.size;
|
||||
if (malloc_size > entbufsize)
|
||||
{
|
||||
malloc_size = bp1 - bp + buf.size;
|
||||
termcap_name = (char *) xrealloc (bp, malloc_size);
|
||||
bp1 += termcap_name - bp;
|
||||
bp = termcap_name;
|
||||
entbufsize = malloc_size;
|
||||
lbp = (char *) xrealloc (termentbuf, entbufsize);
|
||||
bp1 = lbp + bpoff;
|
||||
}
|
||||
|
||||
bp2 = bp1;
|
||||
@@ -587,11 +666,15 @@ tgetent (char *bp, char *name)
|
||||
close (fd);
|
||||
free (buf.beg);
|
||||
|
||||
if (malloc_size)
|
||||
bp = (char *) xrealloc (bp, bp1 - bp + 1);
|
||||
entbufsize = bp1 - lbp + 1;
|
||||
lbp = (char *) xrealloc (lbp, entbufsize);
|
||||
|
||||
ret:
|
||||
term_entry = bp;
|
||||
term_entry = lbp;
|
||||
if (!bp)
|
||||
bp = lbp;
|
||||
|
||||
reset_strbuf = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+32
-8
@@ -1,6 +1,6 @@
|
||||
/* tparam.c - merge parameters into a termcap entry string. */
|
||||
|
||||
/* Copyright (C) 1985, 1986, 1993,1994, 1995, 1998, 2001,2003,2005,2006,2008,2009 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1985, 1986, 1993,1994, 1995, 1998, 2001,2003,2005,2006,2008,2009,2026 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -38,11 +38,16 @@ extern char *realloc ();
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STDDEF_H)
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#else /* not HAVE_CONFIG_H */
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#else
|
||||
char *malloc ();
|
||||
char *realloc ();
|
||||
@@ -97,7 +102,7 @@ xrealloc (void *ptr, size_t size)
|
||||
|
||||
The fourth and following args to tparam serve as the parameter values. */
|
||||
|
||||
static char *tparam1 (char *, char *, int, char *, char *, int *);
|
||||
static char *tparam1 (char *, char *, int, char *, char *, int *, int);
|
||||
|
||||
/* VARARGS 2 */
|
||||
char *
|
||||
@@ -109,11 +114,11 @@ tparam (char *string, char *outstring, int len, int arg0, int arg1, int arg2, in
|
||||
arg[1] = arg1;
|
||||
arg[2] = arg2;
|
||||
arg[3] = arg3;
|
||||
return tparam1 (string, outstring, len, NULL, NULL, arg);
|
||||
return tparam1 (string, outstring, len, NULL, NULL, arg, 4);
|
||||
}
|
||||
|
||||
__private_extern__ char *BC;
|
||||
__private_extern__ char *UP;
|
||||
/*__private_extern__*/ char *BC;
|
||||
/*__private_extern__*/ char *UP;
|
||||
|
||||
static char tgoto_buf[50];
|
||||
|
||||
@@ -126,11 +131,18 @@ tgoto (char *cm, int hpos, int vpos)
|
||||
return NULL;
|
||||
args[0] = vpos;
|
||||
args[1] = hpos;
|
||||
return tparam1 (cm, tgoto_buf, 50, UP, BC, args);
|
||||
return tparam1 (cm, tgoto_buf, 50, UP, BC, args, 2);
|
||||
}
|
||||
|
||||
#define CHECK_OVERFLOW(n) \
|
||||
do { \
|
||||
ptrdiff_t x = argp - orig_argp; /* where we are now */ \
|
||||
if (((int)x + n ) > nargs) \
|
||||
goto overflow; \
|
||||
} while (0)
|
||||
|
||||
static char *
|
||||
tparam1 (char *string, char *outstring, int len, char *up, char *left, int *argp)
|
||||
tparam1 (char *string, char *outstring, int len, char *up, char *left, int *argp, int nargs)
|
||||
{
|
||||
register int c;
|
||||
register char *p = string;
|
||||
@@ -143,6 +155,8 @@ tparam1 (char *string, char *outstring, int len, char *up, char *left, int *argp
|
||||
int doleft = 0;
|
||||
int doup = 0;
|
||||
|
||||
int *orig_argp = argp;
|
||||
|
||||
outend = outstring + len;
|
||||
|
||||
while (1)
|
||||
@@ -196,6 +210,7 @@ tparam1 (char *string, char *outstring, int len, char *up, char *left, int *argp
|
||||
onedigit:
|
||||
*op++ = tem % 10 + '0';
|
||||
argp++;
|
||||
CHECK_OVERFLOW (1);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
@@ -225,14 +240,18 @@ tparam1 (char *string, char *outstring, int len, char *up, char *left, int *argp
|
||||
*op++ = tem ? tem : 0200;
|
||||
case 'f': /* %f means discard next arg. */
|
||||
argp++;
|
||||
CHECK_OVERFLOW (1); /* are we past argp[nargs - 1]? */
|
||||
break;
|
||||
|
||||
case 'b': /* %b means back up one arg (and re-use it). */
|
||||
argp--;
|
||||
if (argp > orig_argp)
|
||||
argp--;
|
||||
break;
|
||||
|
||||
case 'r': /* %r means interchange following two args. */
|
||||
CHECK_OVERFLOW(0);
|
||||
argp[0] = argp[1];
|
||||
CHECK_OVERFLOW(1);
|
||||
argp[1] = tem;
|
||||
old_argp++;
|
||||
break;
|
||||
@@ -269,7 +288,9 @@ tparam1 (char *string, char *outstring, int len, char *up, char *left, int *argp
|
||||
break;
|
||||
|
||||
case 'i': /* %i means add one to arg, */
|
||||
CHECK_OVERFLOW(0);
|
||||
argp[0] ++; /* and leave it to be output later. */
|
||||
CHECK_OVERFLOW(1);
|
||||
argp[1] ++; /* Increment the following arg, too! */
|
||||
break;
|
||||
|
||||
@@ -278,11 +299,13 @@ tparam1 (char *string, char *outstring, int len, char *up, char *left, int *argp
|
||||
|
||||
case 'n': /* %n means xor each of next two args with 140. */
|
||||
argp[0] ^= 0140;
|
||||
CHECK_OVERFLOW(1);
|
||||
argp[1] ^= 0140;
|
||||
break;
|
||||
|
||||
case 'm': /* %m means xor each of next two args with 177. */
|
||||
argp[0] ^= 0177;
|
||||
CHECK_OVERFLOW(1);
|
||||
argp[1] ^= 0177;
|
||||
break;
|
||||
|
||||
@@ -300,6 +323,7 @@ tparam1 (char *string, char *outstring, int len, char *up, char *left, int *argp
|
||||
ordinary:
|
||||
*op++ = c;
|
||||
}
|
||||
overflow:
|
||||
*op = 0;
|
||||
while (doup-- > 0)
|
||||
strcat (op, up);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* This file works under BSD, System V, minix, and Posix systems. It does
|
||||
not implement job control. */
|
||||
|
||||
/* Copyright (C) 1987-2024 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2026 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -96,6 +96,8 @@ int job_control = 0;
|
||||
/* and don't want job notifications */
|
||||
int want_job_notifications = 0;
|
||||
|
||||
int waitonce = 0;
|
||||
|
||||
int running_in_background = 0; /* can't tell without job control */
|
||||
|
||||
/* STATUS and FLAGS are only valid if pid != NO_PID
|
||||
|
||||
Reference in New Issue
Block a user