@@ -3785,38 +3785,62 @@ static bool copy_mem_mapping_just_used(Task* from, Task* to, const KernelMapping
37853785 return true ;
37863786}
37873787
3788- static void move_vdso_mapping (AutoRemoteSyscalls &remote, const KernelMapping &km) {
3789- for (const auto & m : remote.task ()->vm ()->maps ()) {
3790- if (m.map .is_vdso () && m.map .start () != km.start ()) {
3791- size_t size = m.map .size ();
3792- ASSERT (remote.task (), size == km.size ()) << " Inconsistent VDSO sizes" ;
3793- // Handle case where old and new addresses overlap by finding a free range early in the
3794- // address space we can use as a temporary buffer. VDSOs are always at fairly high
3795- // addresses so this shouldn't introduce any new overlap issues.
3796- remote_ptr<void > free_mem = remote.task ()->vm ()->find_free_memory (remote.task (), size,
3797- remote_ptr<void >(65536 ), AddressSpace::FindFreeMemoryPolicy::STRICT_SEARCH);
3798- if (!free_mem) {
3799- FATAL () << " Can't find free memory for VDSO " << m.map ;
3788+ static void move_vdso_and_vvar_mappings (AutoRemoteSyscalls& remote,
3789+ const KernelMapping& vdso, const KernelMapping& vvar) {
3790+ /* Remap VDSO and VVAR to the addresses is used in the target process,
3791+ before they get unmapped.
3792+ Otherwise the kernel seems to put the address of the original
3793+ VDSO __kernel_rt_sigreturn function as return address on the stack.
3794+ This might not affect x86_64 because there __restore_rt
3795+ located in libpthread.so.0 is used.
3796+ */
3797+
3798+ // Handle case where old and new addresses overlap by finding a free range early in the
3799+ // address space we can use as a temporary buffer. VDSOs are always at fairly high
3800+ // addresses so this shouldn't introduce any new overlap issues.
3801+ // We move VDSO and VVAR to their temp addresses first, then move both of them to their
3802+ // final address, to avoid situations where current's VDSO overlaps target's VVAR or
3803+ // vice versa.
3804+ remote_ptr<void > vdso_temp_address = remote.task ()->vm ()->find_free_memory (remote.task (),
3805+ vdso.size () + vvar.size (),
3806+ remote_ptr<void >(65536 ), AddressSpace::FindFreeMemoryPolicy::STRICT_SEARCH);
3807+ remote_ptr<void > vvar_temp_address = vdso_temp_address + vdso.size ();
3808+
3809+ for (int phase = 0 ; phase < 2 ; ++phase) {
3810+ for (const auto & m : remote.task ()->vm ()->maps ()) {
3811+ const KernelMapping* move_to = nullptr ;
3812+ remote_ptr<void > temp_address;
3813+ if (m.map .is_vdso () && vdso.size ()) {
3814+ move_to = &vdso;
3815+ temp_address = vdso_temp_address;
3816+ } else if (m.map .is_vvar () && vvar.size ()) {
3817+ move_to = &vvar;
3818+ temp_address = vvar_temp_address;
38003819 }
3801- if (MemoryRange (free_mem, size). intersects ( MemoryRange ( m.map .start (), size) )) {
3802- FATAL () << " Free memory found overlaps current VDSO address " ;
3820+ if (!move_to || m.map .start () == move_to-> start ( )) {
3821+ continue ;
38033822 }
3804- if (MemoryRange (free_mem, size).intersects (MemoryRange (km.start (), size))) {
3805- FATAL () << " Free memory found overlaps new VDSO address" ;
3823+
3824+ size_t size = m.map .size ();
3825+ ASSERT (remote.task (), size == move_to->size ()) << " Inconsistent VDSO sizes" ;
3826+ ASSERT (remote.task (), !temp_address.is_null ()) << " Can't find free memory for VDSO " << m.map ;
3827+ ASSERT (remote.task (),
3828+ !MemoryRange (temp_address, size).intersects (MemoryRange (m.map .start (), size)))
3829+ << " Free memory found overlaps current VDSO address" ;
3830+ ASSERT (remote.task (),
3831+ !MemoryRange (temp_address, size).intersects (MemoryRange (move_to->start (), size)))
3832+ << " Free memory found overlaps new VDSO address" ;
3833+
3834+ if (phase == 0 ) {
3835+ LOG (debug) << " Moving VDSO for " << remote.task ()->tid << " to temp " << temp_address;
3836+ remote.infallible_syscall (syscall_number_for_mremap (remote.arch ()), m.map .start (), size,
3837+ size, MREMAP_MAYMOVE | MREMAP_FIXED, temp_address);
3838+ } else {
3839+ remote.infallible_syscall (syscall_number_for_mremap (remote.arch ()), temp_address, size,
3840+ size, MREMAP_MAYMOVE | MREMAP_FIXED, move_to->start ());
3841+ remote.task ()->vm ()->remap (remote.task (), m.map .start (), size, move_to->start (), size,
3842+ MREMAP_MAYMOVE | MREMAP_FIXED);
38063843 }
3807- LOG (debug) << " Moving VDSO for " << remote.task ()->tid ;
3808- /* Remap VDSO to the address that is used in the target process,
3809- before it gets unmapped.
3810- Otherwise the kernel seems to put the address of the original
3811- VDSO __kernel_rt_sigreturn function as return address on the stack.
3812- This might not affect x86_64 because there __restore_rt
3813- located in libpthread.so.0 is used. */
3814- remote.infallible_syscall (syscall_number_for_mremap (remote.arch ()), m.map .start (), size,
3815- size, MREMAP_MAYMOVE | MREMAP_FIXED, free_mem);
3816- remote.infallible_syscall (syscall_number_for_mremap (remote.arch ()), free_mem, size,
3817- size, MREMAP_MAYMOVE | MREMAP_FIXED, km.start ());
3818- remote.task ()->vm ()->remap (remote.task (), m.map .start (), size, km.start (), size,
3819- MREMAP_MAYMOVE | MREMAP_FIXED);
38203844 }
38213845 }
38223846}
@@ -3833,7 +3857,7 @@ void Task::dup_from(Task *other) {
38333857 KernelMapping stack_mapping;
38343858 bool found_stack = false ;
38353859 KernelMapping vdso_mapping;
3836- bool found_vdso = false ;
3860+ KernelMapping vvar_mapping ;
38373861
38383862 for (auto map : other->vm ()->maps ()) {
38393863 auto km = map.map ;
@@ -3854,10 +3878,11 @@ void Task::dup_from(Task *other) {
38543878 found_stack = true ;
38553879 } else {
38563880 mappings.push_back (km);
3857- }
3858- if (km.is_vdso ()) {
3859- found_vdso = true ;
3860- vdso_mapping = km;
3881+ if (km.is_vdso ()) {
3882+ vdso_mapping = km;
3883+ } else if (km.is_vvar ()) {
3884+ vvar_mapping = km;
3885+ }
38613886 }
38623887 }
38633888 ASSERT (this , found_stack);
@@ -3869,9 +3894,7 @@ void Task::dup_from(Task *other) {
38693894 }
38703895 {
38713896 AutoRemoteSyscalls remote (this , AutoRemoteSyscalls::DISABLE_MEMORY_PARAMS);
3872- if (found_vdso) {
3873- move_vdso_mapping (remote, vdso_mapping);
3874- }
3897+ move_vdso_and_vvar_mappings (remote, vdso_mapping, vvar_mapping);
38753898 LOG (debug) << " Unmapping memory for " << tid;
38763899 // TODO: Only do this if the rr page isn't already mapped
38773900 this ->vm ()->unmap_all_but_rr_page (remote);
0 commit comments