mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-18 00:58:31 +00:00
mem: don't PROT_WRITE on reservation mmaps
An application might call mmap with PROT_NONE to reserve a large amount of the virtual address space. Something like: void *addr = mmap(NULL, SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); During restore, when we have to premap private vmas (ie pieok is false), CRIU tries to mmap this large PROT_NONE and fails. If a vma has never been written to, it does not have "ac" flag set. Use this fact to safely premap vmas that were done for address reservation. Suggested-by: Andrei Vagin <avagin@gmail.com> Signed-off-by: Bhavik Sachdev <b.sachdev1904@gmail.com>
This commit is contained in:
parent
2c9ee0abd2
commit
7daaa11aa0
5 changed files with 33 additions and 11 deletions
|
|
@ -56,6 +56,7 @@ status = {
|
|||
"VMA_AREA_AIORING": 1 << 13,
|
||||
"VMA_AREA_MEMFD": 1 << 14,
|
||||
"VMA_AREA_UPROBES": 1 << 17,
|
||||
"VMA_AREA_NOT_ACCOUNTABLE": 1 << 18,
|
||||
"VMA_AREA_UNSUPP": 1 << 31
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@
|
|||
#define VMA_AREA_SHSTK (1 << 15)
|
||||
#define VMA_AREA_GUARD (1 << 16)
|
||||
#define VMA_AREA_UPROBES (1 << 17)
|
||||
#define VMA_AREA_NOT_ACCOUNTABLE (1 << 18)
|
||||
|
||||
#define VMA_EXT_PLUGIN (1 << 27)
|
||||
#define VMA_CLOSE (1 << 28)
|
||||
|
|
|
|||
26
criu/mem.c
26
criu/mem.c
|
|
@ -951,15 +951,25 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void
|
|||
}
|
||||
|
||||
/*
|
||||
* All mappings here get PROT_WRITE regardless of whether we
|
||||
* put any data into it or not, because this area will get
|
||||
* mremap()-ed (branch below) so we MIGHT need to have WRITE
|
||||
* bits there. Ideally we'd check for the whole COW-chain
|
||||
* having any data in.
|
||||
* For VMAs that have PROT_NONE and are not accountable
|
||||
* (did not have the "ac" flag in /proc/pid/smaps), we
|
||||
* can safely mmap them with PROT_NONE because we know
|
||||
* we will never need to write any bits to them.
|
||||
*/
|
||||
addr = mmap(*tgt_addr, size, vma->e->prot | PROT_WRITE, vma->e->flags | MAP_FIXED | flag, vma->e->fd,
|
||||
vma->e->pgoff);
|
||||
|
||||
if (vma->e->prot == PROT_NONE && vma_area_is(vma, VMA_AREA_NOT_ACCOUNTABLE)) {
|
||||
addr = mmap(*tgt_addr, size, PROT_NONE, vma->e->flags | MAP_FIXED | flag, vma->e->fd,
|
||||
vma->e->pgoff);
|
||||
} else {
|
||||
/*
|
||||
* All mappings here get PROT_WRITE regardless of whether we
|
||||
* put any data into it or not, because this area will get
|
||||
* mremap()-ed (branch below) so we MIGHT need to have WRITE
|
||||
* bits there. Ideally we'd check for the whole COW-chain
|
||||
* having any data in.
|
||||
*/
|
||||
addr = mmap(*tgt_addr, size, vma->e->prot | PROT_WRITE, vma->e->flags | MAP_FIXED | flag, vma->e->fd,
|
||||
vma->e->pgoff);
|
||||
}
|
||||
if (addr == MAP_FAILED) {
|
||||
pr_perror("Unable to map ANON_VMA");
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -123,10 +123,11 @@ bool handle_vma_plugin(int *fd, struct stat *stat)
|
|||
}
|
||||
|
||||
static void __parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf,
|
||||
int *shstk)
|
||||
int *shstk, bool *no_ac)
|
||||
{
|
||||
char *tok;
|
||||
|
||||
*no_ac = true;
|
||||
if (!buf[0])
|
||||
return;
|
||||
|
||||
|
|
@ -174,6 +175,9 @@ static void __parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf,
|
|||
if (_vmflag_match(tok, "ss"))
|
||||
*shstk = 1;
|
||||
|
||||
if (_vmflag_match(tok, "ac"))
|
||||
*no_ac = false;
|
||||
|
||||
/*
|
||||
* Anything else is just ignored.
|
||||
*/
|
||||
|
|
@ -185,21 +189,26 @@ static void __parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf,
|
|||
void parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf)
|
||||
{
|
||||
int shstk = 0;
|
||||
bool no_ac = false;
|
||||
|
||||
__parse_vmflags(buf, flags, madv, io_pf, &shstk);
|
||||
__parse_vmflags(buf, flags, madv, io_pf, &shstk, &no_ac);
|
||||
}
|
||||
|
||||
static void parse_vma_vmflags(char *buf, struct vma_area *vma_area)
|
||||
{
|
||||
int io_pf = 0;
|
||||
int shstk = 0;
|
||||
bool no_ac = false;
|
||||
|
||||
__parse_vmflags(buf, &vma_area->e->flags, &vma_area->e->madv, &io_pf,
|
||||
&shstk);
|
||||
&shstk, &no_ac);
|
||||
|
||||
if (shstk)
|
||||
vma_area->e->status |= VMA_AREA_SHSTK;
|
||||
|
||||
if (no_ac)
|
||||
vma_area->e->status |= VMA_AREA_NOT_ACCOUNTABLE;
|
||||
|
||||
/*
|
||||
* vmsplice doesn't work for VM_IO and VM_PFNMAP mappings, the
|
||||
* only exception is VVAR area that mapped by the kernel as
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ mmap_status_map = [
|
|||
('VMA_AREA_MEMFD', 1 << 14),
|
||||
('VMA_AREA_SHSTK', 1 << 15),
|
||||
('VMA_AREA_UPROBES', 1 << 17),
|
||||
('VMA_AREA_NOT_ACCOUNTABLE', 1 << 18),
|
||||
('VMA_UNSUPP', 1 << 31),
|
||||
]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue