From b3ec6f15f0a05438c905b8af8ec19755e02719db Mon Sep 17 00:00:00 2001 From: corinna Date: Sat, 5 Jul 2003 18:59:35 +0000 Subject: [PATCH] * mmap.cc (list::match): Add parameters to return valid address and length back to munmap(). Evaluate intersection between given area and mapped area and return it, if any. (mmap64): On regular files, don't allow mappings beginning beyond EOF. Return with errno set to ENXIO instead. (munmap): Rewrite SUSv3 conformant. Check if given memory area is valid. Unmap all maps inside given memory area. Don't return error if no mapping has been unmapped. --- winsup/cygwin/ChangeLog | 13 +++++++++- winsup/cygwin/mmap.cc | 66 +++++++++++++++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index fd982faa05..0bc113e5d1 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,4 +1,15 @@ -2003-07-04 N Stephens +2003-07-05 Corinna Vinschen + + * mmap.cc (list::match): Add parameters to return valid address and + length back to munmap(). Evaluate intersection between given + area and mapped area and return it, if any. + (mmap64): On regular files, don't allow mappings beginning beyond + EOF. Return with errno set to ENXIO instead. + (munmap): Rewrite SUSv3 conformant. Check if given memory area is + valid. Unmap all maps inside given memory area. Don't return error + if no mapping has been unmapped. + +2003-07-05 N Stephens * fhandler.h (fhandler_socket::get_connect_state): New method to return socket connection state. diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index cd974bed11..00ef3e6bc9 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -270,7 +270,8 @@ public: void erase (int i); void erase (); mmap_record *match (_off64_t off, DWORD len); - long match (caddr_t addr, DWORD len, long start); + long match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, + long start); }; list::list () @@ -323,13 +324,24 @@ list::match (_off64_t off, DWORD len) /* Used in munmap() */ long -list::match (caddr_t addr, DWORD len, _off_t start) +list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, + _off_t start) { + caddr_t low, high; + for (int i = start + 1; i < nrecs; ++i) - if (addr >= recs[i].get_address () - && addr + len <= recs[i].get_address () - + (PAGE_CNT (recs[i].get_size ()) * getpagesize ())) - return i; + { + low = (addr >= recs[i].get_address ()) ? addr : recs[i].get_address (); + high = recs[i].get_address () + + (PAGE_CNT (recs[i].get_size ()) * getpagesize ()); + high = (addr + len < high) ? addr + len : high; + if (low < high) + { + m_addr = low; + m_len = high - low; + return i; + } + } return -1; } @@ -486,6 +498,16 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) DWORD high; DWORD low = GetFileSize (fh->get_handle (), &high); _off64_t fsiz = ((_off64_t)high << 32) + low; + /* Don't allow mappings beginning beyond EOF since Windows can't + handle that POSIX like. FIXME: Still looking for a good idea + to allow that nevertheless. */ + if (gran_off >= fsiz) + { + set_errno (ENXIO); + ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, + "mmap"); + return MAP_FAILED; + } fsiz -= gran_off; if (gran_len > fsiz) gran_len = fsiz; @@ -591,16 +613,16 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, _off_t off) return mmap64 (addr, len, prot, flags, fd, (_off64_t)off); } -/* munmap () removes an mmapped area. It insists that base area - requested is the same as that mmapped, error if not. */ +/* munmap () removes all mmapped pages between addr and addr+len. */ extern "C" int munmap (caddr_t addr, size_t len) { syscall_printf ("munmap (addr %x, len %d)", addr, len); - /* Error conditions according to SUSv2 */ - if (((DWORD)addr % getpagesize ()) || !len) + /* Error conditions according to SUSv3 */ + if (!addr || ((DWORD)addr % getpagesize ()) || !len + || IsBadReadPtr (addr, len)) { set_errno (EINVAL); syscall_printf ("-1 = munmap(): Invalid parameters"); @@ -608,17 +630,15 @@ munmap (caddr_t addr, size_t len) } SetResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); - /* Check if a mmap'ed area was ever created */ if (mmapped_areas == NULL) { syscall_printf ("-1 = munmap(): mmapped_areas == NULL"); - set_errno (EINVAL); ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); - return -1; + return 0; } - /* Iterate through the map, looking for the mmapped area. - Error if not found. */ + /* Iterate through the map, unmap pages between addr and addr+len + in all maps. */ for (int it = 0; it < mmapped_areas->nlists; ++it) { @@ -626,10 +646,13 @@ munmap (caddr_t addr, size_t len) if (map_list) { long li = -1; - if ((li = map_list->match(addr, len, li)) >= 0) + caddr_t u_addr; + DWORD u_len; + + while ((li = map_list->match(addr, len, u_addr, u_len, li)) >= 0) { mmap_record *rec = map_list->recs + li; - if (rec->unmap_map (addr, len)) + if (rec->unmap_map (u_addr, u_len)) { fhandler_base *fh = rec->alloc_fh (); fh->munmap (rec->get_handle (), addr, len); @@ -638,18 +661,13 @@ munmap (caddr_t addr, size_t len) /* Delete the entry. */ map_list->erase (li); } - syscall_printf ("0 = munmap(): %x", addr); - ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); - return 0; } } } - set_errno (EINVAL); - syscall_printf ("-1 = munmap(): EINVAL"); - ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); - return -1; + syscall_printf ("0 = munmap(): %x", addr); + return 0; } /* Sync file with memory. Ignore flags for now. */ -- 2.11.0