Author: delphij
Date: Tue Apr  8 18:27:32 2014
New Revision: 264265
URL: http://svnweb.freebsd.org/changeset/base/264265

Log:
  Fix NFS deadlock vulnerability. [SA-14:05]
  
  Fix "Heartbleed" vulnerability and ECDSA Cache Side-channel
  Attack in OpenSSL. [SA-14:06]

Modified:
  head/crypto/openssl/crypto/bn/bn.h
  head/crypto/openssl/crypto/bn/bn_lib.c
  head/crypto/openssl/crypto/ec/ec2_mult.c
  head/crypto/openssl/ssl/d1_both.c
  head/crypto/openssl/ssl/t1_lib.c
  head/sys/fs/nfsserver/nfs_nfsdserv.c

Modified: head/crypto/openssl/crypto/bn/bn.h
==============================================================================
--- head/crypto/openssl/crypto/bn/bn.h  Tue Apr  8 18:22:03 2014        
(r264264)
+++ head/crypto/openssl/crypto/bn/bn.h  Tue Apr  8 18:27:32 2014        
(r264265)
@@ -538,6 +538,8 @@ BIGNUM *BN_mod_inverse(BIGNUM *ret,
 BIGNUM *BN_mod_sqrt(BIGNUM *ret,
        const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
 
+void   BN_consttime_swap(BN_ULONG swap, BIGNUM *a, BIGNUM *b, int nwords);
+
 /* Deprecated versions */
 #ifndef OPENSSL_NO_DEPRECATED
 BIGNUM *BN_generate_prime(BIGNUM *ret,int bits,int safe,
@@ -774,11 +776,20 @@ int RAND_pseudo_bytes(unsigned char *buf
 
 #define bn_fix_top(a)          bn_check_top(a)
 
+#define bn_check_size(bn, bits) bn_wcheck_size(bn, 
((bits+BN_BITS2-1))/BN_BITS2)
+#define bn_wcheck_size(bn, words) \
+       do { \
+               const BIGNUM *_bnum2 = (bn); \
+               assert(words <= (_bnum2)->dmax && words >= (_bnum2)->top); \
+       } while(0)
+
 #else /* !BN_DEBUG */
 
 #define bn_pollute(a)
 #define bn_check_top(a)
 #define bn_fix_top(a)          bn_correct_top(a)
+#define bn_check_size(bn, bits)
+#define bn_wcheck_size(bn, words)
 
 #endif
 

Modified: head/crypto/openssl/crypto/bn/bn_lib.c
==============================================================================
--- head/crypto/openssl/crypto/bn/bn_lib.c      Tue Apr  8 18:22:03 2014        
(r264264)
+++ head/crypto/openssl/crypto/bn/bn_lib.c      Tue Apr  8 18:27:32 2014        
(r264265)
@@ -824,3 +824,55 @@ int bn_cmp_part_words(const BN_ULONG *a,
                }
        return bn_cmp_words(a,b,cl);
        }
+
+/* 
+ * Constant-time conditional swap of a and b.  
+ * a and b are swapped if condition is not 0.  The code assumes that at most 
one bit of condition is set.
+ * nwords is the number of words to swap.  The code assumes that at least 
nwords are allocated in both a and b,
+ * and that no more than nwords are used by either a or b.
+ * a and b cannot be the same number
+ */
+void BN_consttime_swap(BN_ULONG condition, BIGNUM *a, BIGNUM *b, int nwords)
+       {
+       BN_ULONG t;
+       int i;
+
+       bn_wcheck_size(a, nwords);
+       bn_wcheck_size(b, nwords);
+
+       assert(a != b);
+       assert((condition & (condition - 1)) == 0);
+       assert(sizeof(BN_ULONG) >= sizeof(int));
+
+       condition = ((condition - 1) >> (BN_BITS2 - 1)) - 1;
+
+       t = (a->top^b->top) & condition;
+       a->top ^= t;
+       b->top ^= t;
+
+#define BN_CONSTTIME_SWAP(ind) \
+       do { \
+               t = (a->d[ind] ^ b->d[ind]) & condition; \
+               a->d[ind] ^= t; \
+               b->d[ind] ^= t; \
+       } while (0)
+
+
+       switch (nwords) {
+       default:
+               for (i = 10; i < nwords; i++) 
+                       BN_CONSTTIME_SWAP(i);
+               /* Fallthrough */
+       case 10: BN_CONSTTIME_SWAP(9); /* Fallthrough */
+       case 9: BN_CONSTTIME_SWAP(8); /* Fallthrough */
+       case 8: BN_CONSTTIME_SWAP(7); /* Fallthrough */
+       case 7: BN_CONSTTIME_SWAP(6); /* Fallthrough */
+       case 6: BN_CONSTTIME_SWAP(5); /* Fallthrough */
+       case 5: BN_CONSTTIME_SWAP(4); /* Fallthrough */
+       case 4: BN_CONSTTIME_SWAP(3); /* Fallthrough */
+       case 3: BN_CONSTTIME_SWAP(2); /* Fallthrough */
+       case 2: BN_CONSTTIME_SWAP(1); /* Fallthrough */
+       case 1: BN_CONSTTIME_SWAP(0);
+       }
+#undef BN_CONSTTIME_SWAP
+}

Modified: head/crypto/openssl/crypto/ec/ec2_mult.c
==============================================================================
--- head/crypto/openssl/crypto/ec/ec2_mult.c    Tue Apr  8 18:22:03 2014        
(r264264)
+++ head/crypto/openssl/crypto/ec/ec2_mult.c    Tue Apr  8 18:27:32 2014        
(r264265)
@@ -208,11 +208,15 @@ static int gf2m_Mxy(const EC_GROUP *grou
        return ret;
        }
 
+
 /* Computes scalar*point and stores the result in r.
  * point can not equal r.
- * Uses algorithm 2P of
+ * Uses a modified algorithm 2P of
  *     Lopez, J. and Dahab, R.  "Fast multiplication on elliptic curves over 
  *     GF(2^m) without precomputation" (CHES '99, LNCS 1717).
+ *
+ * To protect against side-channel attack the function uses constant time swap,
+ * avoiding conditional branches.
  */
 static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT 
*r, const BIGNUM *scalar,
        const EC_POINT *point, BN_CTX *ctx)
@@ -246,6 +250,11 @@ static int ec_GF2m_montgomery_point_mult
        x2 = &r->X;
        z2 = &r->Y;
 
+       bn_wexpand(x1, group->field.top);
+       bn_wexpand(z1, group->field.top);
+       bn_wexpand(x2, group->field.top);
+       bn_wexpand(z2, group->field.top);
+
        if (!BN_GF2m_mod_arr(x1, &point->X, group->poly)) goto err; /* x1 = x */
        if (!BN_one(z1)) goto err; /* z1 = 1 */
        if (!group->meth->field_sqr(group, z2, x1, ctx)) goto err; /* z2 = x1^2 
= x^2 */
@@ -270,16 +279,12 @@ static int ec_GF2m_montgomery_point_mult
                word = scalar->d[i];
                while (mask)
                        {
-                       if (word & mask)
-                               {
-                               if (!gf2m_Madd(group, &point->X, x1, z1, x2, 
z2, ctx)) goto err;
-                               if (!gf2m_Mdouble(group, x2, z2, ctx)) goto err;
-                               }
-                       else
-                               {
-                               if (!gf2m_Madd(group, &point->X, x2, z2, x1, 
z1, ctx)) goto err;
-                               if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err;
-                               }
+                       BN_consttime_swap(word & mask, x1, x2, 
group->field.top);
+                       BN_consttime_swap(word & mask, z1, z2, 
group->field.top);
+                       if (!gf2m_Madd(group, &point->X, x2, z2, x1, z1, ctx)) 
goto err;
+                       if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err;
+                       BN_consttime_swap(word & mask, x1, x2, 
group->field.top);
+                       BN_consttime_swap(word & mask, z1, z2, 
group->field.top);
                        mask >>= 1;
                        }
                mask = BN_TBIT;

Modified: head/crypto/openssl/ssl/d1_both.c
==============================================================================
--- head/crypto/openssl/ssl/d1_both.c   Tue Apr  8 18:22:03 2014        
(r264264)
+++ head/crypto/openssl/ssl/d1_both.c   Tue Apr  8 18:27:32 2014        
(r264265)
@@ -1459,26 +1459,36 @@ dtls1_process_heartbeat(SSL *s)
        unsigned int payload;
        unsigned int padding = 16; /* Use minimum padding */
 
-       /* Read type and payload length first */
-       hbtype = *p++;
-       n2s(p, payload);
-       pl = p;
-
        if (s->msg_callback)
                s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
                        &s->s3->rrec.data[0], s->s3->rrec.length,
                        s, s->msg_callback_arg);
 
+       /* Read type and payload length first */
+       if (1 + 2 + 16 > s->s3->rrec.length)
+               return 0; /* silently discard */
+       hbtype = *p++;
+       n2s(p, payload);
+       if (1 + 2 + payload + 16 > s->s3->rrec.length)
+               return 0; /* silently discard per RFC 6520 sec. 4 */
+       pl = p;
+
        if (hbtype == TLS1_HB_REQUEST)
                {
                unsigned char *buffer, *bp;
+               unsigned int write_length = 1 /* heartbeat type */ +
+                                           2 /* heartbeat length */ +
+                                           payload + padding;
                int r;
 
+               if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
+                       return 0;
+
                /* Allocate memory for the response, size is 1 byte
                 * message type, plus 2 bytes payload length, plus
                 * payload, plus padding
                 */
-               buffer = OPENSSL_malloc(1 + 2 + payload + padding);
+               buffer = OPENSSL_malloc(write_length);
                bp = buffer;
 
                /* Enter response type, length and copy payload */
@@ -1489,11 +1499,11 @@ dtls1_process_heartbeat(SSL *s)
                /* Random padding */
                RAND_pseudo_bytes(bp, padding);
 
-               r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload 
+ padding);
+               r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 
write_length);
 
                if (r >= 0 && s->msg_callback)
                        s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
-                               buffer, 3 + payload + padding,
+                               buffer, write_length,
                                s, s->msg_callback_arg);
 
                OPENSSL_free(buffer);

Modified: head/crypto/openssl/ssl/t1_lib.c
==============================================================================
--- head/crypto/openssl/ssl/t1_lib.c    Tue Apr  8 18:22:03 2014        
(r264264)
+++ head/crypto/openssl/ssl/t1_lib.c    Tue Apr  8 18:27:32 2014        
(r264265)
@@ -2558,16 +2558,20 @@ tls1_process_heartbeat(SSL *s)
        unsigned int payload;
        unsigned int padding = 16; /* Use minimum padding */
 
-       /* Read type and payload length first */
-       hbtype = *p++;
-       n2s(p, payload);
-       pl = p;
-
        if (s->msg_callback)
                s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
                        &s->s3->rrec.data[0], s->s3->rrec.length,
                        s, s->msg_callback_arg);
 
+       /* Read type and payload length first */
+       if (1 + 2 + 16 > s->s3->rrec.length)
+               return 0; /* silently discard */
+       hbtype = *p++;
+       n2s(p, payload);
+       if (1 + 2 + payload + 16 > s->s3->rrec.length)
+               return 0; /* silently discard per RFC 6520 sec. 4 */
+       pl = p;
+
        if (hbtype == TLS1_HB_REQUEST)
                {
                unsigned char *buffer, *bp;

Modified: head/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdserv.c        Tue Apr  8 18:22:03 2014        
(r264264)
+++ head/sys/fs/nfsserver/nfs_nfsdserv.c        Tue Apr  8 18:27:32 2014        
(r264265)
@@ -1457,10 +1457,23 @@ nfsrvd_rename(struct nfsrv_descript *nd,
                nfsvno_relpathbuf(&fromnd);
                goto out;
        }
+       /*
+        * Unlock dp in this code section, so it is unlocked before
+        * tdp gets locked. This avoids a potential LOR if tdp is the
+        * parent directory of dp.
+        */
        if (nd->nd_flag & ND_NFSV4) {
                tdp = todp;
                tnes = *toexp;
-               tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
+               if (dp != tdp) {
+                       NFSVOPUNLOCK(dp, 0);
+                       tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
+                           p, 0);      /* Might lock tdp. */
+               } else {
+                       tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
+                           p, 1);
+                       NFSVOPUNLOCK(dp, 0);
+               }
        } else {
                tfh.nfsrvfh_len = 0;
                error = nfsrv_mtofh(nd, &tfh);
@@ -1481,10 +1494,12 @@ nfsrvd_rename(struct nfsrv_descript *nd,
                        tnes = *exp;
                        tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
                            p, 1);
+                       NFSVOPUNLOCK(dp, 0);
                } else {
+                       NFSVOPUNLOCK(dp, 0);
                        nd->nd_cred->cr_uid = nd->nd_saveduid;
                        nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
-                           0, p);
+                           0, p);      /* Locks tdp. */
                        if (tdp) {
                                tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
                                    nd->nd_cred, p, 1);
@@ -1499,7 +1514,7 @@ nfsrvd_rename(struct nfsrv_descript *nd,
                if (error) {
                        if (tdp)
                                vrele(tdp);
-                       vput(dp);
+                       vrele(dp);
                        nfsvno_relpathbuf(&fromnd);
                        nfsvno_relpathbuf(&tond);
                        goto out;
@@ -1514,7 +1529,7 @@ nfsrvd_rename(struct nfsrv_descript *nd,
                }
                if (tdp)
                        vrele(tdp);
-               vput(dp);
+               vrele(dp);
                nfsvno_relpathbuf(&fromnd);
                nfsvno_relpathbuf(&tond);
                goto out;
@@ -1523,7 +1538,7 @@ nfsrvd_rename(struct nfsrv_descript *nd,
        /*
         * Done parsing, now down to business.
         */
-       nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
+       nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
        if (nd->nd_repstat) {
                if (nd->nd_flag & ND_NFSV3) {
                        nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to