Re: more: Limited line buffer length results in corrupted UTF-8 text

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Oct 27, 2009 at 11:58:30AM +0000, Roger Leigh wrote:
> An alternative approach which would avoid *all* overflow would be to
> dynamically allocate a minimum buffer size of 4× the number of columns

 Yeah, sounds good. Fixed. Thanks for your excellent bug report.

    Karel


>From 1ac300932deab8dea2c43050921bbbdb36d62ff1 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@xxxxxxxxxx>
Date: Mon, 16 Nov 2009 15:52:45 +0100
Subject: [PATCH] more: limited line buffer length results in corrupted UTF-8 text

Addresses-Debian-Bug: #552608
Reported-By: Roger Leigh <rleigh@xxxxxxxxxx>
Signed-off-by: Karel Zak <kzak@xxxxxxxxxx>
---
 text-utils/more.c |   50 +++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/text-utils/more.c b/text-utils/more.c
index 45a58e2..a152463 100644
--- a/text-utils/more.c
+++ b/text-utils/more.c
@@ -105,9 +105,10 @@ int  get_line(register FILE *f, int *length);
 void prbuf (register char *s, register int n);
 void execute (char *filename, char *cmd, ...);
 FILE *checkf (char *, int *);
+int prepare_line_buffer(void);
 
 #define TBUFSIZ	1024
-#define LINSIZ	256
+#define LINSIZ	256	/* minimal Line buffer size */
 #define ctrl(letter)	(letter & 077)
 #define RUBOUT	'\177'
 #define ESC	'\033'
@@ -141,7 +142,8 @@ int		nfiles;		/* Number of files left to process */
 char		*shell;		/* The name of the shell to use */
 int		shellp;		/* A previous shell command exists */
 sigjmp_buf	restore;
-char		Line[LINSIZ+2];	/* Line buffer */
+char		*Line;		/* Line buffer */
+size_t		LineLen;	/* size of Line buffer */
 int		Lpp = 24;	/* lines per page */
 char		*Clear;		/* clear screen */
 char		*eraseln;	/* erase line */
@@ -284,6 +286,10 @@ int main(int argc, char **argv) {
     fnames = argv;
     setlocale(LC_ALL, "");
     initterm ();
+    if (prepare_line_buffer()) {
+	fprintf(stderr, _("failed to initialize line buffer\n"));
+	exit(1);
+    }
     nscroll = Lpp/2 - 1;
     if (nscroll <= 0)
 	nscroll = 1;
@@ -767,6 +773,32 @@ static void prompt (char *filename)
     inwait++;
 }
 
+int prepare_line_buffer(void)
+{
+    char *nline;
+    size_t nsz = Mcol * 4;
+
+    if (LineLen >= nsz)
+        return 0;
+
+    if (nsz < LINSIZ)
+        nsz = LINSIZ;
+
+    nline = realloc(Line, nsz);
+    if (nline) {
+        Line = nline;
+        LineLen = nsz;
+        return 0;
+    }
+
+    /* error() uses siglongjmp(), we want to return from this
+     * function when the Line buffer is initilized first time in main()
+     */
+    if (Line)
+        error(_("out if memory"));
+    return -1;
+}
+
 /*
  * Get a logical line
  */
@@ -793,6 +825,8 @@ int get_line(register FILE *f, int *length)
     memset (&state, '\0', sizeof (mbstate_t));
 #endif
 
+    prepare_line_buffer();
+
     p = Line;
     column = 0;
     c = Getc (f);
@@ -800,7 +834,7 @@ int get_line(register FILE *f, int *length)
 	Currline++;
 	c = Getc (f);
     }
-    while (p < &Line[LINSIZ - 1]) {
+    while (p < &Line[LineLen - 1]) {
 #ifdef HAVE_WIDECHAR
 	if (fold_opt && use_mbc_buffer_flag && MB_CUR_MAX > 1) {
 	    use_mbc_buffer_flag = 0;
@@ -871,11 +905,11 @@ process_mbc:
 #if 0
 	if (c == '\033') {      /* ESC */
 		c = Getc(f);
-		while (c > ' ' && c < '0' && p < &Line[LINSIZ - 1]) {
+		while (c > ' ' && c < '0' && p < &Line[LineLen - 1]) {
 			*p++ = c;
 			c = Getc(f);
 		}
-		if (c >= '0' && c < '\177' && p < &Line[LINSIZ - 1]) {
+		if (c >= '0' && c < '\177' && p < &Line[LineLen - 1]) {
 			*p++ = c;
 			c = Getc(f);
 			continue;
@@ -890,7 +924,7 @@ process_mbc:
 		    promptlen = 0;
 		}
 		else {
-		    for (--p; p < &Line[LINSIZ - 1];) {
+		    for (--p; p < &Line[LineLen - 1];) {
 			*p++ = ' ';
 			if ((++column & 7) == 0)
 			    break;
@@ -2087,8 +2121,10 @@ void rdline (register FILE *f)
     register int  c;
     register char *p;
 
+    prepare_line_buffer();
+
     p = Line;
-    while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1)
+    while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LineLen - 1)
 	*p++ = c;
     if (c == '\n')
 	Currline++;
-- 
1.6.5.1


--
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux