GMP's mpn_mul_n must never take overlapping source and destination buffers as the implementation makes a few passes over source while updating destination at each pass:
``` https://gmplib.org/manual/Low_002dlevel-Functions.html#Low_002dlevel-Functio...
Function: void mpn_mul_n (mp_limb_t *rp, const mp_limb_t *s1p, const mp_limb_t *s2p, mp_size_t n)
Multiply {s1p, n} and {s2p, n}, and write the 2*n-limb result to rp.
The destination has to have space for 2*n limbs, even if the product’s most significant limb is zero. No overlap is permitted between the destination and either source. ```
Violation of this invariant make nettle to compute curve25519 incorrectly at least on sparc and hppa architectures, see https://bugs.gentoo.org/613418 for some details.
The overlap happens in `ecc-add-eh.c` where layout of local GMP variables on scratch space is the following:
``` |x1|y1|z1|........|B| |x3|y3|z3|... ```
x1/x3, y1/y3, z1/z3 pairs share the same memory region.
Overlap happens at a call of ``` ecc_modp_mul (ecc, y3, B, z1); ``` which is basically ``` mpn_mul_n (y3, B, z1, m->size), ```
Note how y3 overwrites z1. This is scary type of aliasing.
The bug manifested in testsuite failure in nettle and gnutls. I've trailed the bug down to faulty function by adding printf() and comparing exact output of scratch space on x86 versus sparc.
`mpn_mul_n` on the same source numbers produces different results.
This change does not fix the underlying overlap but exposes the problem on all architectures and crashes the testsuitewith asset().
Reported-by: Matt Turner Bug: https://bugs.gentoo.org/613418 Signed-off-by: Sergei Trofimovich slyfox@gentoo.org --- ecc-mod-arith.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/ecc-mod-arith.c b/ecc-mod-arith.c index f2e47f67..735b1238 100644 --- a/ecc-mod-arith.c +++ b/ecc-mod-arith.c @@ -109,11 +109,23 @@ ecc_mod_submul_1 (const struct ecc_modulo *m, mp_limb_t *rp, assert (hi == 0); }
+static int no_overlap(const mp_limb_t * a, size_t la, + const mp_limb_t * b, size_t lb) +{ + if (a < b) + return (size_t)(b - a) >= la; + /* a >= b */ + return (size_t)(a - b) >= lb; +} + /* NOTE: mul and sqr needs 2*m->size limbs at rp */ void ecc_mod_mul (const struct ecc_modulo *m, mp_limb_t *rp, const mp_limb_t *ap, const mp_limb_t *bp) { + /* NOTE: mpn_mul_n does not work correctly when source and destination overlap */ + assert (no_overlap (rp, 2 * m->size, ap, m->size)); + assert (no_overlap (rp, 2 * m->size, bp, m->size)); mpn_mul_n (rp, ap, bp, m->size); m->reduce (m, rp); }
On Sun, 16 Jul 2017 18:18:34 +0100 Sergei Trofimovich slyfox@gentoo.org wrote:
GMP's mpn_mul_n must never take overlapping source and destination buffers as the implementation makes a few passes over source while updating destination at each pass:
https://gmplib.org/manual/Low_002dlevel-Functions.html#Low_002dlevel-Functions Function: void mpn_mul_n (mp_limb_t *rp, const mp_limb_t *s1p, const mp_limb_t *s2p, mp_size_t n) Multiply {s1p, n} and {s2p, n}, and write the 2*n-limb result to rp. The destination has to have space for 2*n limbs, even if the product’s most significant limb is zero. No overlap is permitted between the destination and either source.
Violation of this invariant make nettle to compute curve25519 incorrectly at least on sparc and hppa architectures, see https://bugs.gentoo.org/613418 for some details.
The overlap happens in `ecc-add-eh.c` where layout of local GMP variables on scratch space is the following:
|x1|y1|z1|........|B| |x3|y3|z3|...
x1/x3, y1/y3, z1/z3 pairs share the same memory region.
Overlap happens at a call of
ecc_modp_mul (ecc, y3, B, z1);
which is basically
mpn_mul_n (y3, B, z1, m->size),
Note how y3 overwrites z1. This is scary type of aliasing.
The bug manifested in testsuite failure in nettle and gnutls. I've trailed the bug down to faulty function by adding printf() and comparing exact output of scratch space on x86 versus sparc.
`mpn_mul_n` on the same source numbers produces different results.
This change does not fix the underlying overlap but exposes the problem on all architectures and crashes the testsuitewith asset().
Reported-by: Matt Turner Bug: https://bugs.gentoo.org/613418 Signed-off-by: Sergei Trofimovich slyfox@gentoo.org
ecc-mod-arith.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/ecc-mod-arith.c b/ecc-mod-arith.c index f2e47f67..735b1238 100644 --- a/ecc-mod-arith.c +++ b/ecc-mod-arith.c @@ -109,11 +109,23 @@ ecc_mod_submul_1 (const struct ecc_modulo *m, mp_limb_t *rp, assert (hi == 0); }
+static int no_overlap(const mp_limb_t * a, size_t la,
const mp_limb_t * b, size_t lb)
+{
- if (a < b)
- return (size_t)(b - a) >= la;
- /* a >= b */
- return (size_t)(a - b) >= lb;
+}
/* NOTE: mul and sqr needs 2*m->size limbs at rp */ void ecc_mod_mul (const struct ecc_modulo *m, mp_limb_t *rp, const mp_limb_t *ap, const mp_limb_t *bp) {
- /* NOTE: mpn_mul_n does not work correctly when source and destination overlap */
- assert (no_overlap (rp, 2 * m->size, ap, m->size));
- assert (no_overlap (rp, 2 * m->size, bp, m->size)); mpn_mul_n (rp, ap, bp, m->size); m->reduce (m, rp);
}
2.13.3
Attaching a proof-of-concept patch nettle-3.3-noclobber.patch which fixes tests on sparc.
I don't expect it to be applied upstream as it adds another memory allocation/free to a low-level operation but it's a good workaround to make sure it was the only problem blocking sparc.
Thanks!
Sergei Trofimovich slyfox@gentoo.org writes:
Attaching a proof-of-concept patch nettle-3.3-noclobber.patch which fixes tests on sparc.
Can you try the below patch, which reorders the multiplies, with no change to allocation?
Regards, /Niels
diff --git a/ecc-add-eh.c b/ecc-add-eh.c index a16be4c..c07ff49 100644 --- a/ecc-add-eh.c +++ b/ecc-add-eh.c @@ -98,8 +98,8 @@ ecc_add_eh (const struct ecc_curve *ecc, ecc_modp_mul (ecc, x3, B, z1);
/* y3 */ - ecc_modp_mul (ecc, B, F, C); /* ! */ - ecc_modp_mul (ecc, y3, B, z1); + ecc_modp_mul (ecc, B, F, z1); /* ! */ + ecc_modp_mul (ecc, y3, B, C); /* Clobbers z1 in case r == p. */
/* z3 */ ecc_modp_mul (ecc, B, F, G);
On Tue, 18 Jul 2017 20:33:54 +0200 nisse@lysator.liu.se (Niels Möller) wrote:
Sergei Trofimovich slyfox@gentoo.org writes:
Attaching a proof-of-concept patch nettle-3.3-noclobber.patch which fixes tests on sparc.
Can you try the below patch, which reorders the multiplies, with no change to allocation?
This patch also works. Thank you!
Regards, /Niels
diff --git a/ecc-add-eh.c b/ecc-add-eh.c index a16be4c..c07ff49 100644 --- a/ecc-add-eh.c +++ b/ecc-add-eh.c @@ -98,8 +98,8 @@ ecc_add_eh (const struct ecc_curve *ecc, ecc_modp_mul (ecc, x3, B, z1);
/* y3 */
- ecc_modp_mul (ecc, B, F, C); /* ! */
- ecc_modp_mul (ecc, y3, B, z1);
ecc_modp_mul (ecc, B, F, z1); /* ! */
ecc_modp_mul (ecc, y3, B, C); /* Clobbers z1 in case r == p. */
/* z3 */ ecc_modp_mul (ecc, B, F, G);
-- Niels Möller. PGP-encrypted email is preferred. Keyid 368C6677. Internet email is subject to wholesale government surveillance.
Sergei Trofimovich slyfox@gentoo.org writes:
Can you try the below patch, which reorders the multiplies, with no change to allocation?
This patch also works. Thank you!
Good. Already committed to the repository.
Regards, /Niels
Sergei Trofimovich slyfox@gentoo.org writes:
Overlap happens at a call of
ecc_modp_mul (ecc, y3, B, z1);
which is basically
mpn_mul_n (y3, B, z1, m->size),
I'm adding asserts to these functions, and then I can easily reproduce.
I think linking with a gmp configured with --enable-assert should be enough to catch the problem in a platform-independent way?
Nikos, is it easy to add that gmp config to one of the gitlab ci jobs? Alternatively, we could add the no-overlap asserts to mini-gmp, to catch it in mini-gmp builds.
/* NOTE: mul and sqr needs 2*m->size limbs at rp */ void ecc_mod_mul (const struct ecc_modulo *m, mp_limb_t *rp, const mp_limb_t *ap, const mp_limb_t *bp) {
- /* NOTE: mpn_mul_n does not work correctly when source and destination overlap */
- assert (no_overlap (rp, 2 * m->size, ap, m->size));
- assert (no_overlap (rp, 2 * m->size, bp, m->size)); mpn_mul_n (rp, ap, bp, m->size); m->reduce (m, rp);
}
As you observed, this function doesn't allow in-place operation. It's less clear what the interface of the ecc_add_* and ecc_dup_* functions is. It needs to be determined if they should or shouldn't allow in-place operation, and if not, back that up with asserts.
Thanks for the bug report, /Niels
On Tue, Jul 18, 2017 at 4:57 PM, Niels Möller nisse@lysator.liu.se wrote:
Sergei Trofimovich slyfox@gentoo.org writes:
Overlap happens at a call of
ecc_modp_mul (ecc, y3, B, z1);
which is basically
mpn_mul_n (y3, B, z1, m->size),
I'm adding asserts to these functions, and then I can easily reproduce.
I think linking with a gmp configured with --enable-assert should be enough to catch the problem in a platform-independent way?
Nikos, is it easy to add that gmp config to one of the gitlab ci jobs? Alternatively, we could add the no-overlap asserts to mini-gmp, to catch it in mini-gmp builds.
Hi, I am using the mini-gmp build in gitlab due to some limitations of memory sanitizer with gmp. Thus, if the bundled version has these asserts it should result to an error.
regards, Nikos
nettle-bugs@lists.lysator.liu.se