clone_extended() syscall
Subsystems (4)
v4 cover clone_extended() syscall
Define clone_extended() system call (previously known as clone_with_pids()). See patch 7/7 for details. (Other patches are same as before).
Changelog [v4]:
- Rename system call to clone_extended() and support 64bit clone-flags
- Rename 'struct target_pid_set' to 'struct pid_set'
A message that is not in the archive (sent off-list or not yet received): 20090806061056.GA1044-r/[email protected]
RFC PATCH v4 1/7 Factor out code to allocate pidmap page
Subject: [RFC][v4][PATCH 1/7] Factor out code to allocate pidmap page
To implement support for clone_with_pids() system call we would need to allocate pidmap page in more than one place. Move this code to a new function alloc_pidmap_page().
Changelog[v2]:
- (Matt Helsley, Dave Hansen) Have alloc_pidmap_page() return -ENOMEM on error instead of -1.
--- kernel/pid.c | 46 ++++++++++++++++++++++++++++++---------------- 1 files changed, 30 insertions(+), 16 deletions(-)
kernel/pid.c +30 -16
@@ -122,9 +122,34 @@atomic_inc (&map->nr_free); } +static int alloc_pidmap_page (struct pidmap *map) +{ +void *page; + +if (likely (map->page)) +return 0 ; + + page =kzalloc (PAGE_SIZE ,GFP_KERNEL ); + +/* +* Free the page if someone raced with us installing it: +*/ +spin_lock_irq (&pidmap_lock); +if (map->page) +kfree (page); +else + map->page = page; +spin_unlock_irq (&pidmap_lock); + +if (unlikely (!map->page)) +return -ENOMEM ; + +return 0 ; +} +static int alloc_pidmap (struct pid_namespace *pid_ns) { -int i, offset, max_scan, pid, last = pid_ns->last_pid; +int i, rc, offset, max_scan, pid, last = pid_ns->last_pid;struct pidmap *map; pid = last +1 ;
@@ -134,21 +159,10 @@ map = &pid_ns->pidmap[pid/BITS_PER_PAGE ]; max_scan = (pid_max +BITS_PER_PAGE -1 )/BITS_PER_PAGE - !offset;for (i =0 ; i <= max_scan; ++i) { -if (unlikely (!map->page)) { -void *page =kzalloc (PAGE_SIZE ,GFP_KERNEL ); -/* -* Free the page if someone raced with us -* installing it: -*/ -spin_lock_irq (&pidmap_lock); -if (map->page) -kfree (page); -else - map->page = page; -spin_unlock_irq (&pidmap_lock); -if (unlikely (!map->page)) -break ; - } + rc =alloc_pidmap_page (map); +if (rc) +break ; +if (likely (atomic_read (&map->nr_free))) { do { if (!test_and_set_bit(offset, map->page)) {
RFC PATCH v4 2/7 : Have alloc_pidmap() return actual error code
In reply to a message not in the archiveSubject: [RFC][v4][PATCH 2/7]: Have alloc_pidmap() return actual error code
alloc_pidmap() can fail either because all pid numbers are in use or because memory allocation failed. With support for setting a specific pid number, alloc_pidmap() would also fail if either the given pid number is invalid or in use.
Rather than have callers assume -ENOMEM, have alloc_pidmap() return the actual error.
--- kernel/fork.c | 5 +++-- kernel/pid.c | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-)
kernel/fork.c +3 -2
@@ -1124,10 +1124,11 @@ goto bad_fork_cleanup_io;if (pid != &init_struct_pid) { - retval = -ENOMEM ; pid =alloc_pid (p->nsproxy->pid_ns); -if (!pid) +if (IS_ERR (pid)) { + retval =PTR_ERR (pid); goto bad_fork_cleanup_io; + }if (clone_flags &CLONE_NEWPID ) { retval =pid_ns_prepare_proc (p->nsproxy->pid_ns);
kernel/pid.c +6 -3
@@ -158,6 +158,7 @@ offset = pid &BITS_PER_PAGE_MASK ; map = &pid_ns->pidmap[pid/BITS_PER_PAGE ]; max_scan = (pid_max +BITS_PER_PAGE -1 )/BITS_PER_PAGE - !offset; + rc = -EAGAIN ;for (i =0 ; i <= max_scan; ++i) { rc =alloc_pidmap_page (map);if (rc)
@@ -188,12 +189,14 @@ }else { map = &pid_ns->pidmap[0 ]; offset =RESERVED_PIDS ; -if (unlikely (last == offset)) +if (unlikely (last == offset)) { + rc = -EAGAIN ;break ; + } } pid =mk_pid (pid_ns, map, offset); } -return -1 ; +return rc; }int next_pidmap (struct pid_namespace *pid_ns,int last)
@@ -298,7 +301,7 @@free_pidmap (pid->numbers + i);kmem_cache_free (ns->pid_cachep, pid); - pid =NULL ; + pid =ERR_PTR (nr); goto out; }
RFC PATCH v4 3/7 : Add target_pid parameter to alloc_pidmap()
In reply to a message not in the archiveSubject: [RFC][v4][PATCH 3/7]: Add target_pid parameter to alloc_pidmap()
With support for setting a specific pid number for a process, alloc_pidmap() will need a paramter a 'target_pid' parameter.
Changelog[v2]:
- (Serge Hallyn) Check for 'pid < 0' in set_pidmap().(Code actually checks for 'pid <= 0' for completeness).
--- kernel/pid.c | 28 ++++++++++++++++++++++++++-- 1 files changed, 26 insertions(+), 2 deletions(-)
kernel/pid.c +26 -2
@@ -147,11 +147,35 @@return 0 ; } -static int alloc_pidmap (struct pid_namespace *pid_ns) +static int set_pidmap (struct pid_namespace *pid_ns,int pid) +{ +int offset; +struct pidmap *map; + +if (pid <=0 || pid >= pid_max) +return -EINVAL ; + + offset = pid &BITS_PER_PAGE_MASK ; + map = &pid_ns->pidmap[pid/BITS_PER_PAGE ]; + +if (alloc_pidmap_page (map)) +return -ENOMEM ; + +if (test_and_set_bit (offset, map->page)) +return -EBUSY ; + +atomic_dec (&map->nr_free); +return pid; +} + +static int alloc_pidmap (struct pid_namespace *pid_ns,int target_pid) {int i, rc, offset, max_scan, pid, last = pid_ns->last_pid;struct pidmap *map; +if (target_pid) +return set_pidmap (pid_ns, target_pid); + pid = last +1 ;if (pid >= pid_max) pid =RESERVED_PIDS ;
@@ -270,7 +294,7 @@ tmp = ns;for (i = ns->level; i >=0 ; i--) { - nr =alloc_pidmap (tmp); + nr =alloc_pidmap (tmp,0 );if (nr <0 ) goto out_free;
RFC PATCH v4 4/7 : Add target_pids parameter to alloc_pid()
In reply to a message not in the archiveSubject: [RFC][v4][PATCH 4/7]: Add target_pids parameter to alloc_pid()
This parameter is currently NULL, but will be used in a follow-on patch.
--- include/linux/pid.h | 2 +- kernel/fork.c | 3 ++- kernel/pid.c | 9 +++++++-- 3 files changed, 10 insertions(+), 4 deletions(-)
include/linux/pid.h +1 -1
@@ -119,7 +119,7 @@extern struct pid *find_ge_pid (int nr,struct pid_namespace *);int next_pidmap (struct pid_namespace *pid_ns,int last); -extern struct pid *alloc_pid (struct pid_namespace *ns); +extern struct pid *alloc_pid (struct pid_namespace *ns,pid_t *target_pids);extern void free_pid (struct pid *pid);/*
kernel/fork.c +2 -1
@@ -954,6 +954,7 @@int retval;struct task_struct *p;int cgroup_callbacks_done =0 ; +pid_t *target_pids =NULL ;if ((clone_flags & (CLONE_NEWNS |CLONE_FS )) == (CLONE_NEWNS |CLONE_FS ))return ERR_PTR (-EINVAL );
@@ -1124,7 +1125,7 @@ goto bad_fork_cleanup_io;if (pid != &init_struct_pid) { - pid =alloc_pid (p->nsproxy->pid_ns); + pid =alloc_pid (p->nsproxy->pid_ns, target_pids);if (IS_ERR (pid)) { retval =PTR_ERR (pid); goto bad_fork_cleanup_io;
kernel/pid.c +7 -2
@@ -280,13 +280,14 @@call_rcu (&pid->rcu, delayed_put_pid); } -struct pid *alloc_pid (struct pid_namespace *ns) +struct pid *alloc_pid (struct pid_namespace *ns,pid_t *target_pids) {struct pid *pid;enum pid_type type;int i, nr;struct pid_namespace *tmp;struct upid *upid; +int tpid; pid =kmem_cache_alloc (ns->pid_cachep,GFP_KERNEL );if (!pid)
@@ -294,7 +295,11 @@ tmp = ns;for (i = ns->level; i >=0 ; i--) { - nr =alloc_pidmap (tmp,0 ); + tpid =0 ; +if (target_pids) + tpid = target_pids[i]; + + nr =alloc_pidmap (tmp, tpid);if (nr <0 ) goto out_free;
RFC PATCH v4 5/7 : Add target_pids parameter to copy_process()
In reply to a message not in the archiveSubject: [RFC][v4][PATCH 5/7]: Add target_pids parameter to copy_process()
The new parameter will be used in a follow-on patch when clone_with_pids() is implemented.
--- kernel/fork.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-)
kernel/fork.c +4 -3
@@ -949,12 +949,12 @@unsigned long stack_size, int __user *child_tidptr, struct pid *pid, + pid_t *target_pids, int trace) { int retval;struct task_struct *p;int cgroup_callbacks_done =0 ; -pid_t *target_pids =NULL ;if ((clone_flags & (CLONE_NEWNS |CLONE_FS )) == (CLONE_NEWNS |CLONE_FS ))return ERR_PTR (-EINVAL );
@@ -1330,7 +1330,7 @@struct pt_regs regs; task =copy_process (CLONE_VM ,0 ,idle_regs (®s),0 ,NULL , - &init_struct_pid,0 ); + &init_struct_pid,NULL ,0 );if (!IS_ERR (task))init_idle (task, cpu);
@@ -1353,6 +1353,7 @@struct task_struct *p;int trace =0 ;long nr; +pid_t *target_pids =NULL ;/* * Do some preliminary argument and permissions checking before we
@@ -1393,7 +1394,7 @@ trace =tracehook_prepare_clone (clone_flags); p =copy_process (clone_flags, stack_start, regs, stack_size, - child_tidptr,NULL , trace); + child_tidptr,NULL , target_pids, trace);/* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly.
RFC PATCH v4 6/7 : Define do_fork_with_pids()
In reply to a message not in the archiveSubject: [RFC][v4][PATCH 6/7]: Define do_fork_with_pids()
do_fork_with_pids() is same as do_fork(), except that it takes an additional, 'pid_set', parameter. This parameter, currently unused, specifies the set of target pids of the process in each of its pid namespaces.
Changelog[v3]:
- Fix "long-line" warning from checkpatch.pl
Changelog[v2]:
- To facilitate moving architecture-inpdendent code to kernel/fork.c pass in 'struct target_pid_set __user *' to do_fork_with_pids() rather than 'pid_t *' (next patch moves the arch-independent code to kernel/fork.c)
--- include/linux/sched.h | 3 +++ include/linux/types.h | 5 +++++ kernel/fork.c | 16 ++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-)
include/linux/sched.h +3 -0
@@ -2053,6 +2053,9 @@extern int do_execve (char *,char __user *__user *,char __user *__user *,struct pt_regs *);extern long do_fork (unsigned long ,unsigned long ,struct pt_regs *,unsigned long ,int __user *,int __user *); +extern long do_fork_with_pids (unsigned long ,unsigned long ,struct pt_regs *, +unsigned long ,int __user *,int __user *, +struct pid_set __user *pid_set);struct task_struct *fork_idle (int );extern void set_task_comm (struct task_struct *tsk,char *from);
include/linux/types.h +5 -0
@@ -204,6 +204,11 @@char f_fpack[6 ]; }; +struct pid_set { +int num_pids; +pid_t *pids; +}; +#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ #endif /* _LINUX_TYPES_H */
kernel/fork.c +14 -2
@@ -1343,12 +1343,13 @@* It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ -long do_fork (unsigned long clone_flags, +long do_fork_with_pids (unsigned long clone_flags,unsigned long stack_start,struct pt_regs *regs,unsigned long stack_size,int __user *parent_tidptr, -int __user *child_tidptr) +int __user *child_tidptr, +struct pid_set __user *pid_setp) {struct task_struct *p;int trace =0 ;
@@ -1451,6 +1452,17 @@return nr; } +long do_fork (unsigned long clone_flags, +unsigned long stack_start, +struct pt_regs *regs, +unsigned long stack_size, +int __user *parent_tidptr, +int __user *child_tidptr) +{ +return do_fork_with_pids (clone_flags, stack_start, regs, stack_size, + parent_tidptr, child_tidptr,NULL ); +} +#ifndef ARCH_MIN_MMSTRUCT_ALIGN #define ARCH_MIN_MMSTRUCT_ALIGN 0#endif
RFC PATCH v4 7/7 : Define clone_extended() syscall
In reply to a message not in the archiveSubject: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
Container restart requires that a task have the same pid it had when it was checkpointed. When containers are nested the tasks within the containers exist in multiple pid namespaces and hence have multiple pids to specify during restart.
This patch defines, a new system call, clone_extended() which is like clone(), but takes a new 'pid_set' parameter. This parameter lets caller choose specific pid numbers for the child process, in the process's active and ancestor pid namespaces. (Descendant pid namespaces in general don't matter since processes don't have pids in them anyway, but see comments in copy_target_pids() regarding CLONE_NEWPID).
Unlike clone(), however, clone_extended() needs CAP_SYS_ADMIN, at least for now, to prevent unprivileged processes from misusing this interface.
While the main motivation for this interface is the need to let a process choose its 'pid numbers', the clone_extended() interface uses 64-bit clone flags. The 'higher' portion of the clone flags are unused and are only included to preclude yet another version of clone when a new clone flag is needed.
===== Interface:
Compared to clone(), clone_extended() needs to pass in three more pieces of information:
- additional 32-bit of clone_flags
- number of pids in the set
- user buffer containing the list of pids.
But since clone() already takes 5 parameters and some (all ?) architectures are restricted to 6 parameters to a system-call, additional data-structures (and copy_from_user()) are needed.
The proposed interface for clone_extended() is:
struct clone_tid_info {
void *parent_tid; /* parent_tid_ptr parameter */
void *child_tid; /* child_tid_ptr parameter */
};
struct pid_set {
int num_pids;
pid_t *pids;
};
int clone_extended(int flags_low, int flags_high, void *child_stack,
void *unused, struct clone_tid_info *tid_ptrs,
struct pid_set *pid_setp);where:
- flags_low corresponds to the 'flags' parameter in normal clone().
- flags_high is currently unused and meant to be used if/when a new clone flag is needed.
- 'tid_ptrs' is rather an aribtrary grouping of parameters to keep total parameter count to 6
- pid_setp specifies the pid-numbers for the process in the different pid namespaces (discussed further below). We expect 'struct pid_set' to be useful in other contexts.
- if pid_setp is NULL and flags_high is 0, clone_extended() behaves like normal clone(), except for an extra copy_from_user() when 'tid_ptrs' is non-NULL.
===== Usage:
int flags_low = (CLONE_FS|CLONE_VM|SIGCHLD);
int flags_high = 0; // unused
pid_t pids[] = { 0, 77, 99 };
struct pid_set pid_set;
int parent_tid;
int child_tid;
struct clone_tid_info tid_ptrs = {&parent_tid, &child_tid};
pid_set.num_pids = sizeof(pids) / sizeof(int);
pid_set.pids = &pids;
syscall(__NR_clone_extended, flags_low, flags_high, stack,
NULL, &tid_ptrs, &pid_set);===== Notes on 'struct pid_set' parameter
When pid_set is specified and a target-pid (i.e pid_set.pids[i]) is 0, the kernel continues to assign a pid for the process in that namespace.
In the above example, pids[0] is 0, meaning the kernel will assign next available pid to the process in init_pid_ns.
But kernel will assign pid 77 in the child pid namespace 1 and pid 99 in pid namespace 2. If either 77 or 99 are taken, the system call fails with -EBUSY.
If 'pid_set.num_pids' exceeds the current nesting level of pid namespaces, the system call fails with -EINVAL.
TODO:
- Its mostly an exploratory patch seeking feedback on the interface.
- Gently tested.
- May need additional sanity checks in do_fork_with_pids().
Changelog[v4]:
(address following comments from Serge Hallyn, Oren Laadan).
- Rename interface from clone_with_pids() to clone_extended()
- Add support for clone_flags (define/use 'struct clone_tid_info')
- Rename 'target_pid_set' to simply 'pid_set' since pid_set may be useful in other contexts.
Changelog[v3]:
- (Oren Laadan) Allow CLONE_NEWPID flag (by allocating an extra pid in the target_pids[] list and setting it 0. See copy_target_pids()).
- (Oren Laadan) Specified target pids should apply only to youngest pid-namespaces (see copy_target_pids())
- (Matt Helsley) Update patch description.
Changelog[v2]:
- Remove unnecessary printk and add a note to callers of copy_target_pids() to free target_pids.
- (Serge Hallyn) Mention CAP_SYS_ADMIN restriction in patch description.
- (Oren Laadan) Add checks for 'num_pids < 0' (return -EINVAL) and 'num_pids == 0' (fall back to normal clone()).
- Move arch-independent code (sanity checks and copy-in of target-pids) into kernel/fork.c and simplify sys_clone_with_pids()
Changelog[v1]:
- Fixed some compile errors (had fixed these errors earlier in my git tree but had not refreshed patches before emailing them)
--- arch/x86/include/asm/syscalls.h | 2 + arch/x86/include/asm/unistd_32.h | 1 + arch/x86/kernel/entry_32.S | 1 + arch/x86/kernel/process_32.c | 21 +++++++ arch/x86/kernel/syscall_table_32.S | 1 + kernel/fork.c | 108 +++++++++++++++++++++++++++++++++++- 6 files changed, 133 insertions(+), 1 deletions(-)
arch/x86/include/asm/syscalls.h +2 -0
@@ -40,6 +40,8 @@/* kernel/process_32.c */ int sys_clone (struct pt_regs *); +int sys_clone_extended (struct pt_regs *); +int sys_vfork (struct pt_regs *);int sys_execve (struct pt_regs *);/* kernel/signal.c */
arch/x86/include/asm/unistd_32.h +1 -0
@@ -342,6 +342,7 @@#define __NR_pwritev 334#define __NR_rt_tgsigqueueinfo 335#define __NR_perf_counter_open 336 +#define __NR_clone_extended 337#ifdef __KERNEL__
arch/x86/kernel/entry_32.S +1 -0
@@ -718,6 +718,7 @@ PTREGSCALL(iopl) PTREGSCALL(fork) PTREGSCALL(clone) +PTREGSCALL(clone_extended) PTREGSCALL(vfork) PTREGSCALL(execve) PTREGSCALL(sigaltstack)
arch/x86/kernel/process_32.c +38 -0
@@ -443,6 +443,44 @@return do_fork (clone_flags, newsp, regs,0 , parent_tidptr, child_tidptr); } +int sys_clone_extended (struct pt_regs *regs) +{ +unsigned long clone_flags_low; +unsigned long clone_flags_high; +int __user *utids; +struct clone_tid_info ktids; +unsigned long newsp; +int __user *parent_tidptr; +int __user *child_tidptr; +void __user *upid_setp; + + clone_flags_low = regs->bx; +/* +* clone_flags_high unused for now. If additional clone flags +* are defined, this could be used +*/ + clone_flags_high = regs->cx; + newsp = regs->dx; + utids = (int __user *)regs->di; + upid_setp = (void __user *)regs->bp; + +if (!newsp) + newsp = regs->sp; + + parent_tidptr =NULL ; + child_tidptr =NULL ; +if (utids) { +int n =sizeof (struct clone_tid_info ); +if (copy_from_user (&ktids, utids, n)) +return -EFAULT ; + parent_tidptr = ktids.parent_tid; + child_tidptr = ktids.child_tid; + } + +return do_fork_with_pids (clone_flags_low, newsp, regs,0 , parent_tidptr, + child_tidptr, upid_setp); +} +/* * sys_execve() executes a new program. */
arch/x86/kernel/syscall_table_32.S +1 -0
@@ -336,3 +336,4 @@ .long sys_pwritev .long sys_rt_tgsigqueueinfo /* 335 */ .long sys_perf_counter_open + .long ptregs_clone_extended
kernel/fork.c +107 -1
132 lines not on this page · raw message
include/linux/types.h +5 -0
@@ -209,6 +209,11 @@pid_t *pids; }; +struct clone_tid_info { +void *parent_tid; +void *child_tid; +}; +#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ #endif /* _LINUX_TYPES_H */
A message that is not in the archive (sent off-list or not yet received): 20090806062505.GG5619-r/[email protected]
Re: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
Quoted 15 lines · Sukadev Bhattiprolu
Subject: [RFC][v4][PATCH 7/7]: Define
clone_extended()syscallContainer restart requires that a task have the same pid it had when it was checkpointed. When containers are nested the tasks within the containers exist in multiple pid namespaces and hence have multiple pids to specify during restart.
This patch defines, a new system call,
clone_extended()which is likeclone(), but takes a new 'pid_set' parameter. This parameter lets caller choose specific pid numbers for the child process, in the process's active and ancestor pid namespaces. (Descendant pid namespaces in general don't matter since processes don't have pids in them anyway, but see comments incopy_target_pids()regardingCLONE_NEWPID).
Quoted 2 lines
Unlike
clone(), however,clone_extended()needsCAP_SYS_ADMIN, at least for now, to prevent unprivileged processes from misusing this interface.
It only needs that when specifying pids.
Quoted 21 lines
While the main motivation for this interface is the need to let a process choose its 'pid numbers', the
clone_extended()interface uses 64-bit clone flags. The 'higher' portion of the clone flags are unused and are only included to preclude yet another version of clone when a new clone flag is needed.===== Interface:
Compared to
clone(),clone_extended()needs to pass in three more pieces of information:- additional 32-bit of
clone_flags
- number of pids in the set
- user buffer containing the list of pids.But since
clone()already takes 5 parameters and some (all ?) architectures are restricted to 6 parameters to a system-call, additional data-structures (andcopy_from_user()) are needed.The proposed interface for
clone_extended()is:
Quoted 13 lines
struct clone_tid_info {
void *parent_tid; /* parent_tid_ptr parameter */
void *child_tid; /* child_tid_ptr parameter */
};
struct pid_set {
int num_pids;
pid_t *pids;
};
int clone_extended(int flags_low, int flags_high, void *child_stack,
void *unused, struct clone_tid_info *tid_ptrs,
struct pid_set *pid_setp);I was thinking additional flags would be passed in the (renamed) struct pid_set.
-serge
A message that is not in the archive (sent off-list or not yet received): 20090806133847.GA28392-r/[email protected]
Re: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
Quoted 51 lines · Serge E. Hallyn
Quoted 14 lines · Sukadev Bhattiprolu
Subject: [RFC][v4][PATCH 7/7]: Define
clone_extended()syscallContainer restart requires that a task have the same pid it had when it was checkpointed. When containers are nested the tasks within the containers exist in multiple pid namespaces and hence have multiple pids to specify during restart.
This patch defines, a new system call,
clone_extended()which is likeclone(), but takes a new 'pid_set' parameter. This parameter lets caller choose specific pid numbers for the child process, in the process's active and ancestor pid namespaces. (Descendant pid namespaces in general don't matter since processes don't have pids in them anyway, but see comments incopy_target_pids()regardingCLONE_NEWPID).Quoted 2 lines
Unlike
clone(), however,clone_extended()needsCAP_SYS_ADMIN, at least for now, to prevent unprivileged processes from misusing this interface.It only needs that when specifying pids.
Quoted 31 lines
While the main motivation for this interface is the need to let a process choose its 'pid numbers', the
clone_extended()interface uses 64-bit clone flags. The 'higher' portion of the clone flags are unused and are only included to preclude yet another version of clone when a new clone flag is needed.===== Interface:
Compared to
clone(),clone_extended()needs to pass in three more pieces of information:- additional 32-bit of
clone_flags
- number of pids in the set
- user buffer containing the list of pids.But since
clone()already takes 5 parameters and some (all ?) architectures are restricted to 6 parameters to a system-call, additional data-structures (andcopy_from_user()) are needed.The proposed interface for
clone_extended()is:struct clone_tid_info { void *parent_tid; /* parent_tid_ptr parameter */ void *child_tid; /* child_tid_ptr parameter */ }; struct pid_set { int num_pids; pid_t *pids; };
Quoted 6 lines
Quoted 3 lines
int clone_extended(int
flags_low, intflags_high, void*child_stack,
void *unused, structclone_tid_info*tid_ptrs, structpid_set*pid_setp);I was thinking additional flags would be passed in the (renamed) struct
pid_set.
Yes.
But maybe in (renamed) 'struct clone_info' instead of 'struct pid_set' ?
I vaguely recall a strong preference to not require copy-from-user during a fast-path clone, because it may hurt performance.
*If* this is the case, then maybe place extra flags among the "base" args, or at least a CLONE_EXTRA would indicate that more arguments need to be pulled from user-space ?
Do you intend to get feedback from LKML too ?
Oren.
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
Quoted 63 lines · Oren Laadan
Quoted 51 lines · Serge E. Hallyn
Quoted 14 lines · Sukadev Bhattiprolu
Subject: [RFC][v4][PATCH 7/7]: Define
clone_extended()syscallContainer restart requires that a task have the same pid it had when it was checkpointed. When containers are nested the tasks within the containers exist in multiple pid namespaces and hence have multiple pids to specify during restart.
This patch defines, a new system call,
clone_extended()which is likeclone(), but takes a new 'pid_set' parameter. This parameter lets caller choose specific pid numbers for the child process, in the process's active and ancestor pid namespaces. (Descendant pid namespaces in general don't matter since processes don't have pids in them anyway, but see comments incopy_target_pids()regardingCLONE_NEWPID).Quoted 2 lines
Unlike
clone(), however,clone_extended()needsCAP_SYS_ADMIN, at least for now, to prevent unprivileged processes from misusing this interface.It only needs that when specifying pids.
Quoted 31 lines
While the main motivation for this interface is the need to let a process choose its 'pid numbers', the
clone_extended()interface uses 64-bit clone flags. The 'higher' portion of the clone flags are unused and are only included to preclude yet another version of clone when a new clone flag is needed.===== Interface:
Compared to
clone(),clone_extended()needs to pass in three more pieces of information:- additional 32-bit of
clone_flags
- number of pids in the set
- user buffer containing the list of pids.But since
clone()already takes 5 parameters and some (all ?) architectures are restricted to 6 parameters to a system-call, additional data-structures (andcopy_from_user()) are needed.The proposed interface for
clone_extended()is:struct clone_tid_info { void *parent_tid; /* parent_tid_ptr parameter */ void *child_tid; /* child_tid_ptr parameter */ }; struct pid_set { int num_pids; pid_t *pids; };Quoted 6 lines
Quoted 3 lines
int clone_extended(int
flags_low, intflags_high, void*child_stack,
void *unused, structclone_tid_info*tid_ptrs, structpid_set*pid_setp);I was thinking additional flags would be passed in the (renamed) struct
pid_set.Yes.
Quoted 8 lines
But maybe in (renamed) 'struct
clone_info' instead of 'structpid_set' ?I vaguely recall a strong preference to not require copy-from-user during a fast-path clone, because it may hurt performance.
*If* this is the case, then maybe place extra flags among the "base" args, or at least a
CLONE_EXTRAwould indicate that more arguments need to be pulled from user-space ?
Wouldn't passing NULL for struct clone_info suffice?
Quoted 3 lines
Do you intend to get feedback from LKML too ?
Oren.
A message that is not in the archive (sent off-list or not yet received): 20090806155520.GA904-r/[email protected]
Re: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
Quoted 62 lines · Serge E. Hallyn
Quoted 61 lines · Oren Laadan
Quoted 50 lines · Serge E. Hallyn
Quoted 14 lines · Sukadev Bhattiprolu
Subject: [RFC][v4][PATCH 7/7]: Define
clone_extended()syscallContainer restart requires that a task have the same pid it had when it was checkpointed. When containers are nested the tasks within the containers exist in multiple pid namespaces and hence have multiple pids to specify during restart.
This patch defines, a new system call,
clone_extended()which is likeclone(), but takes a new 'pid_set' parameter. This parameter lets caller choose specific pid numbers for the child process, in the process's active and ancestor pid namespaces. (Descendant pid namespaces in general don't matter since processes don't have pids in them anyway, but see comments incopy_target_pids()regardingCLONE_NEWPID).Quoted 2 lines
Unlike
clone(), however,clone_extended()needsCAP_SYS_ADMIN, at least for now, to prevent unprivileged processes from misusing this interface.It only needs that when specifying pids.
Quoted 31 lines
While the main motivation for this interface is the need to let a process choose its 'pid numbers', the
clone_extended()interface uses 64-bit clone flags. The 'higher' portion of the clone flags are unused and are only included to preclude yet another version of clone when a new clone flag is needed.===== Interface:
Compared to
clone(),clone_extended()needs to pass in three more pieces of information:- additional 32-bit of
clone_flags
- number of pids in the set
- user buffer containing the list of pids.But since
clone()already takes 5 parameters and some (all ?) architectures are restricted to 6 parameters to a system-call, additional data-structures (andcopy_from_user()) are needed.The proposed interface for
clone_extended()is:struct clone_tid_info { void *parent_tid; /* parent_tid_ptr parameter */ void *child_tid; /* child_tid_ptr parameter */ }; struct pid_set { int num_pids; pid_t *pids; };Quoted 5 lines
Quoted 3 lines
int clone_extended(int
flags_low, intflags_high, void*child_stack,
void *unused, structclone_tid_info*tid_ptrs, structpid_set*pid_setp);I was thinking additional flags would be passed in the (renamed) struct
pid_set.Yes.
But maybe in (renamed) 'struct
clone_info' instead of 'structpid_set' ?
Quoted 8 lines
Quoted 6 lines
I vaguely recall a strong preference to not require copy-from-user during a fast-path clone, because it may hurt performance.
*If* this is the case, then maybe place extra flags among the "base" args, or at least a
CLONE_EXTRAwould indicate that more arguments need to be pulled from user-space ?Wouldn't passing NULL for struct
clone_infosuffice?
:o
Actually, I misread the original prototype, and I prefer Suka's current suggestion.
Oren.
Quoted 4 lines
Quoted 4 lines
Do you intend to get feedback from LKML too ?
Oren.
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
Quoted 28 lines · Oren Laadan
Quoted 28 lines
Quoted 27 lines
Quoted 12 lines
Quoted 12 lines
The proposed interface for
clone_extended()is:struct clone_tid_info { void *parent_tid; /* parent_tid_ptr parameter */ void *child_tid; /* child_tid_ptr parameter */ }; struct pid_set { int num_pids; pid_t *pids; };Quoted 5 lines
Quoted 3 lines
int clone_extended(int
flags_low, intflags_high, void*child_stack,
void *unused, structclone_tid_info*tid_ptrs, structpid_set*pid_setp);I was thinking additional flags would be passed in the (renamed) struct
pid_set.Yes.
But maybe in (renamed) 'struct
clone_info' instead of 'structpid_set' ?I vaguely recall a strong preference to not require copy-from-user during a fast-path clone, because it may hurt performance.
*If* this is the case, then maybe place extra flags among the "base" args, or at least a
CLONE_EXTRAwould indicate that more arguments need to be pulled from user-space ?
Quoted 6 lines
Quoted 1 line
Wouldn't passing NULL for struct
clone_infosuffice?:o
Actually, I misread the original prototype, and I prefer Suka's current suggestion.
I think Suka's suggestion is again inherently limited (in # of clone flags) and will force even uglier syscalls for each arch than the previous one already does.
-serge
A message that is not in the archive (sent off-list or not yet received): 20090806161616.GA1472-r/[email protected]
Re: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
| I think Suka's suggestion is again inherently limited (in # of | clone flags) and will force even uglier syscalls for each arch than the | previous one already does. |
Yes other architectures are forced to ignore the flags_high and copy-in the tid pointers.
But if we want more than 64 bit flags, we may need follow the sigset_t model ?
Also, I am listing three approaches below. Do you prefer #2 below ?
1. =====
struct clone_tid_info {
void *parent_tid; /* parent_tid_ptr parameter */
void *child_tid; /* child_tid_ptr parameter */
};
struct pid_set {
int num_pids;
pid_t *pids;
};
int clone_extended(int flags_low, int flags_high, void *child_stack,
void *unused, struct clone_tid_info *tid_ptrs,
struct pid_set *pid_setp);2. ======
struct clone_info {
int flags_high;
struct pid_set pid_set;
}
int clone_extended(int flags_low, void *child_stack, void *unused,
int *parent_tid, int *child_tid, struct clone_info *clone_info);
Pros:
- copy_from_user() needed only for new flags and pid_set
Cons:
- splitting the high and low clone-flags is awkward ?3. =====
typedef struct {
unsigned long flags[N_CLONE_FLAGS];
} clone_flags_t;
int clone_extended(clone_flags_t *flags, void *child_stack, int *unused,
int *parent_tid, int *child_tid, struct pid_set *pid_set);
Pros:
- extendible clone_flags (like sigset_t)
- no copy_from_user() when we have 32 clone-flags
- no copy_from_user for tids
Cons:
- copy_from_user() needed on 32-bit architectures for all flags when they exceed 32.
Sukadev
A message that is not in the archive (sent off-list or not yet received): 20090806182340.GA2579-r/[email protected]
Re: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
Quoted 5 lines · Sukadev Bhattiprolu
| I think Suka's suggestion is again inherently limited (in # of | clone flags) and will force even uglier syscalls for each arch than the | previous one already does. |
Quoted 7 lines
Yes other architectures are forced to ignore the
flags_highand copy-in the tid pointers.But if we want more than 64 bit flags, we may need follow the
sigset_tmodel ?Also, I am listing three approaches below. Do you prefer #2 below ?
I prefer #2 with 'struct pid_set' renamed to clone_ext_data or something, and either a version # or int num_clone_words so we can add clone flags later. I know, adding more then 32 more clone flags seems unlikely, but...
Quoted 54 lines
1. =====
struct clone_tid_info { void *parent_tid; /* parent_tid_ptr parameter */ void *child_tid; /* child_tid_ptr parameter */ }; struct pid_set { int num_pids; pid_t *pids; }; int clone_extended(int flags_low, int flags_high, void *child_stack, void *unused, struct clone_tid_info *tid_ptrs, struct pid_set *pid_setp);2. ======
struct clone_info { int flags_high; struct pid_set pid_set; } int clone_extended(int flags_low, void *child_stack, void *unused, int *parent_tid, int *child_tid, struct clone_info *clone_info); Pros: - copy_from_user() needed only for new flags and pid_set Cons: - splitting the high and low clone-flags is awkward ?3. =====
typedef struct {
unsigned long flags[N_CLONE_FLAGS];
}clone_flags_t;int clone_extended(clone_flags_t *flags, void
*child_stack, int *unused,
int*parent_tid, int*child_tid, structpid_set*pid_set);Pros:
- extendibleclone_flags(likesigset_t)
- nocopy_from_user()when we have 32 clone-flags
- nocopy_from_userfor tidsCons:
-copy_from_user()needed on 32-bit architectures for all flags when they exceed 32.Sukadev
Re: [RFC][v4][PATCH 7/7]: Define clone_extended() syscall
In reply to a message not in the archiveQuoted 15 lines · Sukadev Bhattiprolu
Subject: [RFC][v4][PATCH 7/7]: Define
clone_extended()syscallContainer restart requires that a task have the same pid it had when it was checkpointed. When containers are nested the tasks within the containers exist in multiple pid namespaces and hence have multiple pids to specify during restart.
This patch defines, a new system call,
clone_extended()which is likeclone(), but takes a new 'pid_set' parameter. This parameter lets caller choose specific pid numbers for the child process, in the process's active and ancestor pid namespaces. (Descendant pid namespaces in general don't matter since processes don't have pids in them anyway, but see comments incopy_target_pids()regardingCLONE_NEWPID).
Quoted 2 lines
Unlike
clone(), however,clone_extended()needsCAP_SYS_ADMIN, at least for now, to prevent unprivileged processes from misusing this interface.
It might be good to describe how, without CAP_SYS_ADMIN, the interface could be misused (I believe this was Linus' point):
In the status quo, a malicious task must fork rapidly in order to obtain by trial-and-error the same pid as found in a stale /var/run/foo.pid file. Without CAP_SYS_ADMIN clone_extended() would remove the trial-and-error element that loosely protects the system from such malicious attacks.
Cheers,
-Matt