diff options
author | Joshua M. Clulow <jmc@joyent.com> | 2014-12-19 14:03:07 -0800 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2014-12-23 14:52:48 -0800 |
commit | 196c7f05d2deba7404e90ad67f3861185c78ca2d (patch) | |
tree | 29ff7b2bd21041c7331063485095b6008b58ee10 /usr/src/cmd | |
parent | aa64fa16549f13233681f4b40e50fb5b1c18a97c (diff) | |
download | illumos-gate-196c7f05d2deba7404e90ad67f3861185c78ca2d.tar.gz |
5480 CVE-2012-3165 mailx(1) buffer overflow vulnerability
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src/cmd')
-rw-r--r-- | usr/src/cmd/Makefile | 1 | ||||
-rw-r--r-- | usr/src/cmd/fmt/Makefile | 1 | ||||
-rw-r--r-- | usr/src/cmd/fmt/fmt.c | 6 | ||||
-rw-r--r-- | usr/src/cmd/mailx/Makefile | 4 | ||||
-rw-r--r-- | usr/src/cmd/mailx/cmd1.c | 34 | ||||
-rw-r--r-- | usr/src/cmd/mailx/fio.c | 8 | ||||
-rw-r--r-- | usr/src/cmd/mailx/hdr/def.h | 22 | ||||
-rw-r--r-- | usr/src/cmd/mailx/head.c | 242 | ||||
-rw-r--r-- | usr/src/cmd/mailx/receipt.c | 26 |
9 files changed, 234 insertions, 110 deletions
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index c59e370d47..6f5a277510 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -829,6 +829,7 @@ fs.d: fstyp ksh: shcomp isaexec mdb: terminfo print: lp +fmt: mailx $(FIRST_SUBDIRS) $(BWOSDIRS) $(SUBDIRS) $(AUDITSUBDIRS): FRC @if [ -f $@/Makefile ]; then \ diff --git a/usr/src/cmd/fmt/Makefile b/usr/src/cmd/fmt/Makefile index 21938536d6..cecd4e3c2a 100644 --- a/usr/src/cmd/fmt/Makefile +++ b/usr/src/cmd/fmt/Makefile @@ -33,6 +33,7 @@ SRCS= $(OBJS:%.o=%.c) include ../Makefile.cmd +LDLIBS += -lcmdutils CERRWARN += -_gcc=-Wno-switch CERRWARN += -_gcc=-Wno-parentheses diff --git a/usr/src/cmd/fmt/fmt.c b/usr/src/cmd/fmt/fmt.c index 52d4676172..b5fbee6e13 100644 --- a/usr/src/cmd/fmt/fmt.c +++ b/usr/src/cmd/fmt/fmt.c @@ -86,7 +86,7 @@ int h_lines; /* index into lines of hdrbuf */ void (*(split))(wchar_t []); extern int scrwidth(wchar_t); -extern int ishead(char []); +extern boolean_t is_headline(const char *); static void fill_hdrbuf(wchar_t []); @@ -240,13 +240,13 @@ fmt(FILE *fi) } /* * Need to convert string from wchar_t to char, - * since this is what ishead() expects. Since we + * since this is what is_headline() expects. Since we * only want to make sure cp points to a "From" line * of the email, we don't have to alloc * BUFSIZ * MB_LEN_MAX to cbuf. */ wcstombs(cbuf, cp, (BUFSIZ - 1)); - if (ishead(cbuf)) { + if (is_headline(cbuf) == B_TRUE) { hdr_state = in_hdr; fill_hdrbuf(canonb); } else { diff --git a/usr/src/cmd/mailx/Makefile b/usr/src/cmd/mailx/Makefile index 93b527b72a..4fb19334f2 100644 --- a/usr/src/cmd/mailx/Makefile +++ b/usr/src/cmd/mailx/Makefile @@ -22,6 +22,8 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2014 Joyent, Inc. +# # cmd/mailx/Makefile PROG= mailx @@ -67,7 +69,7 @@ CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-unused-variable CERRWARN += -_gcc=-Wno-clobbered LINTFLAGS= -hb -LDLIBS += -lmail +LDLIBS += -lmail -lcmdutils LDFLAGS += $(MAPFILE.NGB:%=-M%) CLOBBERFILES += $(MAILXHELP) diff --git a/usr/src/cmd/mailx/cmd1.c b/usr/src/cmd/mailx/cmd1.c index 5cdb7ae465..38c9b7ab9b 100644 --- a/usr/src/cmd/mailx/cmd1.c +++ b/usr/src/cmd/mailx/cmd1.c @@ -19,6 +19,11 @@ * * CDDL HEADER END */ + +/* + * Copyright 2014 Joyent, Inc. + */ + /* * Copyright 2001 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -37,8 +42,7 @@ * contributors. */ -#pragma ident "%Z%%M% %I% %E% SMI" - +#include <err.h> #include "rcv.h" #include <locale.h> @@ -213,10 +217,14 @@ printhead(int mesg) char *fromline; char pbuf[LINESIZE]; char name[LINESIZE]; - struct headline hl; + headline_t *hl; register char *cp; int showto; + if (headline_alloc(&hl) != 0) { + err(1, "could not allocate memory"); + } + mp = &message[mesg-1]; ibuf = setinput(mp); readline(ibuf, headline); @@ -248,9 +256,14 @@ printhead(int mesg) dispc = 'H'; if (mp->m_flag & MBOX) dispc = 'M'; - parse(headline, &hl, pbuf); - if (hl.l_date == NOSTR) - hl.l_date = "<Unknown date>"; + if (parse_headline(headline, hl) == -1) { + headline_reset(hl); + } + if (custr_len(hl->hl_date) == 0) { + if (custr_append(hl->hl_date, "<Unknown date>") != 0) { + err(1, "could not print header"); + } + } /* * Netnews interface? @@ -299,11 +312,14 @@ printhead(int mesg) } if (mp->m_text) { printf("%16.16s %4ld/%-5ld %-.25s\n", - hl.l_date, mp->m_lines, mp->m_size, subjline); - } else { - printf("%16.16s binary/%-5ld %-.25s\n", hl.l_date, mp->m_size, + custr_cstr(hl->hl_date), mp->m_lines, mp->m_size, subjline); + } else { + printf("%16.16s binary/%-5ld %-.25s\n", custr_cstr(hl->hl_date), + mp->m_size, subjline); } + + headline_free(hl); } /* diff --git a/usr/src/cmd/mailx/fio.c b/usr/src/cmd/mailx/fio.c index 818860d7ae..59eceb519f 100644 --- a/usr/src/cmd/mailx/fio.c +++ b/usr/src/cmd/mailx/fio.c @@ -21,6 +21,10 @@ */ /* + * Copyright 2014 Joyent, Inc. + */ + +/* * Copyright 1999 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,8 +32,6 @@ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "rcv.h" #include <locale.h> #include <wordexp.h> @@ -174,7 +176,7 @@ setptr(register FILE *ibuf) } /* Look for a From line that starts a new message */ - if (blankline && linebuf[0] == 'F' && ishead(linebuf)) { + if (blankline && linebuf[0] == 'F' && is_headline(linebuf)) { if (msgCount > 0 && !newmail) { message[msgCount-1].m_size = s; message[msgCount-1].m_lines = l; diff --git a/usr/src/cmd/mailx/hdr/def.h b/usr/src/cmd/mailx/hdr/def.h index d0e48820ea..7453b24f97 100644 --- a/usr/src/cmd/mailx/hdr/def.h +++ b/usr/src/cmd/mailx/hdr/def.h @@ -20,6 +20,10 @@ */ /* + * Copyright 2014 Joyent, Inc. + */ + +/* * Copyright (c) 1985, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -60,6 +64,7 @@ extern "C" { #include <stdlib.h> #include <ulimit.h> #include <wait.h> +#include <libcmdutils.h> #endif #ifdef VMUNIX #include <sys/wait.h> @@ -204,11 +209,11 @@ struct cmd { * line */ -struct headline { - char *l_from; /* The name of the sender */ - char *l_tty; /* His tty string (if any) */ - char *l_date; /* The entire date string */ -}; +typedef struct headline { + custr_t *hl_from; /* The name of the sender */ + custr_t *hl_tty; /* His tty string (if any) */ + custr_t *hl_date; /* The entire date string */ +} headline_t; #define GTO 1 /* Grab To: line */ #define GSUBJECT 2 /* Likewise, Subject: line */ @@ -486,6 +491,9 @@ extern int hash(char name[]); extern char *hcontents(char hfield[]); extern int headerp(register char *line); extern int headers(int *msgvec); +extern int headline_alloc(headline_t **); +extern void headline_free(headline_t *); +extern void headline_reset(headline_t *); extern int help(void); extern char *helppath(char *file); extern char *hfield(char field[], struct message *mp, @@ -497,7 +505,7 @@ extern int igfield(char *list[]); extern int inc(void); extern void inithost(void); extern int isdir(char name[]); -extern int ishead(char linebuf[]); +extern boolean_t is_headline(const char *); extern int ishfield(char linebuf[], char field[]); extern int ishost(char *sys, char *rest); extern int isign(char *field, int saving); @@ -533,7 +541,7 @@ extern int null(char *e); extern int outof(struct name *names, FILE *fo); extern struct name *outpre(struct name *to); extern void panic(char *str); -extern void parse(char line[], struct headline *hl, char pbuf[]); +extern int parse_headline(const char *, headline_t *); extern int pcmdlist(void); extern int pdot(void); extern int preserve(int *msgvec); diff --git a/usr/src/cmd/mailx/head.c b/usr/src/cmd/mailx/head.c index 3f833ab14e..b6d09f0767 100644 --- a/usr/src/cmd/mailx/head.c +++ b/usr/src/cmd/mailx/head.c @@ -19,6 +19,11 @@ * * CDDL HEADER END */ + +/* + * Copyright 2014 Joyent, Inc. + */ + /* * Copyright 1995 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -38,7 +43,7 @@ * contributors. */ -#pragma ident "%Z%%M% %I% %E% SMI" +#include <err.h> #include "rcv.h" @@ -49,115 +54,188 @@ * Routines for processing and detecting headlines. */ -static char *copyin(char src[], char **space); -static char *nextword(char wp[], char wbuf[]); +static int nextword(const char *, custr_t *, const char **); /* * See if the passed line buffer is a mail header. * Return true if yes. */ - -int -ishead(char linebuf[]) +boolean_t +is_headline(const char *linebuf) { - register char *cp; - struct headline hl; - char parbuf[BUFSIZ]; - - cp = linebuf; - if (strncmp("From ", cp, 5) != 0) - return(0); - parse(cp, &hl, parbuf); - if (hl.l_from == NOSTR) { - return(0); + headline_t *hl; + boolean_t ret; + + if (strncmp("From ", linebuf, 5) != 0) { + return (B_FALSE); + } + + if (headline_alloc(&hl) != 0 || parse_headline(linebuf, hl) != 0) { + err(1, "could not parse headline"); } - return(1); + + ret = custr_len(hl->hl_from) > 0 ? B_TRUE : B_FALSE; + + headline_free(hl); + return (ret); } /* - * Split a headline into its useful components. - * Copy the line into dynamic string space, then set - * pointers into the copied line in the passed headline - * structure. Actually, it scans. + * Manage headline_t objects: */ -void -parse(char line[], struct headline *hl, char pbuf[]) +void +headline_free(headline_t *hl) +{ + custr_free(hl->hl_from); + custr_free(hl->hl_tty); + custr_free(hl->hl_date); + free(hl); +} + +int +headline_alloc(headline_t **hl) { - register char *cp, *dp; - char *sp; - char word[LINESIZE]; + int en; + headline_t *t; + + if ((t = calloc(1, sizeof (*t))) == NULL) { + return (-1); + } - hl->l_from = NOSTR; - hl->l_date = NOSTR; - cp = line; - sp = pbuf; + if (custr_alloc(&t->hl_from) != 0 || custr_alloc(&t->hl_tty) != 0 || + custr_alloc(&t->hl_date) != 0) { + en = errno; - /* - * Skip the first "word" of the line, which should be "From" - * anyway. - */ + headline_free(t); - cp = nextword(cp, word); - dp = nextword(cp, word); - if (!equal(word, "")) - hl->l_from = copyin(word, &sp); - if (dp != NOSTR) - hl->l_date = copyin(dp, &sp); + errno = en; + return (-1); + } + + *hl = t; + return (0); } /* - * Copy the string on the left into the string on the right - * and bump the right (reference) string pointer by the length. - * Thus, dynamically allocate space in the right string, copying - * the left string into it. + * Clear all of the strings in a headline_t: */ +void +headline_reset(headline_t *hl) +{ + custr_reset(hl->hl_from); + custr_reset(hl->hl_tty); + custr_reset(hl->hl_date); +} -static char * -copyin(char src[], char **space) +int +parse_headline(const char *line, headline_t *hl) { - register char *cp, *top; - register int s; - - s = strlen(src); - cp = *space; - top = cp; - strcpy(cp, src); - cp += s + 1; - *space = cp; - return(top); + const char *c = line; + + headline_reset(hl); + + /* + * Load the first word from the line and ensure that it is "From". + */ + if (nextword(c, hl->hl_from, &c) != 0) { + return (-1); + } + if (strcmp(custr_cstr(hl->hl_from), "From") != 0) { + errno = EINVAL; + return (-1); + } + custr_reset(hl->hl_from); + + /* + * The next word will be the From address. + */ + if (nextword(c, hl->hl_from, &c) != 0) { + return (-1); + } + + /* + * If there is a next word, the rest of the string is the Date. + */ + if (c != NULL) { + if (custr_append(hl->hl_date, c) != 0) { + return (-1); + } + } + + errno = 0; + return (0); } /* - * Collect a liberal (space, tab delimited) word into the word buffer - * passed. Also, return a pointer to the next word following that, - * or NOSTR if none follow. + * Collect a space- or tab-delimited word into the word buffer, if one is + * passed. The double quote character (") can be used to include whitespace + * within a word. Set "nextword" to the location of the first character of the + * _next_ word, or NULL if there were no more words. Returns 0 on success or + * -1 otherwise. */ - -static char * -nextword(char wp[], char wbuf[]) +static int +nextword(const char *input, custr_t *word, const char **nextword) { - register char *cp, *cp2; + boolean_t in_quotes = B_FALSE; + const char *c = input != NULL ? input : ""; + + /* + * Collect the first word into the word buffer, if one is provided. + */ + for (;;) { + if (*c == '\0') { + /* + * We have reached the end of the string. + */ + *nextword = NULL; + return (0); + } + + if (*c == '"') { + /* + * Either beginning or ending a quoted string. + */ + in_quotes = in_quotes ? B_FALSE : B_TRUE; + } + + if (!in_quotes && (*c == ' ' || *c == '\t')) { + /* + * We have reached a whitespace region. + */ + break; + } + + /* + * Copy this character into the word buffer. + */ + if (word != NULL) { + if (custr_appendc(word, *c) != 0) { + return (-1); + } + } + c++; + } + + /* + * Find the beginning of the next word, if there is one. + */ + for (;;) { + if (*c == '\0') { + /* + * We have reached the end of the string. + */ + *nextword = NULL; + return (0); - if ((cp = wp) == NOSTR) { - copy("", wbuf); - return(NOSTR); + } else if (*c != ' ' && *c != '\t') { + /* + * We have located the next word. + */ + *nextword = c; + return (0); + } + c++; } - cp2 = wbuf; - while (!any(*cp, " \t") && *cp != '\0') - if (*cp == '"') { - *cp2++ = *cp++; - while (*cp != '\0' && *cp != '"') - *cp2++ = *cp++; - if (*cp == '"') - *cp2++ = *cp++; - } else - *cp2++ = *cp++; - *cp2 = '\0'; - while (any(*cp, " \t")) - cp++; - if (*cp == '\0') - return(NOSTR); - return(cp); } /* diff --git a/usr/src/cmd/mailx/receipt.c b/usr/src/cmd/mailx/receipt.c index 2a128d6a91..0b6b9296fc 100644 --- a/usr/src/cmd/mailx/receipt.c +++ b/usr/src/cmd/mailx/receipt.c @@ -19,6 +19,11 @@ * * CDDL HEADER END */ + +/* + * Copyright 2014 Joyent, Inc. + */ + /* * Copyright 1998 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -38,7 +43,7 @@ * contributors. */ -#pragma ident "%Z%%M% %I% %E% SMI" +#include <err.h> #include "rcv.h" @@ -47,12 +52,12 @@ static int icsubstr(char *s1, char *s2); void receipt(struct message *mp) { - struct headline hl; char head[LINESIZE]; char buf[BUFSIZ]; FILE *pp, *fp; char *mail, *s; + if ((mail = value("sendmail")) == 0) #ifdef SENDMAIL mail = SENDMAIL; @@ -63,16 +68,27 @@ receipt(struct message *mp) || icsubstr(hfield(">to", mp, addto), "/receipt")) { snprintf(buf, sizeof (buf), "%s %s", mail, skin(nameof(mp))); if (pp = npopen(buf, "w")) { + headline_t *hl; + + if (headline_alloc(&hl) != 0) { + err(1, "could not allocate memory"); + } + fp = setinput(mp); readline(fp, head); - parse(head, &hl, buf); - if (hl.l_date != NOSTR) - fprintf(pp, "Original-Date: %s\n", hl.l_date); + if (parse_headline(head, hl) != 0) { + headline_reset(hl); + } + if (custr_len(hl->hl_date) > 0) { + fprintf(pp, "Original-Date: %s\n", + custr_cstr(hl->hl_date)); + } if (s = hfield("message-id", mp, addone)) fprintf(pp, "Original-Message-ID: %s\n", s); s = hfield("subject", mp, addone); fprintf(pp, "Subject: RR: %s\n", s ? s : "(none)"); npclose(pp); + headline_free(hl); } } } |