Author: delphij
Date: Tue Jul 28 19:58:44 2015
New Revision: 285976
URL: https://svnweb.freebsd.org/changeset/base/285976

Log:
  Fix patch(1) shell injection vulnerability. [SA-15:14]
  
  Fix resource exhaustion in TCP reassembly. [SA-15:15]
  
  Fix OpenSSH multiple vulnerabilities. [SA-15:16]

Modified:
  stable/10/crypto/openssh/auth2-chall.c
  stable/10/crypto/openssh/sshconnect.c
  stable/10/sys/netinet/tcp_reass.c
  stable/10/sys/netinet/tcp_subr.c
  stable/10/sys/netinet/tcp_var.h
  stable/10/usr.bin/patch/common.h
  stable/10/usr.bin/patch/inp.c

Modified: stable/10/crypto/openssh/auth2-chall.c
==============================================================================
--- stable/10/crypto/openssh/auth2-chall.c      Tue Jul 28 19:58:38 2015        
(r285975)
+++ stable/10/crypto/openssh/auth2-chall.c      Tue Jul 28 19:58:44 2015        
(r285976)
@@ -82,6 +82,7 @@ struct KbdintAuthctxt
        void *ctxt;
        KbdintDevice *device;
        u_int nreq;
+       u_int devices_done;
 };
 
 #ifdef USE_PAM
@@ -168,11 +169,15 @@ kbdint_next_device(Authctxt *authctxt, K
                if (len == 0)
                        break;
                for (i = 0; devices[i]; i++) {
-                       if (!auth2_method_allowed(authctxt,
+                       if ((kbdintctxt->devices_done & (1 << i)) != 0 ||
+                           !auth2_method_allowed(authctxt,
                            "keyboard-interactive", devices[i]->name))
                                continue;
-                       if (strncmp(kbdintctxt->devices, devices[i]->name, len) 
== 0)
+                       if (strncmp(kbdintctxt->devices, devices[i]->name,
+                           len) == 0) {
                                kbdintctxt->device = devices[i];
+                               kbdintctxt->devices_done |= 1 << i;
+                       }
                }
                t = kbdintctxt->devices;
                kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;

Modified: stable/10/crypto/openssh/sshconnect.c
==============================================================================
--- stable/10/crypto/openssh/sshconnect.c       Tue Jul 28 19:58:38 2015        
(r285975)
+++ stable/10/crypto/openssh/sshconnect.c       Tue Jul 28 19:58:44 2015        
(r285976)
@@ -1246,29 +1246,39 @@ verify_host_key(char *host, struct socka
 {
        int flags = 0;
        char *fp;
+       Key *plain = NULL;
 
        fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
        debug("Server host key: %s %s", key_type(host_key), fp);
        free(fp);
 
-       /* XXX certs are not yet supported for DNS */
-       if (!key_is_cert(host_key) && options.verify_host_key_dns &&
-           verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
-               if (flags & DNS_VERIFY_FOUND) {
-
-                       if (options.verify_host_key_dns == 1 &&
-                           flags & DNS_VERIFY_MATCH &&
-                           flags & DNS_VERIFY_SECURE)
-                               return 0;
-
-                       if (flags & DNS_VERIFY_MATCH) {
-                               matching_host_key_dns = 1;
-                       } else {
-                               warn_changed_key(host_key);
-                               error("Update the SSHFP RR in DNS with the new "
-                                   "host key to get rid of this message.");
+       if (options.verify_host_key_dns) {
+               /*
+                * XXX certs are not yet supported for DNS, so downgrade
+                * them and try the plain key.
+                */
+               plain = key_from_private(host_key);
+               if (key_is_cert(plain))
+                       key_drop_cert(plain);
+               if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
+                       if (flags & DNS_VERIFY_FOUND) {
+                               if (options.verify_host_key_dns == 1 &&
+                                   flags & DNS_VERIFY_MATCH &&
+                                   flags & DNS_VERIFY_SECURE) {
+                                       key_free(plain);
+                                       return 0;
+                               }
+                               if (flags & DNS_VERIFY_MATCH) {
+                                       matching_host_key_dns = 1;
+                               } else {
+                                       warn_changed_key(plain);
+                                       error("Update the SSHFP RR in DNS "
+                                           "with the new host key to get rid "
+                                           "of this message.");
+                               }
                        }
                }
+               key_free(plain);
        }
 
        return check_host_key(host, hostaddr, options.port, host_key, RDRW,

Modified: stable/10/sys/netinet/tcp_reass.c
==============================================================================
--- stable/10/sys/netinet/tcp_reass.c   Tue Jul 28 19:58:38 2015        
(r285975)
+++ stable/10/sys/netinet/tcp_reass.c   Tue Jul 28 19:58:44 2015        
(r285976)
@@ -79,25 +79,22 @@ static int tcp_reass_sysctl_qsize(SYSCTL
 static SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0,
     "TCP Segment Reassembly Queue");
 
-static VNET_DEFINE(int, tcp_reass_maxseg) = 0;
-#define        V_tcp_reass_maxseg              VNET(tcp_reass_maxseg)
-SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN,
-    &VNET_NAME(tcp_reass_maxseg), 0,
+static int tcp_reass_maxseg = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN,
+    &tcp_reass_maxseg, 0,
     "Global maximum number of TCP Segments in Reassembly Queue");
 
-SYSCTL_VNET_PROC(_net_inet_tcp_reass, OID_AUTO, cursegments,
+SYSCTL_PROC(_net_inet_tcp_reass, OID_AUTO, cursegments,
     (CTLTYPE_INT | CTLFLAG_RD), NULL, 0, &tcp_reass_sysctl_qsize, "I",
     "Global number of TCP Segments currently in Reassembly Queue");
 
-static VNET_DEFINE(int, tcp_reass_overflows) = 0;
-#define        V_tcp_reass_overflows           VNET(tcp_reass_overflows)
-SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, overflows,
+static int tcp_reass_overflows = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows,
     CTLFLAG_RD,
-    &VNET_NAME(tcp_reass_overflows), 0,
+    &tcp_reass_overflows, 0,
     "Global number of TCP Segment Reassembly Queue Overflows");
 
-static VNET_DEFINE(uma_zone_t, tcp_reass_zone);
-#define        V_tcp_reass_zone                VNET(tcp_reass_zone)
+static uma_zone_t tcp_reass_zone;
 
 /* Initialize TCP reassembly queue */
 static void
@@ -105,36 +102,27 @@ tcp_reass_zone_change(void *tag)
 {
 
        /* Set the zone limit and read back the effective value. */
-       V_tcp_reass_maxseg = nmbclusters / 16;
-       V_tcp_reass_maxseg = uma_zone_set_max(V_tcp_reass_zone,
-           V_tcp_reass_maxseg);
+       tcp_reass_maxseg = nmbclusters / 16;
+       tcp_reass_maxseg = uma_zone_set_max(tcp_reass_zone,
+           tcp_reass_maxseg);
 }
 
 void
-tcp_reass_init(void)
+tcp_reass_global_init(void)
 {
 
-       V_tcp_reass_maxseg = nmbclusters / 16;
+       tcp_reass_maxseg = nmbclusters / 16;
        TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
-           &V_tcp_reass_maxseg);
-       V_tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
+           &tcp_reass_maxseg);
+       tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
            NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
        /* Set the zone limit and read back the effective value. */
-       V_tcp_reass_maxseg = uma_zone_set_max(V_tcp_reass_zone,
-           V_tcp_reass_maxseg);
+       tcp_reass_maxseg = uma_zone_set_max(tcp_reass_zone,
+           tcp_reass_maxseg);
        EVENTHANDLER_REGISTER(nmbclusters_change,
            tcp_reass_zone_change, NULL, EVENTHANDLER_PRI_ANY);
 }
 
-#ifdef VIMAGE
-void
-tcp_reass_destroy(void)
-{
-
-       uma_zdestroy(V_tcp_reass_zone);
-}
-#endif
-
 void
 tcp_reass_flush(struct tcpcb *tp)
 {
@@ -145,7 +133,7 @@ tcp_reass_flush(struct tcpcb *tp)
        while ((qe = LIST_FIRST(&tp->t_segq)) != NULL) {
                LIST_REMOVE(qe, tqe_q);
                m_freem(qe->tqe_m);
-               uma_zfree(V_tcp_reass_zone, qe);
+               uma_zfree(tcp_reass_zone, qe);
                tp->t_segqlen--;
        }
 
@@ -159,7 +147,7 @@ tcp_reass_sysctl_qsize(SYSCTL_HANDLER_AR
 {
        int qsize;
 
-       qsize = uma_zone_get_cur(V_tcp_reass_zone);
+       qsize = uma_zone_get_cur(tcp_reass_zone);
        return (sysctl_handle_int(oidp, &qsize, 0, req));
 }
 
@@ -207,7 +195,7 @@ tcp_reass(struct tcpcb *tp, struct tcphd
         */
        if ((th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) &&
            tp->t_segqlen >= (so->so_rcv.sb_hiwat / tp->t_maxseg) + 1) {
-               V_tcp_reass_overflows++;
+               tcp_reass_overflows++;
                TCPSTAT_INC(tcps_rcvmemdrop);
                m_freem(m);
                *tlenp = 0;
@@ -226,7 +214,7 @@ tcp_reass(struct tcpcb *tp, struct tcphd
         * Use a temporary structure on the stack for the missing segment
         * when the zone is exhausted. Otherwise we may get stuck.
         */
-       te = uma_zalloc(V_tcp_reass_zone, M_NOWAIT);
+       te = uma_zalloc(tcp_reass_zone, M_NOWAIT);
        if (te == NULL) {
                if (th->th_seq != tp->rcv_nxt || 
!TCPS_HAVEESTABLISHED(tp->t_state)) {
                        TCPSTAT_INC(tcps_rcvmemdrop);
@@ -277,7 +265,7 @@ tcp_reass(struct tcpcb *tp, struct tcphd
                                TCPSTAT_ADD(tcps_rcvdupbyte, *tlenp);
                                m_freem(m);
                                if (te != &tqs)
-                                       uma_zfree(V_tcp_reass_zone, te);
+                                       uma_zfree(tcp_reass_zone, te);
                                tp->t_segqlen--;
                                /*
                                 * Try to present any queued data
@@ -314,7 +302,7 @@ tcp_reass(struct tcpcb *tp, struct tcphd
                nq = LIST_NEXT(q, tqe_q);
                LIST_REMOVE(q, tqe_q);
                m_freem(q->tqe_m);
-               uma_zfree(V_tcp_reass_zone, q);
+               uma_zfree(tcp_reass_zone, q);
                tp->t_segqlen--;
                q = nq;
        }
@@ -353,7 +341,7 @@ present:
                else
                        sbappendstream_locked(&so->so_rcv, q->tqe_m);
                if (q != &tqs)
-                       uma_zfree(V_tcp_reass_zone, q);
+                       uma_zfree(tcp_reass_zone, q);
                tp->t_segqlen--;
                q = nq;
        } while (q && q->tqe_th->th_seq == tp->rcv_nxt);

Modified: stable/10/sys/netinet/tcp_subr.c
==============================================================================
--- stable/10/sys/netinet/tcp_subr.c    Tue Jul 28 19:58:38 2015        
(r285975)
+++ stable/10/sys/netinet/tcp_subr.c    Tue Jul 28 19:58:44 2015        
(r285976)
@@ -376,7 +376,6 @@ tcp_init(void)
        tcp_tw_init();
        syncache_init();
        tcp_hc_init();
-       tcp_reass_init();
 
        TUNABLE_INT_FETCH("net.inet.tcp.sack.enable", &V_tcp_do_sack);
        V_sack_hole_zone = uma_zcreate("sackhole", sizeof(struct sackhole),
@@ -386,6 +385,8 @@ tcp_init(void)
        if (!IS_DEFAULT_VNET(curvnet))
                return;
 
+       tcp_reass_global_init();
+
        /* XXX virtualize those bellow? */
        tcp_delacktime = TCPTV_DELACK;
        tcp_keepinit = TCPTV_KEEP_INIT;
@@ -433,7 +434,6 @@ void
 tcp_destroy(void)
 {
 
-       tcp_reass_destroy();
        tcp_hc_destroy();
        syncache_destroy();
        tcp_tw_destroy();

Modified: stable/10/sys/netinet/tcp_var.h
==============================================================================
--- stable/10/sys/netinet/tcp_var.h     Tue Jul 28 19:58:38 2015        
(r285975)
+++ stable/10/sys/netinet/tcp_var.h     Tue Jul 28 19:58:44 2015        
(r285976)
@@ -679,11 +679,8 @@ char       *tcp_log_addrs(struct in_conninfo *
 char   *tcp_log_vain(struct in_conninfo *, struct tcphdr *, void *,
            const void *);
 int     tcp_reass(struct tcpcb *, struct tcphdr *, int *, struct mbuf *);
-void    tcp_reass_init(void);
+void    tcp_reass_global_init(void);
 void    tcp_reass_flush(struct tcpcb *);
-#ifdef VIMAGE
-void    tcp_reass_destroy(void);
-#endif
 void    tcp_input(struct mbuf *, int);
 u_long  tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *);
 u_long  tcp_maxmtu6(struct in_conninfo *, struct tcp_ifcap *);

Modified: stable/10/usr.bin/patch/common.h
==============================================================================
--- stable/10/usr.bin/patch/common.h    Tue Jul 28 19:58:38 2015        
(r285975)
+++ stable/10/usr.bin/patch/common.h    Tue Jul 28 19:58:44 2015        
(r285976)
@@ -43,12 +43,10 @@
 #define        LINENUM_MAX LONG_MAX
 
 #define        SCCSPREFIX "s."
-#define        GET "get -e %s"
-#define        SCCSDIFF "get -p %s | diff - %s >/dev/null"
 
 #define        RCSSUFFIX ",v"
-#define        CHECKOUT "co -l %s"
-#define        RCSDIFF "rcsdiff %s > /dev/null"
+#define        CHECKOUT "/usr/bin/co"
+#define        RCSDIFF "/usr/bin/rcsdiff"
 
 #define        ORIGEXT ".orig"
 #define        REJEXT ".rej"

Modified: stable/10/usr.bin/patch/inp.c
==============================================================================
--- stable/10/usr.bin/patch/inp.c       Tue Jul 28 19:58:38 2015        
(r285975)
+++ stable/10/usr.bin/patch/inp.c       Tue Jul 28 19:58:44 2015        
(r285976)
@@ -31,8 +31,10 @@
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
+#include <sys/wait.h>
 
 #include <ctype.h>
+#include <errno.h>
 #include <libgen.h>
 #include <limits.h>
 #include <stddef.h>
@@ -132,12 +134,14 @@ reallocate_lines(size_t *lines_allocated
 static bool
 plan_a(const char *filename)
 {
-       int             ifd, statfailed;
+       int             ifd, statfailed, devnull, pstat;
        char            *p, *s, lbuf[INITLINELEN];
        struct stat     filestat;
        ptrdiff_t       sz;
        size_t          i;
        size_t          iline, lines_allocated;
+       pid_t           pid;
+       char            *argp[4] = {NULL};
 
 #ifdef DEBUGGING
        if (debug & 8)
@@ -165,13 +169,14 @@ plan_a(const char *filename)
        }
        if (statfailed && check_only)
                fatal("%s not found, -C mode, can't probe further\n", filename);
-       /* For nonexistent or read-only files, look for RCS or SCCS versions.  
*/
+       /* For nonexistent or read-only files, look for RCS versions.  */
+
        if (statfailed ||
            /* No one can write to it.  */
            (filestat.st_mode & 0222) == 0 ||
            /* I can't write to it.  */
            ((filestat.st_mode & 0022) == 0 && filestat.st_uid != getuid())) {
-               const char      *cs = NULL, *filebase, *filedir;
+               char    *filebase, *filedir;
                struct stat     cstat;
                char *tmp_filename1, *tmp_filename2;
 
@@ -179,43 +184,26 @@ plan_a(const char *filename)
                tmp_filename2 = strdup(filename);
                if (tmp_filename1 == NULL || tmp_filename2 == NULL)
                        fatal("strdupping filename");
+
                filebase = basename(tmp_filename1);
                filedir = dirname(tmp_filename2);
 
-               /* Leave room in lbuf for the diff command.  */
-               s = lbuf + 20;
-
 #define try(f, a1, a2, a3) \
-       (snprintf(s, buf_size - 20, f, a1, a2, a3), stat(s, &cstat) == 0)
-
-               if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
-                   try("%s/RCS/%s%s", filedir, filebase, "") ||
-                   try("%s/%s%s", filedir, filebase, RCSSUFFIX)) {
-                       snprintf(buf, buf_size, CHECKOUT, filename);
-                       snprintf(lbuf, sizeof lbuf, RCSDIFF, filename);
-                       cs = "RCS";
-               } else if (try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
-                   try("%s/%s%s", filedir, SCCSPREFIX, filebase)) {
-                       snprintf(buf, buf_size, GET, s);
-                       snprintf(lbuf, sizeof lbuf, SCCSDIFF, s, filename);
-                       cs = "SCCS";
-               } else if (statfailed)
-                       fatal("can't find %s\n", filename);
-
-               free(tmp_filename1);
-               free(tmp_filename2);
+       (snprintf(lbuf, sizeof(lbuf), f, a1, a2, a3), stat(lbuf, &cstat) == 0)
 
                /*
                 * else we can't write to it but it's not under a version
                 * control system, so just proceed.
                 */
-               if (cs) {
+               if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
+                   try("%s/RCS/%s%s", filedir, filebase, "") ||
+                   try("%s/%s%s", filedir, filebase, RCSSUFFIX)) {
                        if (!statfailed) {
                                if ((filestat.st_mode & 0222) != 0)
                                        /* The owner can write to it.  */
                                        fatal("file %s seems to be locked "
-                                           "by somebody else under %s\n",
-                                           filename, cs);
+                                           "by somebody else under RCS\n",
+                                           filename);
                                /*
                                 * It might be checked out unlocked.  See if
                                 * it's safe to check out the default version
@@ -223,21 +211,59 @@ plan_a(const char *filename)
                                 */
                                if (verbose)
                                        say("Comparing file %s to default "
-                                           "%s version...\n",
-                                           filename, cs);
-                               if (system(lbuf))
+                                           "RCS version...\n", filename);
+
+                               switch (pid = fork()) {
+                               case -1:
+                                       fatal("can't fork: %s\n",
+                                           strerror(errno));
+                               case 0:
+                                       devnull = open("/dev/null", O_RDONLY);
+                                       if (devnull == -1) {
+                                               fatal("can't open /dev/null: 
%s",
+                                                   strerror(errno));
+                                       }
+                                       (void)dup2(devnull, STDOUT_FILENO);
+                                       argp[0] = strdup(RCSDIFF);
+                                       argp[1] = strdup(filename);
+                                       execv(RCSDIFF, argp);
+                                       exit(127);
+                               }
+                               pid = waitpid(pid, &pstat, 0);
+                               if (pid == -1 || WEXITSTATUS(pstat) != 0) {
                                        fatal("can't check out file %s: "
-                                           "differs from default %s version\n",
-                                           filename, cs);
+                                           "differs from default RCS 
version\n",
+                                           filename);
+                               }
                        }
+
                        if (verbose)
-                               say("Checking out file %s from %s...\n",
-                                   filename, cs);
-                       if (system(buf) || stat(filename, &filestat))
-                               fatal("can't check out file %s from %s\n",
-                                   filename, cs);
+                               say("Checking out file %s from RCS...\n",
+                                   filename);
+
+                       switch (pid = fork()) {
+                       case -1:
+                               fatal("can't fork: %s\n", strerror(errno));
+                       case 0:
+                               argp[0] = strdup(CHECKOUT);
+                               argp[1] = strdup("-l");
+                               argp[2] = strdup(filename);
+                               execv(CHECKOUT, argp);
+                               exit(127);
+                       }
+                       pid = waitpid(pid, &pstat, 0);
+                       if (pid == -1 || WEXITSTATUS(pstat) != 0 ||
+                           stat(filename, &filestat)) {
+                               fatal("can't check out file %s from RCS\n",
+                                   filename);
+                       }
+               } else if (statfailed) {
+                       fatal("can't find %s\n", filename);
                }
+               free(tmp_filename1);
+               free(tmp_filename2);
        }
+
        filemode = filestat.st_mode;
        if (!S_ISREG(filemode))
                fatal("%s is not a normal file--can't patch\n", filename);
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to