ANDROID: 16K: Emulate pread() for pagemap

pread() can read from a specified offset of the file without
changing the files offset position.

In the case of reading /proc/*/pagemap with pread() in an emulated
16KB x86_64 device, userspace believes the pages are large than
they actually are; we adjust the start offset of the pread to emulate
reading the correct page map entries. Adjustment of the count is
handled by .pagemap_read() which will be called by the VFS layer.

This is effectively a no-op in the page size isn't being emulated.

Bug: 383389337
Bug: 385167611
Test: atest vts_ltp_test_x86_64:syscalls.msync04_64bit#syscalls.msync04_64bit
Test: atest vts_ltp_test_x86_64:syscalls.mmap12_64bit#syscalls.mmap12_64bit
Test: atest libmeminfo_test
Test: atest bionic-unit-tests:DlExtRelroSharingTest#VerifyMemorySaving
Note: bionic-unit-tests must be run as root (add require_root: true)
Change-Id: I139d510d7fdb7040236e01a2dc9ee9d5c9c207fd
Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
This commit is contained in:
Kalesh Singh
2025-01-25 02:30:47 +00:00
committed by Carlos Llamas
parent 669f0c4355
commit d684b3125e
3 changed files with 26 additions and 0 deletions

View File

@@ -2923,6 +2923,11 @@ const struct file_operations proc_pagemap_operations = {
.unlocked_ioctl = do_pagemap_cmd,
.compat_ioctl = do_pagemap_cmd,
};
bool __is_emulated_pagemap_file(struct file *file)
{
return __PAGE_SIZE != PAGE_SIZE && file->f_op == &proc_pagemap_operations;
}
#endif /* CONFIG_PROC_PAGE_MONITOR */
#ifdef CONFIG_NUMA

View File

@@ -16,6 +16,7 @@
#include <linux/export.h>
#include <linux/syscalls.h>
#include <linux/pagemap.h>
#include <linux/page_size_compat.h>
#include <linux/splice.h>
#include <linux/compat.h>
#include <linux/mount.h>
@@ -760,6 +761,17 @@ ssize_t ksys_pread64(unsigned int fd, char __user *buf, size_t count,
f = fdget(fd);
if (fd_file(f)) {
ret = -ESPIPE;
/*
* If userspace thinks the pages are larger than they actually are,
* adjust the offset and count to compensate.
*
* NOTE: We only need to adjust the position here since pagemap_read()
* handles updating the count.
*/
if (__is_emulated_pagemap_file(fd_file(f)))
pos *= __PAGE_SIZE / PAGE_SIZE;
if (fd_file(f)->f_mode & FMODE_PREAD)
ret = vfs_read(fd_file(f), buf, count, &pos);
fdput(f);

View File

@@ -165,6 +165,15 @@ extern void __fold_filemap_fixup_entry(struct vma_iterator *iter, unsigned long
extern int __fixup_swap_header(struct file *swap_file, struct address_space *mapping);
#ifdef CONFIG_PROC_PAGE_MONITOR
extern bool __is_emulated_pagemap_file(struct file *file);
#else
static inline bool __is_emulated_pagemap_file(struct file *file)
{
return false;
}
#endif
#endif /* !__ASSEMBLY__ */
#endif /* __LINUX_PAGE_SIZE_COMPAT_H */