mirror of
https://sourceware.org/git/glibc.git
synced 2025-01-11 03:40:06 +00:00
Reset cached offset when reading to end of stream (BZ #17653)
POSIX allows applications to switch file handles when a read results in an end of file. Unset the cached offset at this point so that it is queried again.
This commit is contained in:
parent
61b4f792e0
commit
fe8b4d98e9
10
ChangeLog
10
ChangeLog
@ -1,5 +1,15 @@
|
|||||||
2914-12-04 Siddhesh Poyarekar <siddhesh@redhat.com>
|
2914-12-04 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||||
|
|
||||||
|
[BZ #17653]
|
||||||
|
* libio/fileops.c (_IO_new_file_underflow): Unset cached
|
||||||
|
offset on EOF.
|
||||||
|
* libio/wfileops.c (_IO_wfile_underflow): Likewise.
|
||||||
|
* libio/tst-ftell-active-handler.c (fgets_func_t): New type.
|
||||||
|
(fgets_func): Function pointer to fgets and fgetws.
|
||||||
|
(do_ftell_test): Add test to verify ftell value after read
|
||||||
|
EOF.
|
||||||
|
(do_test): Set fgets_func.
|
||||||
|
|
||||||
* libio/tst-ftell-active-handler.c (do_ftruncate_test): Add
|
* libio/tst-ftell-active-handler.c (do_ftruncate_test): Add
|
||||||
O_TRUNC flag for w and w+ modes.
|
O_TRUNC flag for w and w+ modes.
|
||||||
(do_rewind_test): Likewise.
|
(do_rewind_test): Likewise.
|
||||||
|
2
NEWS
2
NEWS
@ -13,7 +13,7 @@ Version 2.21
|
|||||||
16619, 16740, 16857, 17192, 17266, 17344, 17363, 17370, 17371, 17411,
|
16619, 16740, 16857, 17192, 17266, 17344, 17363, 17370, 17371, 17411,
|
||||||
17460, 17475, 17485, 17501, 17506, 17508, 17522, 17555, 17570, 17571,
|
17460, 17475, 17485, 17501, 17506, 17508, 17522, 17555, 17570, 17571,
|
||||||
17572, 17573, 17574, 17581, 17582, 17583, 17584, 17585, 17589, 17594,
|
17572, 17573, 17574, 17581, 17582, 17583, 17584, 17585, 17589, 17594,
|
||||||
17601, 17608, 17616, 17625, 17633, 17647, 17664, 17665, 17668.
|
17601, 17608, 17616, 17625, 17633, 17647, 17653, 17664, 17665, 17668.
|
||||||
|
|
||||||
* CVE-2104-7817 The wordexp function could ignore the WRDE_NOCMD flag
|
* CVE-2104-7817 The wordexp function could ignore the WRDE_NOCMD flag
|
||||||
under certain input conditions resulting in the execution of a shell for
|
under certain input conditions resulting in the execution of a shell for
|
||||||
|
@ -615,7 +615,13 @@ _IO_new_file_underflow (fp)
|
|||||||
}
|
}
|
||||||
fp->_IO_read_end += count;
|
fp->_IO_read_end += count;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return EOF;
|
{
|
||||||
|
/* If a stream is read to EOF, the calling application may switch active
|
||||||
|
handles. As a result, our offset cache would no longer be valid, so
|
||||||
|
unset it. */
|
||||||
|
fp->_offset = _IO_pos_BAD;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
if (fp->_offset != _IO_pos_BAD)
|
if (fp->_offset != _IO_pos_BAD)
|
||||||
_IO_pos_adjust (fp->_offset, count);
|
_IO_pos_adjust (fp->_offset, count);
|
||||||
return *(unsigned char *) fp->_IO_read_ptr;
|
return *(unsigned char *) fp->_IO_read_ptr;
|
||||||
|
@ -86,7 +86,9 @@ static size_t data_len;
|
|||||||
static size_t file_len;
|
static size_t file_len;
|
||||||
|
|
||||||
typedef int (*fputs_func_t) (const void *data, FILE *fp);
|
typedef int (*fputs_func_t) (const void *data, FILE *fp);
|
||||||
|
typedef void *(*fgets_func_t) (void *ws, int n, FILE *fp);
|
||||||
fputs_func_t fputs_func;
|
fputs_func_t fputs_func;
|
||||||
|
fgets_func_t fgets_func;
|
||||||
|
|
||||||
/* This test verifies that the offset reported by ftell is correct after the
|
/* This test verifies that the offset reported by ftell is correct after the
|
||||||
file is truncated using ftruncate. ftruncate does not change the file
|
file is truncated using ftruncate. ftruncate does not change the file
|
||||||
@ -290,20 +292,22 @@ do_ftell_test (const char *filename)
|
|||||||
int fd_mode;
|
int fd_mode;
|
||||||
size_t old_off;
|
size_t old_off;
|
||||||
size_t new_off;
|
size_t new_off;
|
||||||
|
size_t eof_off;
|
||||||
} test_modes[] = {
|
} test_modes[] = {
|
||||||
/* In w, w+ and r+ modes, the file position should be at the
|
/* In w, w+ and r+ modes, the file position should be at the
|
||||||
beginning of the file. After the write, the offset should be
|
beginning of the file. After the write, the offset should be
|
||||||
updated to data_len. */
|
updated to data_len. We don't use eof_off in w and a modes since
|
||||||
{"w", O_WRONLY | O_TRUNC, 0, data_len},
|
they don't allow reading. */
|
||||||
{"w+", O_RDWR | O_TRUNC, 0, data_len},
|
{"w", O_WRONLY | O_TRUNC, 0, data_len, 0},
|
||||||
{"r+", O_RDWR, 0, data_len},
|
{"w+", O_RDWR | O_TRUNC, 0, data_len, 2 * data_len},
|
||||||
|
{"r+", O_RDWR, 0, data_len, 3 * data_len},
|
||||||
/* For the 'a' mode, the initial file position should be the
|
/* For the 'a' mode, the initial file position should be the
|
||||||
current end of file. After the write, the offset has data_len
|
current end of file. After the write, the offset has data_len
|
||||||
added to the old value. For a+ mode however, the initial file
|
added to the old value. For a+ mode however, the initial file
|
||||||
position is the file position of the underlying file descriptor,
|
position is the file position of the underlying file descriptor,
|
||||||
since it is initially assumed to be in read mode. */
|
since it is initially assumed to be in read mode. */
|
||||||
{"a", O_WRONLY, data_len, 2 * data_len},
|
{"a", O_WRONLY, 3 * data_len, 4 * data_len, 5 * data_len},
|
||||||
{"a+", O_RDWR, 0, 3 * data_len},
|
{"a+", O_RDWR, 0, 5 * data_len, 6 * data_len},
|
||||||
};
|
};
|
||||||
for (int j = 0; j < 2; j++)
|
for (int j = 0; j < 2; j++)
|
||||||
{
|
{
|
||||||
@ -348,12 +352,44 @@ do_ftell_test (const char *filename)
|
|||||||
|
|
||||||
if (off != test_modes[i].new_off)
|
if (off != test_modes[i].new_off)
|
||||||
{
|
{
|
||||||
printf ("Incorrect new offset. Expected %zu but got %ld\n",
|
printf ("Incorrect new offset. Expected %zu but got %ld",
|
||||||
test_modes[i].new_off, off);
|
test_modes[i].new_off, off);
|
||||||
ret |= 1;
|
ret |= 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf ("new offset = %ld\n", off);
|
printf ("new offset = %ld", off);
|
||||||
|
|
||||||
|
/* Read to the end, write some data to the fd and check if ftell can
|
||||||
|
see the new ofset. Do this test only for files that allow
|
||||||
|
reading. */
|
||||||
|
if (test_modes[i].fd_mode != O_WRONLY)
|
||||||
|
{
|
||||||
|
char tmpbuf[data_len];
|
||||||
|
|
||||||
|
rewind (fp);
|
||||||
|
|
||||||
|
while (fgets_func (tmpbuf, sizeof (tmpbuf), fp) && !feof (fp));
|
||||||
|
|
||||||
|
write_ret = write (fd, data, data_len);
|
||||||
|
if (write_ret != data_len)
|
||||||
|
{
|
||||||
|
printf ("write failed (%m)\n");
|
||||||
|
ret |= 1;
|
||||||
|
}
|
||||||
|
off = ftell (fp);
|
||||||
|
|
||||||
|
if (off != test_modes[i].eof_off)
|
||||||
|
{
|
||||||
|
printf (", Incorrect offset after read EOF. "
|
||||||
|
"Expected %zu but got %ld\n",
|
||||||
|
test_modes[i].eof_off, off);
|
||||||
|
ret |= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf (", offset after EOF = %ld\n", off);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
putc ('\n', stdout);
|
||||||
|
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
}
|
}
|
||||||
@ -617,6 +653,7 @@ do_test (void)
|
|||||||
/* Tests for regular files. */
|
/* Tests for regular files. */
|
||||||
puts ("Regular mode:");
|
puts ("Regular mode:");
|
||||||
fputs_func = (fputs_func_t) fputs;
|
fputs_func = (fputs_func_t) fputs;
|
||||||
|
fgets_func = (fgets_func_t) fgets;
|
||||||
data = char_data;
|
data = char_data;
|
||||||
data_len = strlen (char_data);
|
data_len = strlen (char_data);
|
||||||
ret |= do_one_test (filename);
|
ret |= do_one_test (filename);
|
||||||
@ -638,6 +675,7 @@ do_test (void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fputs_func = (fputs_func_t) fputws;
|
fputs_func = (fputs_func_t) fputws;
|
||||||
|
fgets_func = (fgets_func_t) fgetws;
|
||||||
data = wide_data;
|
data = wide_data;
|
||||||
data_len = wcslen (wide_data);
|
data_len = wcslen (wide_data);
|
||||||
ret |= do_one_test (filename);
|
ret |= do_one_test (filename);
|
||||||
|
@ -257,7 +257,10 @@ _IO_wfile_underflow (fp)
|
|||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
{
|
{
|
||||||
if (count == 0 && naccbuf == 0)
|
if (count == 0 && naccbuf == 0)
|
||||||
fp->_flags |= _IO_EOF_SEEN;
|
{
|
||||||
|
fp->_flags |= _IO_EOF_SEEN;
|
||||||
|
fp->_offset = _IO_pos_BAD;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fp->_flags |= _IO_ERR_SEEN, count = 0;
|
fp->_flags |= _IO_ERR_SEEN, count = 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user