From: Bruno Haible Date: Sun, 6 May 2018 11:30:24 +0000 (+0200) Subject: af_alg: Fix bug with streams that are not at position 0. X-Git-Tag: v1.0~5642 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=22d459bb708adc2651f47e6ad877e4848c5319bd;p=gnulib.git af_alg: Fix bug with streams that are not at position 0. * lib/af_alg.c (afalg_stream): Before sendfile, invoke fflush. Don't assume that the stream is positioned at position 0. * lib/af_alg.h (afalg_stream): Mention restriction regarding the state of the stream. * lib/md5.h (md5_stream): Likewise. * lib/sha1.h (sha1_stream): Likewise. * lib/sha256.h (sha256_stream, sha224_stream): Likewise. * lib/sha512.h (sha512_stream, sha384_stream): Likewise. * modules/crypto/af_alg (Depends-on): Add fflush, lseek. --- diff --git a/ChangeLog b/ChangeLog index 49624ecfb2..20e13168e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2018-05-06 Bruno Haible + af_alg: Fix bug with streams that are not at position 0. + * lib/af_alg.c (afalg_stream): Before sendfile, invoke fflush. Don't + assume that the stream is positioned at position 0. + * lib/af_alg.h (afalg_stream): Mention restriction regarding the state + of the stream. + * lib/md5.h (md5_stream): Likewise. + * lib/sha1.h (sha1_stream): Likewise. + * lib/sha256.h (sha256_stream, sha224_stream): Likewise. + * lib/sha512.h (sha512_stream, sha384_stream): Likewise. + * modules/crypto/af_alg (Depends-on): Add fflush, lseek. + crypto/{md5,sha1,sha256,sha512} tests: Enhance test. * tests/test-digest.h (test_digest_on_files): Add a test with a FILE stream that is not positioned at the beginning. diff --git a/lib/af_alg.c b/lib/af_alg.c index 97bdff516b..79e219586e 100644 --- a/lib/af_alg.c +++ b/lib/af_alg.c @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include #include @@ -65,12 +67,35 @@ afalg_stream (FILE *stream, const char *alg, void *resblock, ssize_t hashlen) } /* if file is a regular file, attempt sendfile to pipe the data. */ + int fd = fileno (stream); struct stat st; - if (fstat (fileno (stream), &st) == 0 + if (fstat (fd, &st) == 0 && (S_ISREG (st.st_mode) || S_TYPEISSHM (&st) || S_TYPEISTMO (&st)) && 0 < st.st_size && st.st_size <= SYS_BUFSIZE_MAX) { - if (sendfile (ofd, fileno (stream), NULL, st.st_size) != st.st_size) + /* Make sure the offset of fileno (stream) reflects how many bytes + have been read from stream before this function got invoked. + Note: fflush on an input stream after ungetc does not work as expected + on some platforms. Therefore this situation is not supported here. */ + if (fflush (stream)) + { +#if defined _WIN32 && ! defined __CYGWIN__ + ret = -EIO; +#else + ret = -errno; +#endif + goto out_cfd; + } + + off_t nbytes = st.st_size - lseek (fd, 0, SEEK_CUR); + /* On Linux < 4.9, the value for an empty stream is wrong (all zeroes). + See . */ + if (nbytes <= 0) + { + ret = -EAFNOSUPPORT; + goto out_ofd; + } + if (sendfile (ofd, fd, NULL, nbytes) != nbytes) { ret = -EIO; goto out_ofd; diff --git a/lib/af_alg.h b/lib/af_alg.h index a15a956513..dfcc995964 100644 --- a/lib/af_alg.h +++ b/lib/af_alg.h @@ -38,8 +38,13 @@ extern "C" { # if USE_LINUX_CRYPTO_API /* Compute a message digest of the contents of a file. + STREAM is an open file stream. Regular files are handled more efficiently. + The contents of STREAM from its current position to its end will be read. + The case that the last operation on STREAM was an 'ungetc' is not supported. + ALG is the message digest algorithm; see the file /proc/crypto. + RESBLOCK points to a block of HASHLEN bytes, for the result. HASHLEN must be the length of the message digest, in bytes, in particular: diff --git a/lib/md5.h b/lib/md5.h index d5d3c0167f..47dc7d41b0 100644 --- a/lib/md5.h +++ b/lib/md5.h @@ -122,8 +122,11 @@ extern void *__md5_buffer (const char *buffer, size_t len, void *resblock) __THROW; # endif -/* Compute MD5 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 16 bytes +/* Compute MD5 message digest for bytes read from STREAM. + STREAM is an open file stream. Regular files are handled more efficiently. + The contents of STREAM from its current position to its end will be read. + The case that the last operation on STREAM was an 'ungetc' is not supported. + The resulting message digest number will be written into the 16 bytes beginning at RESBLOCK. */ extern int __md5_stream (FILE *stream, void *resblock) __THROW; diff --git a/lib/sha1.h b/lib/sha1.h index e41ce4bfee..cca83fc91a 100644 --- a/lib/sha1.h +++ b/lib/sha1.h @@ -87,8 +87,11 @@ extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); extern void *sha1_buffer (const char *buffer, size_t len, void *resblock); # endif -/* Compute SHA1 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 20 bytes +/* Compute SHA1 message digest for bytes read from STREAM. + STREAM is an open file stream. Regular files are handled more efficiently. + The contents of STREAM from its current position to its end will be read. + The case that the last operation on STREAM was an 'ungetc' is not supported. + The resulting message digest number will be written into the 20 bytes beginning at RESBLOCK. */ extern int sha1_stream (FILE *stream, void *resblock); diff --git a/lib/sha256.h b/lib/sha256.h index e3449864bb..19ed3ccd4d 100644 --- a/lib/sha256.h +++ b/lib/sha256.h @@ -89,8 +89,11 @@ extern void *sha256_buffer (const char *buffer, size_t len, void *resblock); extern void *sha224_buffer (const char *buffer, size_t len, void *resblock); # endif -/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The - resulting message digest number will be written into the 32 (28) bytes +/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. + STREAM is an open file stream. Regular files are handled more efficiently. + The contents of STREAM from its current position to its end will be read. + The case that the last operation on STREAM was an 'ungetc' is not supported. + The resulting message digest number will be written into the 32 (28) bytes beginning at RESBLOCK. */ extern int sha256_stream (FILE *stream, void *resblock); extern int sha224_stream (FILE *stream, void *resblock); diff --git a/lib/sha512.h b/lib/sha512.h index 6a0aadba02..2c39ab195c 100644 --- a/lib/sha512.h +++ b/lib/sha512.h @@ -92,8 +92,11 @@ extern void *sha512_buffer (const char *buffer, size_t len, void *resblock); extern void *sha384_buffer (const char *buffer, size_t len, void *resblock); # endif -/* Compute SHA512 (SHA384) message digest for bytes read from STREAM. The - resulting message digest number will be written into the 64 (48) bytes +/* Compute SHA512 (SHA384) message digest for bytes read from STREAM. + STREAM is an open file stream. Regular files are handled more efficiently. + The contents of STREAM from its current position to its end will be read. + The case that the last operation on STREAM was an 'ungetc' is not supported. + The resulting message digest number will be written into the 64 (48) bytes beginning at RESBLOCK. */ extern int sha512_stream (FILE *stream, void *resblock); extern int sha384_stream (FILE *stream, void *resblock); diff --git a/modules/crypto/af_alg b/modules/crypto/af_alg index c9602dc3b7..0c498e05c8 100644 --- a/modules/crypto/af_alg +++ b/modules/crypto/af_alg @@ -8,6 +8,8 @@ lib/sys-limits.h m4/af_alg.m4 Depends-on: +fflush [test $USE_AF_ALG = 1] +lseek [test $USE_AF_ALG = 1] sys_socket sys_stat