2018-05-06 Bruno Haible <bruno@clisp.org>
+ 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.
#include <unistd.h>
#include <string.h>
+#include <stdio.h>
+#include <errno.h>
#include <linux/if_alg.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
}
/* 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 <https://patchwork.kernel.org/patch/9434741/>. */
+ if (nbytes <= 0)
+ {
+ ret = -EAFNOSUPPORT;
+ goto out_ofd;
+ }
+ if (sendfile (ofd, fd, NULL, nbytes) != nbytes)
{
ret = -EIO;
goto out_ofd;
# 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:
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;
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);
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);
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);
m4/af_alg.m4
Depends-on:
+fflush [test $USE_AF_ALG = 1]
+lseek [test $USE_AF_ALG = 1]
sys_socket
sys_stat