From: Bruno Haible Date: Sun, 24 Jun 2018 22:41:03 +0000 (+0200) Subject: af_alg: Fix state of stream after sendfile() succeeds. X-Git-Tag: v1.0~5546 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=c08a99b5b471b80ad01833a6ca360d3b9cc7e2cb;p=gnulib.git af_alg: Fix state of stream after sendfile() succeeds. * lib/af_alg.c (afalg_stream): Invoke fflush and lseek, to ensure that the stream is correctly positioned afterwards. * modules/crypto/af_alg (Depends-on): Add fflush. * tests/test-digest.h (test_digest_on_files): Verify that after the operation the stream is positioned at end of file. --- diff --git a/ChangeLog b/ChangeLog index 3890bcadca..33da642c3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2018-06-24 Bruno Haible + + af_alg: Fix state of stream after sendfile() succeeds. + * lib/af_alg.c (afalg_stream): Invoke fflush and lseek, to ensure that + the stream is correctly positioned afterwards. + * modules/crypto/af_alg (Depends-on): Add fflush. + * tests/test-digest.h (test_digest_on_files): Verify that after the + operation the stream is positioned at end of file. + 2018-06-24 Jim Meyering canon-host: take GCC9's advice rather than ignoring warning diff --git a/lib/af_alg.c b/lib/af_alg.c index 555eb2be6b..2753ab9a42 100644 --- a/lib/af_alg.c +++ b/lib/af_alg.c @@ -113,18 +113,47 @@ afalg_stream (FILE *stream, const char *alg, int fd = fileno (stream); int result; struct stat st; - off_t nseek = 0; /* Number of bytes to seek (backwards) in case of error. */ off_t off = ftello (stream); if (0 <= off && fstat (fd, &st) == 0 && (S_ISREG (st.st_mode) || S_TYPEISSHM (&st) || S_TYPEISTMO (&st)) && off < st.st_size && st.st_size - off < SYS_BUFSIZE_MAX) { - off_t nbytes = st.st_size - off; - result = sendfile (ofd, fd, &off, nbytes) == nbytes ? 0 : -EAFNOSUPPORT; + /* 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)) + result = -EIO; + else + { + off_t nbytes = st.st_size - off; + if (sendfile (ofd, fd, &off, nbytes) == nbytes) + { + if (read (ofd, resblock, hashlen) == hashlen) + { + /* The input buffers of stream are no longer valid. */ + if (lseek (fd, off, SEEK_SET) != (off_t)-1) + result = 0; + else + /* The file position of fd has not changed. */ + result = -EAFNOSUPPORT; + } + else + /* The file position of fd has not changed. */ + result = -EAFNOSUPPORT; + } + else + /* The file position of fd has not changed. */ + result = -EAFNOSUPPORT; + } } else { /* sendfile not possible, do a classic read-write loop. */ + + /* Number of bytes to seek (backwards) in case of error. */ + off_t nseek = 0; + for (;;) { char buf[BLOCKSIZE]; @@ -154,14 +183,14 @@ afalg_stream (FILE *stream, const char *alg, break; } } - } - if (result == 0 && read (ofd, resblock, hashlen) != hashlen) - { - if (nseek == 0 || fseeko (stream, nseek, SEEK_CUR) == 0) - result = -EAFNOSUPPORT; - else - result = -EIO; + if (result == 0 && read (ofd, resblock, hashlen) != hashlen) + { + if (nseek == 0 || fseeko (stream, nseek, SEEK_CUR) == 0) + result = -EAFNOSUPPORT; + else + result = -EIO; + } } close (ofd); return result; diff --git a/modules/crypto/af_alg b/modules/crypto/af_alg index 2ad25febbf..95273d495f 100644 --- a/modules/crypto/af_alg +++ b/modules/crypto/af_alg @@ -9,6 +9,7 @@ m4/af_alg.m4 Depends-on: c99 [test $USE_AF_ALG = 1] +fflush [test $USE_AF_ALG = 1] fseeko [test $USE_AF_ALG = 1] ftello [test $USE_AF_ALG = 1] sys_socket diff --git a/tests/test-digest.h b/tests/test-digest.h index 369ef9f6a8..c58d3dad87 100644 --- a/tests/test-digest.h +++ b/tests/test-digest.h @@ -129,6 +129,12 @@ test_digest_on_files (int (*streamfunc) (FILE *, void *), fprintf (stderr, "\n"); exit (1); } + /* Verify that fp is now positioned at end of file. */ + if (getc (fp) != EOF) + { + fprintf (stderr, "%s left the stream not at EOF\n", streamfunc_name); + exit (1); + } fclose (fp); free (digest - 1); }