Skip to content

Commit 677e315

Browse files
committed
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: f90e23f ("*autoload.cc (NtCreateSection): Define.") Signed-off-by: Ken Brown <[email protected]>
1 parent efa5401 commit 677e315

File tree

2 files changed

+21
-13
lines changed

2 files changed

+21
-13
lines changed

winsup/cygwin/mm/mmap.cc

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,8 @@ class mmap_record
339339

340340
SIZE_T find_unused_pages (SIZE_T pages) const;
341341
bool match (caddr_t addr, SIZE_T len, caddr_t &m_addr, SIZE_T &m_len);
342-
off_t map_pages (SIZE_T len);
343-
bool map_pages (caddr_t addr, SIZE_T len);
342+
off_t map_pages (SIZE_T len, int new_prot);
343+
bool map_pages (caddr_t addr, SIZE_T len, int new_prot);
344344
bool unmap_pages (caddr_t addr, SIZE_T len);
345345
int access (caddr_t address);
346346

@@ -373,7 +373,8 @@ class mmap_list
373373
void set (int nfd, struct stat *st);
374374
mmap_record *add_record (mmap_record &r);
375375
bool del_record (mmap_record *rec);
376-
caddr_t try_map (void *addr, size_t len, int flags, off_t off);
376+
caddr_t try_map (void *addr, size_t len, int new_prot, int flags,
377+
off_t off);
377378
};
378379

379380
class mmap_areas
@@ -455,22 +456,24 @@ mmap_record::init_page_map (mmap_record &r)
455456
}
456457

457458
off_t
458-
mmap_record::map_pages (SIZE_T len)
459+
mmap_record::map_pages (SIZE_T len, int new_prot)
459460
{
460461
/* Used ONLY if this mapping matches into the chunk of another already
461462
performed mapping in a special case of MAP_ANON|MAP_PRIVATE.
462463
463464
Otherwise it's job is now done by init_page_map(). */
464465
DWORD old_prot;
465-
debug_printf ("map_pages (fd=%d, len=%lu)", get_fd (), len);
466+
debug_printf ("map_pages (fd=%d, len=%lu, new_prot=%y)", get_fd (), len,
467+
new_prot);
466468
len = PAGE_CNT (len);
467469

468470
off_t off = find_unused_pages (len);
469471
if (off == (off_t) -1)
470472
return (off_t) 0;
471473
if (!noreserve ()
472474
&& !VirtualProtect (get_address () + off * wincap.page_size (),
473-
len * wincap.page_size (), gen_protect (),
475+
len * wincap.page_size (),
476+
::gen_protect (new_prot, get_flags ()),
474477
&old_prot))
475478
{
476479
__seterrno ();
@@ -483,9 +486,10 @@ mmap_record::map_pages (SIZE_T len)
483486
}
484487

485488
bool
486-
mmap_record::map_pages (caddr_t addr, SIZE_T len)
489+
mmap_record::map_pages (caddr_t addr, SIZE_T len, int new_prot)
487490
{
488-
debug_printf ("map_pages (addr=%p, len=%lu)", addr, len);
491+
debug_printf ("map_pages (addr=%p, len=%lu, new_prot=%y)", addr, len,
492+
new_prot);
489493
DWORD old_prot;
490494
off_t off = addr - get_address ();
491495
off /= wincap.page_size ();
@@ -499,7 +503,8 @@ mmap_record::map_pages (caddr_t addr, SIZE_T len)
499503
}
500504
if (!noreserve ()
501505
&& !VirtualProtect (get_address () + off * wincap.page_size (),
502-
len * wincap.page_size (), gen_protect (),
506+
len * wincap.page_size (),
507+
::gen_protect (new_prot, get_flags ()),
503508
&old_prot))
504509
{
505510
__seterrno ();
@@ -614,7 +619,7 @@ mmap_list::del_record (mmap_record *rec)
614619
}
615620

616621
caddr_t
617-
mmap_list::try_map (void *addr, size_t len, int flags, off_t off)
622+
mmap_list::try_map (void *addr, size_t len, int new_prot, int flags, off_t off)
618623
{
619624
mmap_record *rec;
620625

@@ -628,7 +633,7 @@ mmap_list::try_map (void *addr, size_t len, int flags, off_t off)
628633
break;
629634
if (rec && rec->compatible_flags (flags))
630635
{
631-
if ((off = rec->map_pages (len)) == (off_t) -1)
636+
if ((off = rec->map_pages (len, new_prot)) == (off_t) -1)
632637
return (caddr_t) MAP_FAILED;
633638
return (caddr_t) rec->get_address () + off;
634639
}
@@ -655,7 +660,7 @@ mmap_list::try_map (void *addr, size_t len, int flags, off_t off)
655660
set_errno (EINVAL);
656661
return (caddr_t) MAP_FAILED;
657662
}
658-
if (!rec->map_pages ((caddr_t) addr, len))
663+
if (!rec->map_pages ((caddr_t) addr, len, new_prot))
659664
return (caddr_t) MAP_FAILED;
660665
return (caddr_t) addr;
661666
}
@@ -1051,7 +1056,7 @@ mmap (void *addr, size_t len, int prot, int flags, int fd, off_t off)
10511056
/* Test if an existing anonymous mapping can be recycled. */
10521057
if (map_list && anonymous (flags))
10531058
{
1054-
caddr_t tried = map_list->try_map (addr, len, flags, off);
1059+
caddr_t tried = map_list->try_map (addr, len, prot, flags, off);
10551060
/* try_map returns NULL if no map matched, otherwise it returns
10561061
a valid address, or MAP_FAILED in case of a fatal error. */
10571062
if (tried)

winsup/cygwin/release/3.5.5

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,6 @@ Fixes:
6161
- Fix several problems triggered when a lot of SIGSTOP/SIGCONT signals
6262
are received rapidly.
6363
Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html
64+
65+
- Fix the protection when mmap(2) recycles unused pages.
66+
Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256911.html

0 commit comments

Comments
 (0)