ports/90317: buffer overflows in www/gnuinfo
Juergen Lock
nox at jelal.kn-bremen.de
Tue Dec 13 00:30:09 UTC 2005
>Number: 90317
>Category: ports
>Synopsis: buffer overflows in www/gnuinfo
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: freebsd-ports-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: maintainer-update
>Submitter-Id: current-users
>Arrival-Date: Tue Dec 13 00:30:06 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator: Juergen Lock
>Release: FreeBSD 5.3-RELEASE-p20 i386
>Organization:
me? organized??
>Environment:
System: FreeBSD saturn 5.3-RELEASE-p20 FreeBSD 5.3-RELEASE-p20 #1: Fri Jul 29 14:59:03 CEST 2005 nox at saturn:/usr/home/nox/src5/usr/src/sys/i386/compile/NEPTUN i386
>Description:
Per advice of kris@ I post the security patch, in the
hope that the port will be added to vuxml soon. (I hope the
disappeared MASTER_SITE can be taken care of after that.)
Security: try to fix possible buffer overflows or similar.
>How-To-Repeat:
hmm, look at the code? :)
>Fix:
New file: files/patch-security
Index: files/patch-security
@@ -0,0 +1,315 @@
+Index: convert.lex
+@@ -140,50 +140,66 @@
+
+ void print_longlink(char *link)
+ {
+- char linknode[LINK_LENGTH];
++ char linknode[LINK_LENGTH * 3];
+ char linkfile[LINK_LENGTH];
+ char text[LINK_LENGTH];
+ char *h;
+
+ /* text */
+- strcpy(text,link+(link[1]==' ' ? 2 : 6));
+- *(strchr(text,':')) = '\0';
++ snprintf(text, sizeof text, "%s", link+(link[1]==' ' ? 2 : 6));
++ h = strchr(text,':');
++ if (h) *h = '\0';
+
+ /* link */
+ h = strchr(link,':');
+ do h++; while (*h == ' ');
+ if (*h == '(') {
+ /* we have a file */
+- strcpy(linkfile,h+1);
+- *(h=strchr(linkfile,')')) = '\0';
+- do h++; while (*h == ' ');
++ if (strlen(h) > sizeof linkfile) {
++ snprintf(linkfile, sizeof linkfile, "%s", file);
++ h = NULL;
++ } else {
++ snprintf(linkfile, sizeof linkfile, "%s", h+1);
++ h=strchr(linkfile,')');
++ if (h) *h = '\0';
++ }
++ if (h) {
++ do h++; while (*h == ' ');
++ }
+ strcpy(linknode,"Top"); /* default node, may be overwritten later */
+ } else {
+- strcpy(linkfile,file);
++ snprintf(linkfile, sizeof linkfile, "%s", file);
+ }
+- if (*h != '.' && *h != ',') {
++ if (h && *h != '.' && *h != ',' && strlen(h) * 3 < sizeof linknode - 1) {
+ /* we have a node */
+- quote(linknode,h);
++ quote(linknode, sizeof linknode, h);
+ h = strstr(linknode,"%2e"); /* quoted '.' */
+ if (!h)
+ h = strstr(linknode,"%2c"); /* quoted ',' */
+- *h = '\0';
++ if (h) *h = '\0';
+ }
+ printf("<a href=\"%s/%s/%s\">*",whoami,linkfile,linknode);
+ if (link[1] != ' ') printf("note");
+ printf(" %s:</a>",text);
+ if (link[1] == ' ') printf(MENU_DESC);
+ h = strchr(link,':');
+- do h++; while (*h == ' ');
+- printf("%s",h);
++ if (h) {
++ do h++; while (*h == ' ');
++ printf("%s",h);
++ }
+ }
+
+ void print_shortlink(char *link)
+ {
+- char linknode[LINK_LENGTH];
++ char linknode[LINK_LENGTH * 3], *h;
+
+- quote(linknode,link+(link[1]==' ' ? 2 : 6));
+- *(strstr(linknode,"%3a")) = '\0'; /* ':' -> "%3a" (URL-Quoting) */
++ if (strlen(link) * 3 > sizeof linknode - 1)
++ strcpy(linknode, "Top");
++ else {
++ quote(linknode, sizeof linknode, link+(link[1]==' ' ? 2 : 6));
++ h = strstr(linknode,"%3a");
++ if (h) *h = '\0'; /* ':' -> "%3a" (URL-Quoting) */
++ }
+
+ printf("<a href=\"%s/%s/%s\">",whoami,file,linknode);
+ printf("%s</a>",link);
+Index: info2html.c
+@@ -22,12 +22,12 @@
+
+ /*-------------------------------------------------------------*/
+
+-void quote(char *dest, char *src)
++void quote(char *dest, size_t bufsize, char *src)
+ {
+ static const char lookup[16] = "0123456789abcdef";
+ int i,j;
+
+- for (i=0, j=0; src[j] != '\0';) {
++ for (i=0, j=0; src[j] != '\0' && i < bufsize - 4 ;) {
+ if (isalnum(src[j])) {
+ dest[i++] = src[j++];
+ } else {
+@@ -41,12 +41,12 @@
+ }
+
+ /* copy string and convert the "%??" to normal char's */
+-void unquote(char *dest, char *src)
++void unquote(char *dest, size_t bufsize, char *src)
+ {
+ int i,j,hex;
+ char nr[3];
+
+- for (i=0, j=0; src[j] != '?' && src[j] != '\0'; i++) {
++ for (i=0, j=0; src[j] != '?' && src[j] != '\0' && i < bufsize - 1 ; i++) {
+ if (src[j] == '%') {
+ nr[0] = src[j+1];
+ nr[1] = src[j+2];
+@@ -72,12 +72,12 @@
+ file[0] = 0;
+ node[0] = 0;
+ path = getenv("PATH_INFO");
+- if (path && *path) {
+- strcpy(file,path+1);
++ if (path && *path && strlen(path) < sizeof file) {
++ snprintf(file, sizeof file, "%s", path+1);
+ h = strchr(file,'/');
+ if (h) {
+ *(h++) = 0;
+- if (*h) strcpy(node,h);
++ if (*h) snprintf(node, sizeof node, "%s", h);
+ /* workaround: Spinner appends a slash to the URL */
+ if (NULL != (h = strchr(node,'/'))) *h = 0;
+ }
+@@ -100,11 +100,13 @@
+ h++;
+ }
+ }
+- strcpy(whoami,h);
++ if (strlen(h) >= sizeof whoami)
++ h = argv0;
++ snprintf(whoami, sizeof whoami, "%s", h);
+ }
+
+ /*-------------------------------------------------------------*/
+-
++
+ char infodirs[]=INFODIRS;
+ char *dirs[20];
+
+@@ -119,7 +121,7 @@
+ else
+ dirs[0] = infodirs;
+
+- for (i = 0; dirs[i] != NULL ; i++) {
++ for (i = 0; dirs[i] != NULL && i < sizeof dirs - 1; i++) {
+ h = strchr(dirs[i],':');
+ if (h) {
+ *h = 0;
+@@ -135,7 +137,7 @@
+ /* open an infofile. The indir-parameter is for indirections */
+ FILE *open_infofile(int indir)
+ {
+- char filename[LINK_LENGTH],nr[10],last_modi[80];
++ char *filename = NULL,nr[10],last_modi[80];
+ struct stat st;
+ int fd_pipe[2];
+ int i,d,gzip;
+@@ -149,29 +151,29 @@
+ for (i = 0; i < 4 /* 8 */; i++) {
+ switch (i) {
+ case 0:
+- gzip = FALSE;sprintf(filename,"%s/%s%s",dirs[d],file,nr);
++ gzip = FALSE;asprintf(&filename,"%s/%s%s",dirs[d],file,nr);
+ break;
+ case 1:
+- gzip = FALSE;sprintf(filename,"%s/%s.info%s",dirs[d],file,nr);
++ gzip = FALSE;asprintf(&filename,"%s/%s.info%s",dirs[d],file,nr);
+ break;
+ case 2:
+- gzip = TRUE; sprintf(filename,"%s/%s%s.gz",dirs[d],file,nr);
++ gzip = TRUE; asprintf(&filename,"%s/%s%s.gz",dirs[d],file,nr);
+ break;
+ case 3:
+- gzip = TRUE; sprintf(filename,"%s/%s.info%s.gz",dirs[d],file,nr);
++ gzip = TRUE; asprintf(&filename,"%s/%s.info%s.gz",dirs[d],file,nr);
+ break;
+ /*
+ case 4:
+- gzip = TRUE; sprintf(filename,"%s/%s%s.z",dirs[d],file,nr);
++ gzip = TRUE; asprintf(&filename,"%s/%s%s.z",dirs[d],file,nr);
+ break;
+ case 5:
+- gzip = TRUE; sprintf(filename,"%s/%s.info%s.z",dirs[d],file,nr);
++ gzip = TRUE; asprintf(&filename,"%s/%s.info%s.z",dirs[d],file,nr);
+ break;
+ case 6:
+- gzip = TRUE; sprintf(filename,"%s/%s%s.Z",dirs[d],file,nr);
++ gzip = TRUE; asprintf(&filename,"%s/%s%s.Z",dirs[d],file,nr);
+ break;
+ case 7:
+- gzip = TRUE; sprintf(filename,"%s/%s.info%s.Z",dirs[d],file,nr);
++ gzip = TRUE; asprintf(&filename,"%s/%s.info%s.Z",dirs[d],file,nr);
+ break;
+ */
+ default: return NULL; /* keep compiler happy */
+@@ -191,6 +193,7 @@
+ pipe(fd_pipe);
+ switch (fork()) {
+ case -1:
++ if (filename) free(filename);
+ return NULL;
+ case 0:
+ /* child */
+@@ -204,14 +207,20 @@
+ dup2(fd_pipe[0],0);
+ close(fd_pipe[0]);
+ close(fd_pipe[1]);
++ if (filename) free(filename);
+ return stdin;
+ }
+ } else {
+- return fopen(filename,"r");
++ if (filename) {
++ FILE *ret = fopen(filename,"r");
++ free(filename);
++ return ret;
++ }
+ }
+ }
+ }
+ }
++ if (filename) free(filename);
+ return NULL;
+ }
+
+@@ -221,23 +230,25 @@
+ {
+ char text[LINK_LENGTH];
+ char linkfile[LINK_LENGTH];
+- char linknode[LINK_LENGTH];
++ char linknode[LINK_LENGTH * 3];
+ char *h;
+
++ if (strlen(buf) >= LINK_LENGTH) return;
+ h = strstr(buf,what);
+ if (!h) return;
+ h += strlen(what);
+- strcpy(text,h);
++ snprintf(text, sizeof text, "%s", h);
+ h = strchr(text,',' ); if (h) *h = '\0';
+ h = strchr(text,'\t'); if (h) *h = '\0';
+ h = strchr(text,'\n'); if (h) *h = '\0';
+ if (text[0] == '(') {
+- strcpy(linkfile,text+1);
+- *(strchr(linkfile,')')) = '\0';
++ snprintf(linkfile, sizeof linkfile, "%s", text+1);
++ h = strchr(linkfile,')');
++ if (h) *h = '\0';
+ strcpy(linknode,"Top");
+ } else {
+- strcpy(linkfile,file);
+- quote(linknode,text);
++ snprintf(linkfile, sizeof linkfile, "%s", file);
++ quote(linknode, sizeof linknode, text);
+ }
+ printf("%s <a href=\"%s/%s/%s\">%s</a> \n",
+ what,whoami,linkfile,linknode,text);
+@@ -249,21 +260,22 @@
+ log_error(int node_failed)
+ {
+ time_t tm;
+- char timestr[64],from[256];
++ char timestr[64], *from = strdup("");
+
+ time(&tm);
+ strftime(timestr,64,"%a %h %d %T %Y",
+ localtime(&tm));
+- if (getenv("HTTP_REFERER")) /* be sure we have a referer */
+- sprintf(from," from %250s",getenv("HTTP_REFERER"));
+- else
+- from[0] = 0;
++ if (getenv("HTTP_REFERER")) { /* be sure we have a referer */
++ free(from);
++ asprintf(&from," from %250s",getenv("HTTP_REFERER"));
++ }
+ if (node_failed)
+ fprintf(stderr,"[%s] gnuinfo: access to node %s, info file %s failed%s\n",
+ timestr,node,file,from);
+ else
+ fprintf(stderr,"[%s] gnuinfo: access to info file %s failed%s\n",
+ timestr,file,from);
++ if (from) free(from);
+ }
+
+ /*-------------------------------------------------------------*/
+@@ -366,8 +378,11 @@
+ }
+
+ /* find out which file */
+- h = strchr(buf,127); h++;
+- line = atoi(h);
++ if ((h = strchr(buf,127))) {
++ h++;
++ line = atoi(h);
++ } else
++ line = 0;
+ for (i = 0; indir_table[i] != 0 && line >= indir_table[i] ; i++);
+
+ /* play it again... */
+Index: info2html.h
+@@ -17,5 +17,5 @@
+ extern FILE *yyin;
+ int yylex();
+
+-void quote(char*, char*);
+-void unquote(char* , char*);
++void quote(char*, size_t bufsize, char*);
++void unquote(char*, size_t bufsize, char*);
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-ports-bugs
mailing list