summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorJoshua M. Clulow <jmc@joyent.com>2014-12-19 14:03:07 -0800
committerRobert Mustacchi <rm@joyent.com>2014-12-23 14:52:48 -0800
commit196c7f05d2deba7404e90ad67f3861185c78ca2d (patch)
tree29ff7b2bd21041c7331063485095b6008b58ee10 /usr/src/cmd
parentaa64fa16549f13233681f4b40e50fb5b1c18a97c (diff)
downloadillumos-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/Makefile1
-rw-r--r--usr/src/cmd/fmt/Makefile1
-rw-r--r--usr/src/cmd/fmt/fmt.c6
-rw-r--r--usr/src/cmd/mailx/Makefile4
-rw-r--r--usr/src/cmd/mailx/cmd1.c34
-rw-r--r--usr/src/cmd/mailx/fio.c8
-rw-r--r--usr/src/cmd/mailx/hdr/def.h22
-rw-r--r--usr/src/cmd/mailx/head.c242
-rw-r--r--usr/src/cmd/mailx/receipt.c26
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);
}
}
}