Bug 86439 - memccpy() can read past end of source string
memccpy() can read past end of source string
Status: CLOSED ERRATA
Product: Red Hat Enterprise Linux 2.1
Classification: Red Hat
Component: glibc (Show other bugs)
2.1
ia64 Linux
medium Severity medium
: ---
: ---
Assigned To: Jakub Jelinek
Brian Brock
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2003-03-21 18:35 EST by Jason Uhlenkott
Modified: 2016-11-24 09:50 EST (History)
1 user (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2003-05-22 12:42:16 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Jason Uhlenkott 2003-03-21 18:35:25 EST
/*
The memccpy() call below will cause a segmentation fault on ia64
systems:  It tries to read beyond the end of srcbuf and hits an
unreadable page.  Is this a bug?

Note that we're deliberately indicating a size of SIZE+8 characters to
memccpy even though srcbuf is only SIZE characters long.

One point of view is that memccpy should never attempt to read more
than SIZE characters:  It should see the 0 character at srcbuf[SIZE-1]
and stop there.  memccpy() is supposed to stop after it copies n
characters or after it copies the character specified by the argument
c, whichever comes first, so obviously it's ok for the source string
to be shorter than n characters.

Another point of view is that just because it only copies SIZE
characters, that doesn't mean it will only try to access SIZE
characters from the source string.  The length of the source string is
allowed to be less than n characters, but the size of the object
containing the source string isn't.

The C standard contains some explicit language which comes down on the
side of the latter point of view.  Section 7.21.1 paragraph 2 (I'm
quoting from C99 since that's what I have handy, but C89/C90 has the
same requirements):
-----
| Where an argument declared as size_t n specifies the length of the
| array for a function, n can have the value zero on a call to that
| function.  Unless explicitly stated otherwise in the description of a
| particular function in this subclause, pointer arguments on such a
| call shall still have valid values, as described in 7.1.4.
-----
Section 7.1.4 states:
-----
| If a function argument is described as being an array, the pointer
| actually passed to the function shall have a value such that all
| address computations and accesses to objects (that would be valid if
| the pointer did point to the first element of such an array) are in
| fact valid.
-----
So if memccpy were a standard C function, we'd clearly be invoking
undefined behavior by doing what we're doing.  memccpy is not part of
the standard C library however.

One point which has caused some consternation is that these two
statements are expected to behave identically:
        memccpy(dstbuf, srcbuf, 0, SIZE+8);
        strncpy(dstbuf, srcbuf, SIZE+8);
Yet the memccpy call causes a segfault while the strncpy call does
not.
*/


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <assert.h>

#define SIZE 32768

int main(void) {

        int fd;
        char *srcbuf;
        char dstbuf[2*SIZE];
        char *protected;

        fd = open("/dev/zero", O_RDONLY);
        if(fd == -1) {
                perror("open");
                exit(EXIT_FAILURE);
        }

        srcbuf = mmap(0, SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
        if(srcbuf == (char *)-1) {
                perror("mmap");
                exit(EXIT_FAILURE);
        }
        protected = mmap(srcbuf+SIZE, SIZE, PROT_NONE,
                MAP_FIXED|MAP_PRIVATE, fd, SIZE);
        if(protected == (char *)-1) {
                perror("mmap");
                exit(EXIT_FAILURE);
        }
        assert(protected == srcbuf+SIZE);

        memset(srcbuf, 'x', SIZE-1);
        srcbuf[SIZE-1]='\0';

#if 1
        memccpy(dstbuf, srcbuf, 0, SIZE+8);
#else
        strncpy(dstbuf, srcbuf, SIZE+8);
#endif

        return 0;
}
Comment 1 Mark J. Cox (Product Security) 2003-05-22 12:42:17 EDT
An errata has been issued which should help the problem described in this bug report. 
This report is therefore being closed with a resolution of ERRATA. For more information
on the solution and/or where to find the updated files, please follow the link below. You may reopen 
this bug report if the solution does not work for you.

http://rhn.redhat.com/errata/RHSA-2003-090.html

Note You need to log in before you can comment on or make changes to this bug.