4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-22 00:38:06 +08:00

Cygwin: mmap: fix protection when unused pages are recycled

Previously, when unused pages from an mmap_record were recycled, they
were given the protection of the mmap_record rather than the
protection requested in the mmap call.  Fix this by adding a
"new_prot" parameter to mmap_list::try_map() and
mmap_record::map_pages() to keep track of the requested protection.
Then use new_prot in the calls to VirtualProtect().

Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256911.html
Fixes: f90e23f2714cb ("*autoload.cc (NtCreateSection): Define.")
Signed-off-by: Ken Brown <kbrown@cornell.edu>
This commit is contained in:
Ken Brown 2024-12-18 11:39:31 -05:00
parent efa5401ea9
commit 677e315090
2 changed files with 21 additions and 13 deletions

View File

@ -339,8 +339,8 @@ class mmap_record
SIZE_T find_unused_pages (SIZE_T pages) const;
bool match (caddr_t addr, SIZE_T len, caddr_t &m_addr, SIZE_T &m_len);
off_t map_pages (SIZE_T len);
bool map_pages (caddr_t addr, SIZE_T len);
off_t map_pages (SIZE_T len, int new_prot);
bool map_pages (caddr_t addr, SIZE_T len, int new_prot);
bool unmap_pages (caddr_t addr, SIZE_T len);
int access (caddr_t address);
@ -373,7 +373,8 @@ class mmap_list
void set (int nfd, struct stat *st);
mmap_record *add_record (mmap_record &r);
bool del_record (mmap_record *rec);
caddr_t try_map (void *addr, size_t len, int flags, off_t off);
caddr_t try_map (void *addr, size_t len, int new_prot, int flags,
off_t off);
};
class mmap_areas
@ -455,14 +456,15 @@ mmap_record::init_page_map (mmap_record &r)
}
off_t
mmap_record::map_pages (SIZE_T len)
mmap_record::map_pages (SIZE_T len, int new_prot)
{
/* Used ONLY if this mapping matches into the chunk of another already
performed mapping in a special case of MAP_ANON|MAP_PRIVATE.
Otherwise it's job is now done by init_page_map(). */
DWORD old_prot;
debug_printf ("map_pages (fd=%d, len=%lu)", get_fd (), len);
debug_printf ("map_pages (fd=%d, len=%lu, new_prot=%y)", get_fd (), len,
new_prot);
len = PAGE_CNT (len);
off_t off = find_unused_pages (len);
@ -470,7 +472,8 @@ mmap_record::map_pages (SIZE_T len)
return (off_t) 0;
if (!noreserve ()
&& !VirtualProtect (get_address () + off * wincap.page_size (),
len * wincap.page_size (), gen_protect (),
len * wincap.page_size (),
::gen_protect (new_prot, get_flags ()),
&old_prot))
{
__seterrno ();
@ -483,9 +486,10 @@ mmap_record::map_pages (SIZE_T len)
}
bool
mmap_record::map_pages (caddr_t addr, SIZE_T len)
mmap_record::map_pages (caddr_t addr, SIZE_T len, int new_prot)
{
debug_printf ("map_pages (addr=%p, len=%lu)", addr, len);
debug_printf ("map_pages (addr=%p, len=%lu, new_prot=%y)", addr, len,
new_prot);
DWORD old_prot;
off_t off = addr - get_address ();
off /= wincap.page_size ();
@ -499,7 +503,8 @@ mmap_record::map_pages (caddr_t addr, SIZE_T len)
}
if (!noreserve ()
&& !VirtualProtect (get_address () + off * wincap.page_size (),
len * wincap.page_size (), gen_protect (),
len * wincap.page_size (),
::gen_protect (new_prot, get_flags ()),
&old_prot))
{
__seterrno ();
@ -614,7 +619,7 @@ mmap_list::del_record (mmap_record *rec)
}
caddr_t
mmap_list::try_map (void *addr, size_t len, int flags, off_t off)
mmap_list::try_map (void *addr, size_t len, int new_prot, int flags, off_t off)
{
mmap_record *rec;
@ -628,7 +633,7 @@ mmap_list::try_map (void *addr, size_t len, int flags, off_t off)
break;
if (rec && rec->compatible_flags (flags))
{
if ((off = rec->map_pages (len)) == (off_t) -1)
if ((off = rec->map_pages (len, new_prot)) == (off_t) -1)
return (caddr_t) MAP_FAILED;
return (caddr_t) rec->get_address () + off;
}
@ -655,7 +660,7 @@ mmap_list::try_map (void *addr, size_t len, int flags, off_t off)
set_errno (EINVAL);
return (caddr_t) MAP_FAILED;
}
if (!rec->map_pages ((caddr_t) addr, len))
if (!rec->map_pages ((caddr_t) addr, len, new_prot))
return (caddr_t) MAP_FAILED;
return (caddr_t) addr;
}
@ -1051,7 +1056,7 @@ go_ahead:
/* Test if an existing anonymous mapping can be recycled. */
if (map_list && anonymous (flags))
{
caddr_t tried = map_list->try_map (addr, len, flags, off);
caddr_t tried = map_list->try_map (addr, len, prot, flags, off);
/* try_map returns NULL if no map matched, otherwise it returns
a valid address, or MAP_FAILED in case of a fatal error. */
if (tried)

View File

@ -61,3 +61,6 @@ Fixes:
- Fix several problems triggered when a lot of SIGSTOP/SIGCONT signals
are received rapidly.
Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html
- Fix the protection when mmap(2) recycles unused pages.
Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256911.html