[nas] Fix CVE-2013-4256 and CVE-2013-4257
Petr Pisar
ppisar at fedoraproject.org
Tue Sep 17 07:15:41 UTC 2013
commit b654a4771a1a108355ebca3a868a1167ad84bd3d
Author: Petr Písař <ppisar at redhat.com>
Date: Mon Sep 16 16:25:52 2013 +0200
Fix CVE-2013-4256 and CVE-2013-4257
nas-1.9.3-CVE-2013-4256-1.patch | 63 +++++
nas-1.9.3-CVE-2013-4256-2_CVE-2013-4257.patch | 340 +++++++++++++++++++++++++
nas.spec | 12 +
3 files changed, 415 insertions(+), 0 deletions(-)
---
diff --git a/nas-1.9.3-CVE-2013-4256-1.patch b/nas-1.9.3-CVE-2013-4256-1.patch
new file mode 100644
index 0000000..3a37e22
--- /dev/null
+++ b/nas-1.9.3-CVE-2013-4256-1.patch
@@ -0,0 +1,63 @@
+------------------------------------------------------------------------
+r287 | auerswald | 2013-08-09 19:19:13 +0200 (Pá, 09 srp 2013) | 18 lines
+
+Accept only possible values for listen port offset of nasd.
+
+Verify that the listen port offset specified as a command line argument
+to nasd is a non-negative number that will result in a valid TCP port
+number if added to AU_DEFAULT_TCP_PORT (currently 8000).
+
+Specifying a long argument starting with a colon would otherwise result
+in buffer overflows later on.
+
+The problem was reported to the nas mailing list by
+Hamid Zamani <me at hamidx9.ir>, together with other vulnerabilities
+in NAS 1.9.3:
+
+http://radscan.com/pipermail/nas/2013-August/001270.html
+
+[Adding bounds checks to the string operations is still needed to guarantee
+they do not overflow.]
+
+------------------------------------------------------------------------
+Index: server/os/utils.c
+===================================================================
+--- server/os/utils.c (revision 286)
++++ server/os/utils.c (revision 287)
+@@ -50,6 +50,9 @@
+
+ #include <audio/audio.h>
+ #include <audio/Aos.h>
++#include <audio/Aproto.h>
++#include <errno.h>
++#include <limits.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include "nasconf.h"
+@@ -298,6 +301,26 @@
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == ':') {
++ char *check;
++ long display_value;
++ errno = 0;
++ display_value = strtol(argv[i]+1, &check, 10);
++ if (errno) {
++ Error("Unable to parse display number");
++ continue;
++ }
++ if (check[0] != '\0') {
++ fprintf(stderr, "Listen port offset must be a number.\n");
++ continue;
++ }
++ if (display_value > USHRT_MAX - AU_DEFAULT_TCP_PORT) {
++ fprintf(stderr, "Ignoring too big listen port offset.\n");
++ continue;
++ }
++ if (display_value < 0) {
++ fprintf(stderr, "Ignoring negative listen port offset.\n");
++ continue;
++ }
+ display = argv[i];
+ display++;
+ } else if (strcmp(argv[i], "-aa") == 0)
diff --git a/nas-1.9.3-CVE-2013-4256-2_CVE-2013-4257.patch b/nas-1.9.3-CVE-2013-4256-2_CVE-2013-4257.patch
new file mode 100644
index 0000000..d0a5a4b
--- /dev/null
+++ b/nas-1.9.3-CVE-2013-4256-2_CVE-2013-4257.patch
@@ -0,0 +1,340 @@
+------------------------------------------------------------------------
+r288 | auerswald | 2013-08-11 23:28:33 +0200 (Ne, 11 srp 2013) | 21 lines
+
+nasd: Use snprintf, strncpy, and strncat to guard against buffer overflows.
+
+Hamid Zamani <me at hamidx9.ir> reported a list of vulnerabilities in nasd
+to the NAS mailing list:
+
+http://radscan.com/pipermail/nas/2013-August/001270.html
+
+Most of these result from using sprintf, strcpy, and strcat with fixed
+buffer sizes, but unknown input data. Ensure that the fixed buffers do
+not overflow by using snprintf, strncpy, and strncat. Since strncpy
+does not guarantee to terminate the copied string with '\0', set the
+last position of the destination buffer to '\0' manually.
+
+This commit assumes that snprintf, strncpy, and strncat are available
+everywhere nasd is used.
+
+One vulnerability from the list mentioned above is still open. This affects
+MINIX only, and Hamid Zamani suggested a fix:
+
+http://radscan.com/pipermail/nas/2013-August/001284.html
+
+------------------------------------------------------------------------
+Index: server/os/connection.c
+===================================================================
+--- server/os/connection.c (revision 287)
++++ server/os/connection.c (revision 288)
+@@ -534,8 +534,10 @@
+ chmod(X_UNIX_DIR, 0777 | S_ISVTX);
+ #endif
+
+- strcpy(unsock.sun_path, X_UNIX_PATH);
+- strcat(unsock.sun_path, display);
++ strncpy(unsock.sun_path, X_UNIX_PATH, sizeof unsock.sun_path);
++ unsock.sun_path[sizeof unsock.sun_path - 1] = '\0';
++ strncat(unsock.sun_path, display,
++ sizeof unsock.sun_path - strlen(unsock.sun_path) - 1);
+ #ifdef BSD44SOCKETS
+ unsock.sun_len = strlen(unsock.sun_path);
+ #endif
+@@ -550,12 +552,15 @@
+ static char oldLinkName[256];
+
+ uname(&systemName);
+- strcpy(oldLinkName, OLD_UNIX_DIR);
++ strncpy(oldLinkName, OLD_UNIX_DIR, sizeof oldLinkName);
++ oldLinkName[sizeof oldLinkName - 1] = '\0';
+ if (!mkdir(oldLinkName, 0777))
+ chown(oldLinkName, 2, 3);
+- strcat(oldLinkName, "/");
+- strcat(oldLinkName, systemName.nodename);
+- strcat(oldLinkName, display);
++ strncat(oldLinkName, "/", sizeof oldLinkName - strlen(oldLinkName) - 1);
++ strncat(oldLinkName, systemName.nodename,
++ sizeof oldLinkName - strlen(oldLinkName) - 1);
++ strncat(oldLinkName, display,
++ sizeof oldLinkName - strlen(oldLinkName) - 1);
+ unlink(oldLinkName);
+ symlink(unsock.sun_path, oldLinkName);
+ }
+@@ -568,8 +573,8 @@
+ i = strlen(unsock.sun_path);
+ buffer = (char *) malloc(i + 80);
+ if (buffer) {
+- sprintf(buffer, "Error creating unix socket: %s\n",
+- unsock.sun_path);
++ snprintf(buffer, i+80, "Error creating unix socket: %s\n",
++ unsock.sun_path);
+ Error(buffer);
+ free(buffer);
+ } else
+@@ -591,7 +596,7 @@
+ i = strlen(unsock.sun_path);
+ buffer = (char *) malloc(i + 80);
+ if (buffer) {
+- sprintf(buffer, "Error binding unix socket: %s\n",
++ snprintf(buffer, i+80, "Error binding unix socket: %s\n",
+ unsock.sun_path);
+ Error(buffer);
+ free(buffer);
+@@ -669,15 +674,15 @@
+ mkdir(AUDIO_ISC_DIR, 0777);
+ chmod(AUDIO_ISC_DIR, 0777);
+
+- strcpy(path, AUDIO_ISC_PATH);
++ strncpy(path, AUDIO_ISC_PATH, sizeof path); path[sizeof path - 1] = '\0';
+ #else /* SVR4_ACP && UNIXCONN */
+ mkdir(X_UNIX_DIR, 0777);
+ chmod(X_UNIX_DIR, 0777);
+
+- strcpy(path, X_UNIX_PATH);
++ strncpy(path, X_UNIX_PATH, sizeof path); path[sizeof path - 1] = '\0';
+ #endif /* SVR4_ACP && UNIXCONN */
+
+- strcat(path, display);
++ strncat(path, display, sizeof path - strlen(path) - 1);
+
+ if (unlink(path) < 0 && errno != ENOENT) {
+ ErrorF("audio server: ISC listener pipe in use (%s)\n", path);
+@@ -729,8 +734,8 @@
+ int fds = -1, fdr = -1;
+ char pathS[64], pathR[64];
+
+- sprintf(pathS, "%s%sS", AUDIO_XSIGHT_PATH, display);
+- sprintf(pathR, "%s%sR", AUDIO_XSIGHT_PATH, display);
++ snprintf(pathS, sizeof pathS, "%s%sS", AUDIO_XSIGHT_PATH, display);
++ snprintf(pathR, sizeof pathR, "%s%sR", AUDIO_XSIGHT_PATH, display);
+
+ if ((unlink(pathS) < 0 && errno != ENOENT) ||
+ (unlink(pathR) < 0 && errno != ENOENT)) {
+@@ -802,8 +807,9 @@
+ mkdir(AUDIO_STREAMS_DIR, 0777);
+ chmod(AUDIO_STREAMS_DIR, 0777);
+
+- strcpy(path, AUDIO_STREAMS_PATH);
+- strcat(path, display);
++ strncpy(path, AUDIO_STREAMS_PATH, sizeof path);
++ path[sizeof path - 1] = '\0';
++ strncat(path, display, sizeof path - strlen(path) - 1);
+
+ if ((unlink(path) < 0 && errno != ENOENT)) {
+ ErrorF("audio server: USL listener pipe in use (%s)\n", path);
+@@ -842,8 +848,9 @@
+ mkdir(AUDIO_STREAMS_DIR, 0777);
+ chmod(AUDIO_STREAMS_DIR, 0777);
+
+- strcpy(path, AUDIO_NSTREAMS_PATH);
+- strcat(path, display);
++ strncpy(path, AUDIO_NSTREAMS_PATH, sizeof path);
++ path[sizeof path - 1] = '\0';
++ strncat(path, display, sizeof path - strlen(path) - 1);
+
+ if ((unlink(path) < 0 && errno != ENOENT)) {
+ ErrorF("audio server: SVR4 named listener pipe in use (%s)\n",
+@@ -1039,7 +1046,8 @@
+ }
+ bzero((char *) &dnsock, sizeof(dnsock));
+ dnsock.sdn_family = AF_DECnet;
+- sprintf(dnsock.sdn_objname, "AUDIO$%d", atoi(display));
++ snprintf(dnsock.sdn_objname, sizeof(dnsock.sdn_objname), "AUDIO$%d",
++ atoi(display));
+ dnsock.sdn_objnamel = strlen(dnsock.sdn_objname);
+ if (bind(request, (struct sockaddr *) &dnsock, sizeof(dnsock))) {
+ Error("Binding DECnet socket");
+@@ -1293,31 +1301,35 @@
+ {
+ char addr[128];
+
+- if (!len)
+- strcpy(addr, "local host");
++ if (!len) {
++ strncpy(addr, "local host", sizeof addr);
++ addr[sizeof addr - 1] = '\0';
++ }
+ else
+ switch (saddr->sa_family) {
+ case AF_UNSPEC:
+ #ifdef UNIXCONN
+ case AF_UNIX:
+ #endif
+- strcpy(addr, "local host");
++ strncpy(addr, "local host", sizeof addr);
++ addr[sizeof addr - 1] = '\0';
+ break;
+ #ifdef TCPCONN
+ case AF_INET:
+- sprintf(addr, "IP %s port %d",
++ snprintf(addr, sizeof addr, "IP %s port %d",
+ inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr),
+ (int) ntohs(((struct sockaddr_in *) saddr)->sin_port));
+ break;
+ #endif
+ #ifdef DNETCONN
+ case AF_DECnet:
+- sprintf(addr, "DN %s",
++ snprintf(addr, sizeof addr, "DN %s",
+ dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add));
+ break;
+ #endif
+ default:
+- strcpy(addr, "unknown address");
++ strncpy(addr, "unknown address", sizeof addr);
++ addr[sizeof addr - 1] = '\0';
+ }
+ if (letin)
+ AuditF("client %d connected from %s\n", client, addr);
+@@ -2115,7 +2127,7 @@
+ if (AuServerHostName == NULL)
+ FatalError
+ ("AUDIOHOST not set, or server host name not given\n");
+- sprintf(host, "%s/%s:%s", DEF_AUSVRDIR, AuServerHostName,
++ snprintf(host, sizeof host, "%s/%s:%s", DEF_AUSVRDIR, AuServerHostName,
+ 0 /* port */ );
+
+ uniqport(&Au.cap_port);
+@@ -2366,13 +2378,13 @@
+
+ buf[0] = '\0';
+ if (status == 0)
+- sprintf(buf, "NONE");
++ snprintf(buf, sizeof buf, "NONE");
+ if (status & CONN_KILLED)
+- sprintf(buf, "%s KILLED", buf);
++ strncat(buf, " KILLED", sizeof buf - strlen(buf) - 1);
+ if (status & REQ_PUSHBACK)
+- sprintf(buf, "%s PUSHBACK", buf);
++ strncat(buf, " PUSHBACK", sizeof buf - strlen(buf) - 1);
+ if (status & IGNORE)
+- sprintf(buf, "%s IGNORE", buf);
++ strncat(buf, " IGNORE", sizeof buf - strlen(buf) - 1);
+ return buf;
+ }
+
+@@ -2466,7 +2478,8 @@
+
+ case STD_INFO:
+ rep.h_status = STD_OK;
+- sprintf(repb, "audio server on %s", AuServerHostName);
++ snprintf(repb, REPLY_BUFSIZE, "audio server on %s",
++ AuServerHostName);
+ rep.h_size = strlen(repb);
+ putrep(&rep, repb, rep.h_size);
+ break;
+@@ -2631,9 +2644,9 @@
+ int result;
+ int looping = 0;
+
+- strncpy(name, AuTcpServerName, BUFSIZ);
++ strncpy(name, AuTcpServerName, BUFSIZ); name[BUFSIZ-1] = '\0';
+ if ((err = name_lookup(name, &svrcap)) != STD_OK) {
+- sprintf(name, "%s/%s", TCP_SVR_NAME, AuTcpServerName);
++ snprintf(name, BUFSIZ, "%s/%s", TCP_SVR_NAME, AuTcpServerName);
+ if ((err = name_lookup(name, &svrcap)) != STD_OK)
+ FatalError("Lookup %s failed: %s\n", AuTcpServerName,
+ err_why(err));
+Index: server/os/access.c
+===================================================================
+--- server/os/access.c (revision 287)
++++ server/os/access.c (revision 288)
+@@ -478,9 +478,9 @@
+ validhosts = host->next;
+ FreeHost(host);
+ }
+- strcpy(fname, "/etc/X");
+- strcat(fname, display);
+- strcat(fname, ".hosts");
++ strncpy(fname, "/etc/X", sizeof fname); fname[sizeof fname - 1] = '\0';
++ strncat(fname, display, sizeof fname - strlen(fname) - 1);
++ strncat(fname, ".hosts", sizeof fname - strlen(fname) - 1);
+ if (fd = fopen(fname, "r")) {
+ while (fgets(hostname, sizeof(hostname), fd)) {
+ if (ptr = index(hostname, '\n'))
+Index: server/os/osinit.c
+===================================================================
+--- server/os/osinit.c (revision 287)
++++ server/os/osinit.c (revision 288)
+@@ -101,7 +101,7 @@
+ /* hack test to decide where to log errors */
+ if (write(2, fname, 0)) {
+ FILE *err;
+- sprintf(fname, ADMPATH, display);
++ snprintf(fname, sizeof fname, ADMPATH, display);
+ /*
+ * uses stdio to avoid os dependencies here,
+ * a real os would use
+Index: server/os/aulog.c
+===================================================================
+--- server/os/aulog.c (revision 287)
++++ server/os/aulog.c (revision 288)
+@@ -29,7 +29,7 @@
+
+ va_start(ap, fmt);
+
+- (void) vsprintf(buf, fmt, ap);
++ (void) vsnprintf(buf, sizeof buf, fmt, ap);
+
+ va_end(ap);
+
+Index: server/os/iopreader.c
+===================================================================
+--- server/os/iopreader.c (revision 287)
++++ server/os/iopreader.c (revision 288)
+@@ -49,7 +49,8 @@
+ */
+ if (AuServerHostName == NULL)
+ FatalError("No hostname, no screen\n");
+- sprintf(host, "%s/%s/%s", HOST_DIR, AuServerHostName, DEF_IOPSVRNAME);
++ snprintf(host, sizeof host, "%s/%s/%s", HOST_DIR, AuServerHostName,
++ DEF_IOPSVRNAME);
+ if ((err = name_lookup(host, &iopcap)) != STD_OK)
+ FatalError("Cannot find IOP server %s: %s\n", host, err_why(err));
+
+Index: server/dda/sun/ausuni.c
+===================================================================
+--- server/dda/sun/ausuni.c (revision 287)
++++ server/dda/sun/ausuni.c (revision 288)
+@@ -1368,7 +1368,7 @@
+ /* pebl: We cannot just concat "ctl" on variable device, so
+ make a copy and concat "ctl". (free it again) */
+ if (!(devicectl = (char *) aualloc(strlen(device) +
+- strlen("ctl"))))
++ strlen("ctl") + 1)))
+ return AuFalse;
+ sprintf(devicectl, "%sctl", device);
+
+Index: server/dda/voxware/auvoxware.c
+===================================================================
+--- server/dda/voxware/auvoxware.c (revision 287)
++++ server/dda/voxware/auvoxware.c (revision 288)
+@@ -1445,7 +1445,8 @@
+ {
+ char tempbuf[80];
+
+- sprintf(tempbuf, "\nwriteMono buf: %d size: %d\n", buf, bufSize);
++ snprintf(tempbuf, sizeof tempbuf, "\nwriteMono buf: %d size: %d\n",
++ buf, bufSize);
+ write(dspout, tempbuf, strlen(tempbuf));
+ write(dspout, buf, bufSize);
+ }
+@@ -1524,7 +1525,8 @@
+ {
+ char tempbuf[80];
+
+- sprintf(tempbuf, "\nwriteStereo buf: %d size: %d\n", buf, bufSize);
++ snprintf(tempbuf, sizeof tempbuf, "\nwriteStereo buf: %d size: %d\n",
++ buf, bufSize);
+ write(dspout, tempbuf, strlen(tempbuf));
+ write(dspout, buf, bufSize);
+ }
+@@ -1586,7 +1588,7 @@
+ #ifdef DEBUGDSPIN
+ {
+ char tempbuf[80];
+- sprintf(tempbuf, "\nreadInputs buf: %d size: %d\n",
++ snprintf(tempbuf, sizeof tempbuf, "\nreadInputs buf: %d size: %d\n",
+ stereoInputDevice->minibuf,
+ stereoInputDevice->bytesPerSample * auMinibufSamples);
+ write(dspin, tempbuf, strlen(tempbuf));
diff --git a/nas.spec b/nas.spec
index c482763..4db7a13 100644
--- a/nas.spec
+++ b/nas.spec
@@ -14,6 +14,13 @@ Patch0: %{name}-1.9.3-Move-AuErrorDB-to-SHAREDIR.patch
# Fix formatting string for syslog, in upstream after 1.9.3, CVE-2013-4258,
# bug #1006753
Patch1: %{name}-1.9.3-CVE-2013-4258.patch
+# Fix buffer overflow when parsing display number, in upstream after 1.9.3,
+# CVE-2013-4256, bug #1006753
+Patch2: %{name}-1.9.3-CVE-2013-4256-1.patch
+# Fix various buffer overflows (CVE-2013-4256) and a heap overflow when using
+# AUDIOHOST environment variable (CVE-2013-4257), in upstream after 1.9.3,
+# bug #1006753
+Patch3: %{name}-1.9.3-CVE-2013-4256-2_CVE-2013-4257.patch
BuildRequires: bison flex
BuildRequires: imake
@@ -67,6 +74,8 @@ Development files and the documentation for Network Audio System.
%setup -q
%patch0 -p1 -b .move_AuErrorDB
%patch1 -p0 -b .CVE-2013-4258
+%patch2 -p0 -b .CVE-2013-4256
+%patch3 -p0 -b .CVE-2013-4256-2_CVE-2013-4257
# Update config.sub to support aarch64, bug #926196
cp -p %{_datadir}/automake-*/config.{sub,guess} config
@@ -151,6 +160,9 @@ echo ' systemd-sysv-convert --apply %{daemon}'
%changelog
* Mon Sep 16 2013 Petr Pisar <ppisar at redhat.com> - 1.9.3-9
- Fix CVE-2013-4258 (formatting string for syslog call) (bug #1006753)
+- Fix CVE-2013-4256 (parsing display number) (bug #1006753)
+- Fix CVE-2013-4257 (heap overflow when processing AUDIOHOST variable)
+ (bug #1006753)
* Sat Aug 03 2013 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 1.9.3-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
More information about the scm-commits
mailing list