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:
Chet Ramey
2026-09-23 11:24:04 -04:00
parent f26caaa178
commit 1c20880e16
14 changed files with 365 additions and 65 deletions
+47
View File
@@ -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
View File
@@ -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
View File
@@ -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. */
Vendored
+33 -7
View 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+8 -1
View File
@@ -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);
+2
View File
@@ -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);
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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