Bug 14292 - fmemopen_seek() incorrectly inverses seek offset when using SEEK_END
Summary: fmemopen_seek() incorrectly inverses seek offset when using SEEK_END
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: stdio (show other bugs)
Version: 2.19
: P1 critical
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-06-25 14:56 UTC by Tobias Klausmann
Modified: 2015-07-08 15:17 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Klausmann 2012-06-25 14:56:04 UTC
From the fseek man page:

If whence is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset  is  relative  to the start of the file, the current position indicator, or end-of-file, respectively.

This leads me to believe that fseek(file, -1, SEEK_END); would seek to the penultimate byte of file). using fseek on fopen()ened files does exactly that.

Howeverm, the fmemopen-specific implementation fseek (libio/fmemopen.c:151 has this implementation:

    case SEEK_END:
      np = (c->binmode ? c->size : c->maxpos) - *p;
      break;

Which makes a negative offset seek forward from the end of the file (this fails, naturally).
Comment 1 Tobias Klausmann 2012-08-13 08:27:24 UTC
This is also present in 2.16
Comment 2 Tobias Klausmann 2012-12-27 21:28:02 UTC
... and in 2.17
Comment 3 Tobias Klausmann 2013-06-25 13:33:46 UTC
HAppy birthday, dear trivial bug.
Comment 4 Tobias Klausmann 2013-08-13 07:33:06 UTC
And it's in 2.18, too.
Comment 5 paxdiablo 2014-01-30 05:32:47 UTC
This is a definite bug and should be fixed. "Real" files use -20 with SEEK_END to seek 20 bytes back from the end.

Author freely admitted that there may be differences between their fmemopen and the original GNU one and that they weren't shure whether the glibc original version suppoerted seek. But, if you're going to add it, you should do it the way the spec says (POSIX). It clearly states that the offset is added to the whence to get the position from file start, that means you need to seek negative from SEEK_END to back up.

It's a "simple" (simple, assuming people haven't allowed for it) matter of changing:

   np = (c->binmode ? c->size : c->maxpos) - *p;

into:

   np = (c->binmode ? c->size : c->maxpos) + *p;
Comment 6 paxdiablo 2014-01-30 05:42:54 UTC
Upgrading importance since it dfoesn't conform to ISO C. Reasoning is that it changes how fseek() works depending on underlying "file" type.
Comment 7 paxdiablo 2014-01-30 08:09:18 UTC
FWIW, this bug has been there since about 2001. glibc-2.1.3 from Feb-2000 had the old implementation in stdio which didn't support fseek at all.

In Jan-2001, glibc-2.2.1 incorporated the new code into libio and it already had that bug.

I can only assume that the fact no-one noticed for over a decade is because no-one has ever used it :-)
Comment 8 Tobias Klausmann 2014-03-24 11:55:14 UTC
Also present in 2.19
Comment 9 Florian Weimer 2014-06-13 14:04:42 UTC
Marking as no security impact because there are apparently have not been any users of this function.
Comment 10 Adhemerval Zanella 2015-07-08 15:17:19 UTC
This is fixed by fdb7d390dd0d96e4a8239c46f3aa64598b90842b.  Closing this bug.