aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin LI <delphij@FreeBSD.org>2014-04-08 23:16:05 +0000
committerXin LI <delphij@FreeBSD.org>2014-04-08 23:16:05 +0000
commitf560df808834504a5c85e831ab2d2656337c5d96 (patch)
treeff3978dc672a966c00e0aa6cae9426860c1c9d9f
parent2a3fdf3af127a885a0c5c04d103747cb8ba74c89 (diff)
downloadsrc-f560df808834504a5c85e831ab2d2656337c5d96.tar.gz
src-f560df808834504a5c85e831ab2d2656337c5d96.zip
Fix NFS deadlock vulnerability. [SA-14:05]
Fix ECDSA Cache Side-channel Attack in OpenSSL. [SA-14:06] Approved by: so
Notes
Notes: svn path=/releng/9.2/; revision=264284
-rw-r--r--UPDATING6
-rw-r--r--crypto/openssl/crypto/bn/bn.h11
-rw-r--r--crypto/openssl/crypto/bn/bn_lib.c52
-rw-r--r--crypto/openssl/crypto/ec/ec2_mult.c26
-rw-r--r--sys/conf/newvers.sh2
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c25
6 files changed, 105 insertions, 17 deletions
diff --git a/UPDATING b/UPDATING
index d1ea8703fd85..991238cf2b2c 100644
--- a/UPDATING
+++ b/UPDATING
@@ -11,6 +11,12 @@ handbook:
Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before running portupgrade.
+20140408: p4 FreeBSD-SA-14:05.nfsserver
+ FreeBSD-SA-14:06.openssl
+ Fix deadlock in the NFS server. [SA-14:05]
+
+ Fix for ECDSA Cache Side-channel Attack in OpenSSL. [SA-14:06]
+
20140114: p3 FreeBSD-SA-14:01.bsnmpd
FreeBSD-SA-14:02.ntpd
FreeBSD-SA-14:04.bind
diff --git a/crypto/openssl/crypto/bn/bn.h b/crypto/openssl/crypto/bn/bn.h
index f1719a5877f7..688a4e7e86fb 100644
--- a/crypto/openssl/crypto/bn/bn.h
+++ b/crypto/openssl/crypto/bn/bn.h
@@ -511,6 +511,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,
@@ -740,11 +742,20 @@ int RAND_pseudo_bytes(unsigned char *buf,int num);
#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
diff --git a/crypto/openssl/crypto/bn/bn_lib.c b/crypto/openssl/crypto/bn/bn_lib.c
index 32a8fbaf51ee..b66f50752b6c 100644
--- a/crypto/openssl/crypto/bn/bn_lib.c
+++ b/crypto/openssl/crypto/bn/bn_lib.c
@@ -824,3 +824,55 @@ int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b,
}
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
+}
diff --git a/crypto/openssl/crypto/ec/ec2_mult.c b/crypto/openssl/crypto/ec/ec2_mult.c
index 7dca5e4bcd43..6b570a3f9173 100644
--- a/crypto/openssl/crypto/ec/ec2_mult.c
+++ b/crypto/openssl/crypto/ec/ec2_mult.c
@@ -208,9 +208,12 @@ static int gf2m_Mxy(const EC_GROUP *group, const BIGNUM *x, const BIGNUM *y, BIG
/* Computes scalar*point and stores the result in r.
* point can not equal r.
- * Uses algorithm 2P of
+ * Uses a modified algorithm 2P of
* Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
* GF(2^m) without precomputation".
+ *
+ * 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)
@@ -244,6 +247,11 @@ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r,
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 */
@@ -266,16 +274,12 @@ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r,
{
for (; j >= 0; j--)
{
- if (scalar->d[i] & 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(scalar->d[i] & mask, x1, x2, group->field.top);
+ BN_consttime_swap(scalar->d[i] & 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(scalar->d[i] & mask, x1, x2, group->field.top);
+ BN_consttime_swap(scalar->d[i] & mask, z1, z2, group->field.top);
mask >>= 1;
}
j = BN_BITS2 - 1;
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index 2e7b7f1b67d8..bf468c473010 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -32,7 +32,7 @@
TYPE="FreeBSD"
REVISION="9.2"
-BRANCH="RELEASE-p3"
+BRANCH="RELEASE-p4"
if [ "X${BRANCH_OVERRIDE}" != "X" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index 307b1f6cc5a3..bf2d7ed77e7b 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -1457,10 +1457,23 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
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, int isdgram,
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, int isdgram,
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, int isdgram,
}
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, int isdgram,
/*
* 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,