Messages in this thread | | | Date | Wed, 21 Jul 2021 01:25:41 +0300 | From | Cyrill Gorcunov <> | Subject | Re: [PATCH] prctl: allow to setup brk for et_dyn executables |
| |
On Tue, Jul 20, 2021 at 02:51:48PM -0700, Andrew Morton wrote: > > > > This of course prevent criu from restoring such programs. > > Looking into how kernel operates with brk/start_brk inside > > brk() syscall I don't see any problem if we allow to setup > > brk/start_brk without checking for end_data. Even if someone > > pass some weird address here on a purpose then the worst > > possible result will be an unexpected unmapping of existing > > vma (own vma, since prctl works with the callers memory) but > > test for RLIMIT_DATA is still valid and a user won't be able > > to gain more memory in case of expanding VMAs via new values > > shipped with prctl call. > > So... do you recall why you added that test originally?
To be honest, when I added this test in first place I simply forgot about et_dyn executables because we usually run executables via traditional exec call (where brk map sits before end_data VMA), not via loader and that's the reason why I didn't hit this problem before and why this get revealed only after a couple of years. This is simply rarely used.
> > This is under prctl(CAP_SET_MM), yes? What capabilities does this > require?
Yes, it is for prctl(PR_SET_MM_MAP) and requires no additional caps. The most important thing here is check_data_rlimit() function which called at the end of memory map verification -- we make sure the user won't get more memory than been granted by RLIMIT_DATA limit even if he passes some bad brk value here on a purpose.
/* * Neither we should allow to override limits if they set. */ if (check_data_rlimit(rlimit(RLIMIT_DATA), prctl_map->brk, prctl_map->start_brk, prctl_map->end_data, prctl_map->start_data)) goto out;
which expands to (I wrapped code to make it a bit more readable)
static inline int check_data_rlimit(unsigned long rlim, unsigned long new, unsigned long start, unsigned long end_data, unsigned long start_data) { if (rlimit(RLIMIT_DATA) < RLIM_INFINITY) { if (((prctl_map->brk - prctl_map->start_brk) + (prctl_map->end_data - prctl_map->start_data)) > rlimit(RLIMIT_DATA)) return -ENOSPC; }
return 0; }
| |