Note: This is a beta release of Red Hat Bugzilla 5.0. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Also email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback here.
Bug 454865 - read() returns incorrect value
Summary: read() returns incorrect value
Keywords:
Status: CLOSED DUPLICATE of bug 453053
Alias: None
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: kernel
Version: 4.6
Hardware: x86_64
OS: Linux
medium
medium
Target Milestone: rc
: ---
Assignee: Larry Woodman
QA Contact: Martin Jenner
URL:
Whiteboard:
Depends On:
Blocks: 461304
TreeView+ depends on / blocked
 
Reported: 2008-07-10 10:45 UTC by Konstantin Khorenko
Modified: 2008-09-17 18:57 UTC (History)
4 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2008-09-17 18:57:41 UTC
Target Upstream Version:


Attachments (Terms of Use)
patch fixes copy_user_generic return value on error path (deleted)
2008-07-10 10:45 UTC, Konstantin Khorenko
no flags Details | Diff
v2.: patch fixes copy_user_generic return value on error path (deleted)
2008-07-11 13:14 UTC, Konstantin Khorenko
no flags Details | Diff

Description Konstantin Khorenko 2008-07-10 10:45:33 UTC
During recent OpenVZ/Virtuozzo kernel testing our kernel team noticed a bug
which also takes place in RHEL4 kernel 2.6.9-67.0.20.ELsmp x86_64 kernel:

if read() is going to read < 8 bytes and fails it returns success and a big
value as a number of bytes read.

A testcase:
[root@aaa finist]# cat read_test.c
#define _GNU_SOURCE             /* for O_DIRECTORY */
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

int main() {
        void *buf = (void *) -1;
        char a;
        int ret, fd3;
        char fname[] = "read02.tmp";

        // Note: PROT_NONE used => pages may not be accessed
        buf = mmap(0, 1, PROT_NONE,
                        MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
        if (buf == MAP_FAILED) {
                perror("mmap failed");
                return 1;
        }
        // prepare a file with 1 byte in it
        fd3 = open(fname, O_RDWR | O_CREAT, 0666);
        if (fd3 < 0) {
                perror("open");
                return 1;
        }
        if (write(fd3, "A", 1) != 1) {
                perror("read");
                return 1;
        }
        close(fd3);
        fd3 = open(fname, O_RDWR, 0666);
        if (fd3 < 0) {
                perror("open");
                return 1;
        }

        // try to read from the file to the buffer which cannot be accessed
        ret = read(fd3, buf, 1);
        printf("%d %d %m\n", ret, errno);
        return 0;
}
[root@aaa finist]# gcc read_test.c
[root@aaa finist]# ./a.out
-2024112128 0 Success
[root@aaa finist]# uname -a
Linux aaa 2.6.9-67.0.20.ELsmp #1 SMP Wed Jun 18 12:35:02 EDT 2008 x86_64 x86_64
x86_64 GNU/Linux

At the moment old kernel works as expected:
[root@aaa finist]# uname -a
Linux aaa 2.6.9-42.ELsmp #1 SMP Wed Jul 12 23:32:02 EDT 2006 x86_64 x86_64
x86_64 GNU/Linux
[root@aaa finist]# ./a.out
-1 14 Bad address

############################################################################
This bug is due to patch linux-2.6.9-x86_64-copy_user-zero-tail.patch which
appeared first in 2.6.9-67.0.20 kernel.

The problem is the following:

left = __copy_to_user(desc->arg.buf, kaddr + offset, size);
__copy_to_user() returns wrong value.

the appropriate piece of code:
arch/x86_64/lib/copy_user.S:

 /* rdi destination
  * rsi source
  * rdx count
  *
  * Output:
  * eax uncopied bytes or 0 if successfull.
  */
copy_user_generic_c:
        xorq %rax,%rax
        movl %edx,%ecx
        shrl $3,%ecx
        andl $7,%edx
.Lc1:   rep
        movsq
        movl %edx,%ecx
.Lc2:   rep
        movsb
        ret

.Lc1e:  movq %rcx,%rsi
.Lc3:   rep
        stosq
.Lc2e:  movl %edx,%ecx
.Lc4:   rep
        stosb
.Lc3e:  leaq (%rdx,%rsi,8),%rax
        ret

When (size == 1) we execute the following strings:
.Lc2e:  movl %edx,%ecx
.Lc4:   rep
        stosb
.Lc3e:  leaq (%rdx,%rsi,8),%rax
        ret
So, %rsi contains the source address but not the number of octets of uncopied bytes.

Marat Stanichecnko (mstanichenko@openvz.org), an Virtuozzo/OpenVZ developer,
prepared a patch to fix this issue, attached.

Comment 1 Konstantin Khorenko 2008-07-10 10:45:33 UTC
Created attachment 311467 [details]
patch fixes copy_user_generic return value on error path

Comment 2 Konstantin Khorenko 2008-07-10 12:27:40 UTC
The patch was mistakenly done with -p0. Sorry for that.

Comment 3 Konstantin Khorenko 2008-07-11 13:12:04 UTC
Comment on attachment 311467 [details]
patch fixes copy_user_generic return value on error path

the patch is incorrect, al is used by stosb.

Comment 4 Konstantin Khorenko 2008-07-11 13:14:19 UTC
Created attachment 311573 [details]
v2.: patch fixes copy_user_generic return value on error path

Comment 7 RHEL Product and Program Management 2008-07-31 18:03:24 UTC
This request was evaluated by Red Hat Product Management for inclusion in a Red
Hat Enterprise Linux maintenance release.  Product Management has requested
further review of this request by Red Hat Engineering, for potential
inclusion in a Red Hat Enterprise Linux Update release for currently deployed
products.  This request is not yet committed for inclusion in an Update
release.

Comment 9 RHEL Product and Program Management 2008-09-03 13:14:39 UTC
Updating PM score.

Comment 10 Larry Woodman 2008-09-17 18:57:41 UTC

*** This bug has been marked as a duplicate of bug 453053 ***


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