This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug libc/23951] pread64(fd, buf, (size_t)-1, offset) do not works as expected, using 32bit glibc-2.27 under 64bit-linux-4.4
- From: "adhemerval.zanella at linaro dot org" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sourceware dot org
- Date: Thu, 06 Dec 2018 14:21:31 +0000
- Subject: [Bug libc/23951] pread64(fd, buf, (size_t)-1, offset) do not works as expected, using 32bit glibc-2.27 under 64bit-linux-4.4
- Auto-submitted: auto-generated
- References: <bug-23951-131@http.sourceware.org/bugzilla/>
https://sourceware.org/bugzilla/show_bug.cgi?id=23951
Adhemerval Zanella <adhemerval.zanella at linaro dot org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |RESOLVED
CC| |adhemerval.zanella at linaro dot o
| |rg
Resolution|--- |INVALID
--- Comment #5 from Adhemerval Zanella <adhemerval.zanella at linaro dot org> ---
(In reply to wangfangpeng from comment #4)
> (In reply to Andreas Schwab from comment #2)
> > I don't think there is a bug here, as in both cases we pass the arguments
> > unchanged to the kernel, and return what the kernel reports:
> >
> > pread64(0, "", 4294967295, 0) = 0
> >
> > pread64(0, 0x7ffdd658d2d0, 18446744073709551615, 0) = -1 EFAULT (Bad address)
>
> You mean this is a kernel bug,not a glibc bug?
You are relying on implementation detail when checking for EFAULT. POSIX [1]
does not define EFAULT as a possible error, even on 'may fail'.
pread64, when used on compat mode, does not fail with EFAULT because the check
on vfs_read that check if the user address access is 'ok' won't report an
invalid address:
fs/read_write.c
440 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t
*pos)
441 {
442 ssize_t ret;
443
444 if (!(file->f_mode & FMODE_READ))
445 return -EBADF;
446 if (!(file->f_mode & FMODE_CAN_READ))
447 return -EINVAL;
448 if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
449 return -EFAULT;
arch/x86/include/asm/uaccess.h
36 #define user_addr_max() (current_thread_info()->addr_limit.seg)
89 #define access_ok(type, addr, size) \
90 likely(!__range_not_ok(addr, size, user_addr_max()))
44 static inline bool __chk_range_not_ok(unsigned long addr, unsigned long
size, unsigned long limit)
45 {
46 /*
47 * If we have used "sizeof()" for the size,
48 * we know it won't overflow the limit (but
49 * it might overflow the 'addr', so it's
50 * important to subtract the size from the
51 * limit, not add it to the address).
52 */
53 if (__builtin_constant_p(size))
54 return unlikely(addr > limit - size);
55
56 /* Arbitrary sizes? Be careful about overflow */
57 addr += size;
58 if (unlikely(addr < size))
59 return true;
60 return unlikely(addr > limit);
61 }
62
63 #define __range_not_ok(addr, size, limit) \
64 ({ \
65 __chk_user_ptr(addr); \
66 __chk_range_not_ok((unsigned long __force)(addr), size, limit); \
67 })
Assuming user_addr_max use the definition of USER_DS, it will check against
TASK_SIZE_MAX (usually (1UL << 47) - PAGE_SIZE for x86_64 kernels), any 32-bit
ADDR plus any 32-bit size won't trigger the invalid range. I think current
Linux does not handle TASK_SIZE_MAX differently depending on if the process is
32 or 64 in 64-bit kernels.
In any case, this has not to do with glibc since from standard it should not
emulate this behavior. As Andreas Schwab has put on comment #2, it is up to
kernel to provide identical semantic for pread regardless it is running on 32
or 64-bit kernel.
As a side note, I see the same issue on glibc-2.20. It will use essentially
__NR_pread64 as for newer glibc.
[1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html
--
You are receiving this mail because:
You are on the CC list for the bug.