On 10/17/23 2:08 PM, jeffxu@xxxxxxxxxxxx wrote: > From: Jeff Xu <jeffxu@xxxxxxxxxx> > > mremap(2) can shrink/expand a VMA, or move a VMA to a fixed > address and overwriting or existing VMA. Sealing will > prevent unintended mremap(2) call. > > What this patch does: > When a mremap(2) is invoked, if one of its VMAs has MM_SEAL_MREMAP > set from previous mseal(2) call, this mremap(2) will fail, without > any VMA modified. > > This patch is based on following: > 1. At syscall entry point: SYSCALL_DEFINE5(mremap,...) > There are two cases: Maybe we can reduce the code duplication by bringing the check if memory is sealed before call to mremap_to(). > a. going into mremap_to(). > b. not going into mremap_to(). > > 2. For mremap_to() case. > Since mremap_to() is called only from SYSCALL_DEFINE5(mremap,..), > omit changing signature of mremap_to(), i.e. not passing > checkSeals flag. > In mremap_to(), it calls can_modify_mm() for src address and > dst address (when MREMAP_FIXED is used), before any update is > made to the VMAs. > > 3. For non mremap_to() case. > It is still part of SYSCALL_DEFINE5(mremap,...). > It calls can_modify_mm() to check sealing in the src address, > before any update is made to src VMAs. > Check for dest address is not needed, because dest memory is > allocated in current mremap(2) call. > > Signed-off-by: Jeff Xu <jeffxu@xxxxxxxxxx> > --- > mm/mremap.c | 25 +++++++++++++++++++++++++ > 1 file changed, 25 insertions(+) > > diff --git a/mm/mremap.c b/mm/mremap.c > index ac363937f8c4..691fc32d37e4 100644 > --- a/mm/mremap.c > +++ b/mm/mremap.c > @@ -836,7 +836,27 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len, > if ((mm->map_count + 2) >= sysctl_max_map_count - 3) > return -ENOMEM; > > + /* > + * Check src address for sealing. > + * > + * Note: mremap_to() currently called from one place: > + * SYSCALL_DEFINE4(pkey_mprotect, ...) > + * and not in any other places. > + * Therefore, omit changing the signature of mremap_to() > + * Otherwise, we might need to add checkSeals and pass it > + * from all callers of mremap_to(). > + */ > + if (!can_modify_mm(mm, addr, addr + old_len, MM_SEAL_MREMAP)) > + return -EACCES; > + > if (flags & MREMAP_FIXED) { > + /* > + * Check dest address for sealing. > + */ > + if (!can_modify_mm(mm, new_addr, new_addr + new_len, > + MM_SEAL_MREMAP)) > + return -EACCES; > + Move these two checks to just before call to mremap_to() in sys_mremap() or even earlier. Or even better move the first condition before mremap_to() and second condition can be checked before call to mremap_to(). > ret = do_munmap(mm, new_addr, new_len, uf_unmap_early); > if (ret) > goto out; > @@ -995,6 +1015,11 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, > goto out; > } > > + if (!can_modify_mm(mm, addr, addr + old_len, MM_SEAL_MREMAP)) { > + ret = -EACCES; > + goto out; > + } > + > /* > * Always allow a shrinking remap: that just unmaps > * the unnecessary pages.. -- BR, Muhammad Usama Anjum