Your message dated Sat, 15 Aug 2015 18:47:06 +0000
with message-id <e1zqgty-00074j...@franck.debian.org>
and subject line Bug#788704: fixed in gnutls28 3.3.8-6+deb8u3
has caused the Debian Bug report #788704,
regarding gnutls28: VIA PadLock accelerated AES-CBC segfaults
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact ow...@bugs.debian.org
immediately.)


-- 
788704: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=788704
Debian Bug Tracking System
Contact ow...@bugs.debian.org with problems
--- Begin Message ---
Source: gnutls28
Version: 3.3.8-6+deb8u1
Severity: normal
Tags: patch

Dear Maintainer,

After upgrading a server with a VIA C3 (Nehemiah) processor to jessie,
exim4 started to crash on pretty much every connection that negotiated
AES-128-CBC or AES-256-CBC on TLS:

> 2015-05-31T16:06:43.641909+02:00 info kernel: [ 3466.879332] exim4[2381]: 
> segfault at 4aeb2453 ip b6a4a5e2 sp bf7bfde0 error 4 in 
> libgnutls-deb0.so.28.41.0[b6996000+13a000]

There's nothing in the exim4 log; it crashes before anything is logged.

The problem is not limited to exim4: I could reproduce the crash with
gnutls-cli. This is also how I discovered AES-CBC was to blame. It turns
out that lib/accelerated/x86/elf/e_padlock-x86.s segfaults in the
function padlock_cbc_encrypt() because it has not been written to handle
the case where it is requested to encrypt 0 bytes of data; it expects a
strictly positive number. Yet, it is called with a length of 0. The
function overwrites 512 bytes on the top of its stack, and then
dereferences a pointer in the overwritten data.

The attached patch simply checks for a 0 length in the C functions that
call the handwritten assembly PadLock AES encryption routines, so the
call is avoided. The patch fixed the issue on my system.

All the functions padlock_{ecb,cbc,cfb,ofb,ctr32}_encrypt() share almost
all their code. The AES-CGM ciphers in GnuTLS don't seem to call the
function with a 0 length, but my patch also checks for 0 in that cipher
mode on the basis "once bitten, twice shy".

The rest of the mail is a detailed description of the problem with
length 0.

I don't include a "steps to reproduce this" because it's likely you
don't have access to a system with a VIA PadLock engine. But it's
trivial to reproduce with gnutls-cli and an SMTP server to connect to.

To my surprise, e_padlock-x86.s is a generated file[4]; the source is
not included with GnuTLS. The source is the file
engines/asm/e_padlock-x86.pl in openssl; from the Git repository for
GnuTLS version 3.3.8, it can be concluded that the source is commit
34ccd24 in the OpenSSL Git.

First, a small aside on return values. OpenSSL checks the return value
(an int) of padlock_cbc_encrypt(), and indeed the function can abort if
the struct padlock_cipher_data is not aligned on a 16-byte boundary, or
if len is not a multiple of 16 (AES block size). But there's something
odd: /if/ the function aborts, the return value (EAX) is not set; it is
kept at the value it was when the function was called. On a succesful
return, it's set to 1.

GnuTLS never checks the return value. If it is possible that the length
is not a multiple of 16, GnuTLS will not notice that the
padlock_cbc_encrypt() call did nothing (unless it does some checks on
the data later).

I analysed the behaviour of padlock_cbc_encrypt() with GDB.

During my debugging, the input and output data were never aligned on a
16-byte boundary. padlock_cbc_encrypt() checks for this because not all
VIA processors can cope with this, or only at a tremendous speed
penalty. To fix the alignment, an aligned block of room is allocated on
the stack, and the data is copied there, encrypted in place, and copied to
the destination.

This part of the program is the problematic part:

File openssl/engines/asm/e_padlock-x86.pl, line 204:
----------------------- 8< ------------------ >8 -----------------------
204:    &cmp    ($len,$chunk);
205:    &cmovc  ($chunk,$len);          # 
chunk=len>PADLOCK_CHUNK?PADLOCK_CHUNK:len
206:    &and    ("eax",$chunk);         # out_misaligned?chunk:0
207:    &mov    ($chunk,$len);
208:    &neg    ("eax");
209:    &and    ($chunk,$PADLOCK_CHUNK-1);      # chunk=len%PADLOCK_CHUNK
210:    &lea    ("esp",&DWP(0,"eax","ebp"));    # alloca
211:    &mov    ("eax",$PADLOCK_CHUNK);
212:    &cmovz  ($chunk,"eax");                 # chunk=chunk?:PADLOCK_CHUNK
----------------------- 8< ------------------ >8 -----------------------
[1]

At the start, EAX is all ones (binary), signifying the output is not
aligned on a 16-byte boundary.  Room is allocated on the stack for the
data in line 210. Either `len` bytes or PADLOCK_CHUNK (512), whichever
is less.

The purpose of `chunk` is to take up to PADLOCK_CHUNK bytes from
`len` to process. If `len` is not a multiple of 512, the remainder is
processed first. After the remainder is processed, either a multiple of
PADLOCK_CHUNK still needs to be processed, or we're done.

To this end, it ANDs `len` with 511 in line 209. If `len` is a multiple
of 512, the result is zero, so a full PADLOCK_CHUNK is processed (line
212).

But if `len` was already zero to begin with, this test produces the
wrong result, and results in `chunk` also being set to 512, to process
512 bytes of data.

The confusion comes now. The code has just set aside 0 bytes on the
stack for copying data. Then it copies 512 bytes of data from the input
pointer to the stack (in line 265 of the source[2]), thereby overwriting
the other information it is keeping on the stack. For good measure, this
is then encrypted as well :). And here is where the SIGSEGV occurs:

File openssl/engines/asm/e_padlock-x86.pl, line 279:
----------------------- 8< ------------------ >8 -----------------------
279:    &mov    ($out,&DWP(0,"ebp"));           # restore parameters
280:    &mov    ($chunk,&DWP(12,"ebp"));
[...]
292:    &test   ($out,0x0f);
293:    &jz     (&label("${mode}_out_aligned"));
294:    &mov    ($len,$chunk);
295:    &lea    ($inp,&DWP(0,"esp"));
296:    &shr    ($len,2);
297:    &data_byte(0xf3,0xa5);                  # rep movsl
----------------------- 8< ------------------ >8 -----------------------
[3]

`out` and `chunk` are loaded with bogus data; it is from the part of
the stack that was overwritten and subsequently encrypted. In line 297,
the 'rep movsl' copies `len` = `chunk` bytes of data from the stack to the
address `out`, but `chunk` and `out` are both garbage, resulting in a
segmentation fault.

That concludes my analysis.

With regards,

Peter.

-- System Information:
Debian Release: 8.1
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: i386 (i686)

Kernel: Linux 3.16.0-4-586
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

$ cat /proc/cpuinfo
processor       : 0
vendor_id       : CentaurHauls
cpu family      : 6
model           : 9
model name      : VIA Nehemiah
stepping        : 10
cpu MHz         : 999.583
cache size      : 64 KB
fdiv_bug        : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 1
wp              : yes
flags           : fpu vme de pse tsc msr cx8 sep mtrr pge cmov pat mmx
fxsr sse rng rng_en ace ace_en
bogomips        : 1999.16
clflush size    : 32
cache_alignment : 32
address sizes   : 32 bits physical, 32 bits virtual
power management:

[1] 
https://git.openssl.org/?p=openssl.git;a=blob;f=engines/asm/e_padlock-x86.pl;h=4148468c41de695751e8731369a948dff171c1ca;hb=34ccd24d0e6#l204

[2] 
https://git.openssl.org/?p=openssl.git;a=blob;f=engines/asm/e_padlock-x86.pl;h=4148468c41de695751e8731369a948dff171c1ca;hb=34ccd24d0e6#l265

[3] 
https://git.openssl.org/?p=openssl.git;a=blob;f=engines/asm/e_padlock-x86.pl;h=4148468c41de695751e8731369a948dff171c1ca;hb=34ccd24d0e6#l279

[4] In my opinion, this is not in the spirit of the stipulation "the
preferred form of the work for making modifications to it" of the (L)GPL
license GnuTLS is released under. For one thing, all comments explaining
the code are not in the generated output.

-- 
I use the GNU Privacy Guard (GnuPG) in combination with Enigmail.
You can send me encrypted mail if you want some privacy.
My key is available at <http://digitalbrains.com/2012/openpgp-key-peter>
--- gnutls28-3.3.8.orig/lib/accelerated/x86/aes-gcm-padlock.c
+++ gnutls28-3.3.8/lib/accelerated/x86/aes-gcm-padlock.c
@@ -52,6 +52,9 @@ static void padlock_aes_encrypt(void *_c
        struct padlock_ctx *ctx = _ctx;
        struct padlock_cipher_data *pce;
 
+       if (length == 0)
+               return;
+
        pce = ALIGN16(&ctx->expanded_key);
 
        padlock_ecb_encrypt(dst, src, pce, length);
--- gnutls28-3.3.8.orig/lib/accelerated/x86/aes-padlock.c
+++ gnutls28-3.3.8/lib/accelerated/x86/aes-padlock.c
@@ -130,6 +130,9 @@ padlock_aes_cbc_encrypt(void *_ctx, cons
        struct padlock_ctx *ctx = _ctx;
        struct padlock_cipher_data *pce;
 
+       if (src_size == 0)
+               return 0;
+
        pce = ALIGN16(&ctx->expanded_key);
 
        padlock_cbc_encrypt(dst, src, pce, src_size);
@@ -145,6 +148,9 @@ padlock_aes_cbc_decrypt(void *_ctx, cons
        struct padlock_ctx *ctx = _ctx;
        struct padlock_cipher_data *pcd;
 
+       if (src_size == 0)
+               return 0;
+
        pcd = ALIGN16(&ctx->expanded_key);
 
        padlock_cbc_encrypt(dst, src, pcd, src_size);

--- End Message ---
--- Begin Message ---
Source: gnutls28
Source-Version: 3.3.8-6+deb8u3

We believe that the bug you reported is fixed in the latest version of
gnutls28, which is due to be installed in the Debian FTP archive.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to 788...@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Andreas Metzler <ametz...@debian.org> (supplier of updated gnutls28 package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmas...@ftp-master.debian.org)


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Format: 1.8
Date: Fri, 14 Aug 2015 18:28:30 +0200
Source: gnutls28
Binary: libgnutls28-dev libgnutls-deb0-28 libgnutls28-dbg gnutls-bin gnutls-doc 
guile-gnutls libgnutlsxx28 libgnutls-openssl27
Architecture: all source
Version: 3.3.8-6+deb8u3
Distribution: jessie
Urgency: medium
Maintainer: Debian GnuTLS Maintainers <pkg-gnutls-ma...@lists.alioth.debian.org>
Changed-By: Andreas Metzler <ametz...@debian.org>
Closes: 788704
Description: 
 gnutls-bin - GNU TLS library - commandline utilities
 gnutls-doc - GNU TLS library - documentation and examples
 guile-gnutls - GNU TLS library - GNU Guile bindings
 libgnutls28-dbg - GNU TLS library - debugger symbols
 libgnutls28-dev - GNU TLS library - development files
 libgnutls-deb0-28 - GNU TLS library - main runtime library
 libgnutls-openssl27 - GNU TLS library - OpenSSL wrapper
 libgnutlsxx28 - GNU TLS library - C++ runtime library
Changes:
 gnutls28 (3.3.8-6+deb8u3) jessie; urgency=medium
 .
   * Pull 50_Handle-zero-length-plaintext-for-VIA-PadLock-functio.patch from
     upstream version 3.3.12 to fix a crash in VIA PadLock asm. (Thanks, Peter
     Lebbing). Closes: #788704
   * Pull 51_0001__gnutls_session_sign_algo_enabled-do-not-consider-an.patch
     51_0002_before-falling-back-to-SHA1-as-signature-algorithm-i.patch
     51_0003_tests-added-reproducer-for-the-MD5-acceptance-issue.patch (the
     latter unfuzzed) from GnuTLS 3.3.15 to fix GNUTLS-SA-2015-2. - A
     ServerKeyExchange signature sent by the server was not verified to be in
     the acceptable by the client set of algorithms. That had the effect of
     allowing MD5 signatures (which are disabled by default) in the
     ServerKeyExchange message.
Checksums-Sha1: 
 3c40d629052a6ae6030b7cd0b1fb1ffa56f35c9e 2941 gnutls28_3.3.8-6+deb8u3.dsc
 2e4b9aba3af221807bf33eb87bf0085c4959d980 95104 
gnutls28_3.3.8-6+deb8u3.debian.tar.xz
 ce72f27c1d0cbd51668d2b87e4d762efbb77e5a3 3626674 
gnutls-doc_3.3.8-6+deb8u3_all.deb
Checksums-Sha256: 
 5c1cd78b2eb4547377ef5c0894de48945265251dbdca2303526cef894e77e46d 2941 
gnutls28_3.3.8-6+deb8u3.dsc
 fe56f1f7a79b855577a5539202408e91a5a7a57095751550d983368cc0c08f8d 95104 
gnutls28_3.3.8-6+deb8u3.debian.tar.xz
 4237df1548470db035c271b47a2897b3915d4e39e3cd430e89e1c5f1037dc38a 3626674 
gnutls-doc_3.3.8-6+deb8u3_all.deb
Files: 
 8ad07147cab2bc286141c0ffe3fbb85d 2941 libs optional gnutls28_3.3.8-6+deb8u3.dsc
 0e8fbda2f8b264a4eb0c8cf9c809466a 95104 libs optional 
gnutls28_3.3.8-6+deb8u3.debian.tar.xz
 aca4e24bb39775418512e8e20aa3295d 3626674 doc optional 
gnutls-doc_3.3.8-6+deb8u3_all.deb

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBCgAGBQJVz0YIAAoJEKVPAYVDghSELZ0QAIU849YPi7KmShrfHQXtwn8u
BHniyHxYFJVXiY/NzOi0++o46mNmvB8eoYXV3oxIIbFa2hVlEnGmZCUmTblDdFMf
oI0OiK2fZSfnILoYN+Zhrx4y0ZeO3J7ZGb/b2SUc5KyYv34n6Oj12TCH8O1ZL4tm
6D7syrTrG86uXWr20kgfScLq0Vrm/gyKkopuJ35UjkVK5/Yz4G9LusyP0XbB/U6q
dFaJhUYw65hpggNJscPJOiFn07akaGM8nmzCBLDU9Iq2UgEIeSwlBwv4HMnFbqJ1
Wl4C+m8JqOpAgH0SiWXc40CeLg/6JVQTz8CNSOpkn1dopTK8SdzF5jL3yGZpZ38B
GkXddtZaOFF8AnDe+ztmj5WiYiWLCMGkZkTJAQWc4qfM93s6vvtI1uyPy666iHeR
19YfM2wgEfXqJaaYzydbDmliGLrVRjajzHIWSVNHz2I85tWb8nrkjKDjO8Vv0DcZ
jGd9/bZ66VTR+nceSa+2iVb2BNYBkhgGv7cGeQsAkWHxjPwUGFxB7iZ0lZngRqsM
UysdAF0Yp7W8ed8aeI7m7SpBigtHroHYWdwow1xDK0tegXlFjN5N5h+IoDWwuCSk
dA5+mn3FVsotWHi0NGgIKuuLlz1JoQnRBubL7mDR3sC/hZbjvQBkh38ZrP4EWq+B
zxH1gH4si0Nle1neN7jv
=HsqL
-----END PGP SIGNATURE-----

--- End Message ---

Reply via email to