Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 284436
b: refs/heads/master
c: 028ee4b
h: refs/heads/master
v: v3
  • Loading branch information
Cyrill Gorcunov authored and Linus Torvalds committed Jan 13, 2012
1 parent 3ce2efb commit 38830a0
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b3f7f573a20081910e34e99cbc91831f4f02f1ff
refs/heads/master: 028ee4be34a09a6d48bdf30ab991ae933a7bc036
12 changes: 12 additions & 0 deletions trunk/include/linux/prctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,16 @@

#define PR_MCE_KILL_GET 34

/*
* Tune up process memory map specifics.
*/
#define PR_SET_MM 35
# define PR_SET_MM_START_CODE 1
# define PR_SET_MM_END_CODE 2
# define PR_SET_MM_START_DATA 3
# define PR_SET_MM_END_DATA 4
# define PR_SET_MM_START_STACK 5
# define PR_SET_MM_START_BRK 6
# define PR_SET_MM_BRK 7

#endif /* _LINUX_PRCTL_H */
121 changes: 121 additions & 0 deletions trunk/kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -1692,6 +1692,124 @@ SYSCALL_DEFINE1(umask, int, mask)
return mask;
}

#ifdef CONFIG_CHECKPOINT_RESTORE
static int prctl_set_mm(int opt, unsigned long addr,
unsigned long arg4, unsigned long arg5)
{
unsigned long rlim = rlimit(RLIMIT_DATA);
unsigned long vm_req_flags;
unsigned long vm_bad_flags;
struct vm_area_struct *vma;
int error = 0;
struct mm_struct *mm = current->mm;

if (arg4 | arg5)
return -EINVAL;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;

if (addr >= TASK_SIZE)
return -EINVAL;

down_read(&mm->mmap_sem);
vma = find_vma(mm, addr);

if (opt != PR_SET_MM_START_BRK && opt != PR_SET_MM_BRK) {
/* It must be existing VMA */
if (!vma || vma->vm_start > addr)
goto out;
}

error = -EINVAL;
switch (opt) {
case PR_SET_MM_START_CODE:
case PR_SET_MM_END_CODE:
vm_req_flags = VM_READ | VM_EXEC;
vm_bad_flags = VM_WRITE | VM_MAYSHARE;

if ((vma->vm_flags & vm_req_flags) != vm_req_flags ||
(vma->vm_flags & vm_bad_flags))
goto out;

if (opt == PR_SET_MM_START_CODE)
mm->start_code = addr;
else
mm->end_code = addr;
break;

case PR_SET_MM_START_DATA:
case PR_SET_MM_END_DATA:
vm_req_flags = VM_READ | VM_WRITE;
vm_bad_flags = VM_EXEC | VM_MAYSHARE;

if ((vma->vm_flags & vm_req_flags) != vm_req_flags ||
(vma->vm_flags & vm_bad_flags))
goto out;

if (opt == PR_SET_MM_START_DATA)
mm->start_data = addr;
else
mm->end_data = addr;
break;

case PR_SET_MM_START_STACK:

#ifdef CONFIG_STACK_GROWSUP
vm_req_flags = VM_READ | VM_WRITE | VM_GROWSUP;
#else
vm_req_flags = VM_READ | VM_WRITE | VM_GROWSDOWN;
#endif
if ((vma->vm_flags & vm_req_flags) != vm_req_flags)
goto out;

mm->start_stack = addr;
break;

case PR_SET_MM_START_BRK:
if (addr <= mm->end_data)
goto out;

if (rlim < RLIM_INFINITY &&
(mm->brk - addr) +
(mm->end_data - mm->start_data) > rlim)
goto out;

mm->start_brk = addr;
break;

case PR_SET_MM_BRK:
if (addr <= mm->end_data)
goto out;

if (rlim < RLIM_INFINITY &&
(addr - mm->start_brk) +
(mm->end_data - mm->start_data) > rlim)
goto out;

mm->brk = addr;
break;

default:
error = -EINVAL;
goto out;
}

error = 0;

out:
up_read(&mm->mmap_sem);

return error;
}
#else /* CONFIG_CHECKPOINT_RESTORE */
static int prctl_set_mm(int opt, unsigned long addr,
unsigned long arg4, unsigned long arg5)
{
return -EINVAL;
}
#endif

SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
{
Expand Down Expand Up @@ -1841,6 +1959,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
error = PR_MCE_KILL_DEFAULT;
break;
case PR_SET_MM:
error = prctl_set_mm(arg2, arg3, arg4, arg5);
break;
default:
error = -EINVAL;
break;
Expand Down

0 comments on commit 38830a0

Please sign in to comment.