mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-05 19:31:57 -04:00
Merge remote-tracking branch 'sm8350/lineage-20' into lineage-23.2
* sm8350/lineage-20: UPSTREAM: tty: allow TIOCSLCKTRMIOS with CAP_CHECKPOINT_RESTORE UPSTREAM: selftests: add clone3() CAP_CHECKPOINT_RESTORE test UPSTREAM: prctl: exe link permission error changed from -EINVAL to -EPERM UPSTREAM: prctl: Allow local CAP_CHECKPOINT_RESTORE to change /proc/self/exe UPSTREAM: proc: allow access in init userns for map_files with CAP_CHECKPOINT_RESTORE UPSTREAM: pid_namespace: use checkpoint_restore_ns_capable() for ns_last_pid UPSTREAM: pid: use checkpoint_restore_ns_capable() for set_tid UPSTREAM: capabilities: Introduce CAP_CHECKPOINT_RESTORE UPSTREAM: selftests: add tests for clone3() with *set_tid UPSTREAM: fork: extend clone3() to support setting a PID UPSTREAM: selftests: add tests for clone3() UPSTREAM: tests: test CLONE_CLEAR_SIGHAND UPSTREAM: clone3: add CLONE_CLEAR_SIGHAND Change-Id: I7890fb550e85b9fd4c0c3a27144d5bfd8963d496
This commit is contained in:
commit
5048089773
22 changed files with 1139 additions and 61 deletions
|
|
@ -1540,6 +1540,11 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
|
|||
spin_lock_irq(¤t->sighand->siglock);
|
||||
memcpy(sig->action, current->sighand->action, sizeof(sig->action));
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
/* Reset all signal handler not set to SIG_IGN to SIG_DFL. */
|
||||
if (clone_flags & CLONE_CLEAR_SIGHAND)
|
||||
flush_signal_handlers(tsk, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2161,7 +2166,8 @@ static __latent_entropy struct task_struct *copy_process(
|
|||
stackleak_task_init(p);
|
||||
|
||||
if (pid != &init_struct_pid) {
|
||||
pid = alloc_pid(p->nsproxy->pid_ns_for_children);
|
||||
pid = alloc_pid(p->nsproxy->pid_ns_for_children, args->set_tid,
|
||||
args->set_tid_size);
|
||||
if (IS_ERR(pid)) {
|
||||
retval = PTR_ERR(pid);
|
||||
goto bad_fork_cleanup_thread;
|
||||
|
|
@ -2659,6 +2665,7 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
|
|||
{
|
||||
int err;
|
||||
struct clone_args args;
|
||||
pid_t *kset_tid = kargs->set_tid;
|
||||
|
||||
if (unlikely(usize > PAGE_SIZE))
|
||||
return -E2BIG;
|
||||
|
|
@ -2669,6 +2676,15 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (unlikely(args.set_tid_size > MAX_PID_NS_LEVEL))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(!args.set_tid && args.set_tid_size > 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(args.set_tid && args.set_tid_size == 0))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Verify that higher 32bits of exit_signal are unset and that
|
||||
* it is a valid signal
|
||||
|
|
@ -2686,8 +2702,16 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
|
|||
.stack = args.stack,
|
||||
.stack_size = args.stack_size,
|
||||
.tls = args.tls,
|
||||
.set_tid_size = args.set_tid_size,
|
||||
};
|
||||
|
||||
if (args.set_tid &&
|
||||
copy_from_user(kset_tid, u64_to_user_ptr(args.set_tid),
|
||||
(kargs->set_tid_size * sizeof(pid_t))))
|
||||
return -EFAULT;
|
||||
|
||||
kargs->set_tid = kset_tid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2721,11 +2745,8 @@ static inline bool clone3_stack_valid(struct kernel_clone_args *kargs)
|
|||
|
||||
static bool clone3_args_valid(struct kernel_clone_args *kargs)
|
||||
{
|
||||
/*
|
||||
* All lower bits of the flag word are taken.
|
||||
* Verify that no other unknown flags are passed along.
|
||||
*/
|
||||
if (kargs->flags & ~CLONE_LEGACY_FLAGS)
|
||||
/* Verify that no unknown flags are passed along. */
|
||||
if (kargs->flags & ~(CLONE_LEGACY_FLAGS | CLONE_CLEAR_SIGHAND))
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
|
@ -2735,6 +2756,10 @@ static bool clone3_args_valid(struct kernel_clone_args *kargs)
|
|||
if (kargs->flags & (CLONE_DETACHED | CSIGNAL))
|
||||
return false;
|
||||
|
||||
if ((kargs->flags & (CLONE_SIGHAND | CLONE_CLEAR_SIGHAND)) ==
|
||||
(CLONE_SIGHAND | CLONE_CLEAR_SIGHAND))
|
||||
return false;
|
||||
|
||||
if ((kargs->flags & (CLONE_THREAD | CLONE_PARENT)) &&
|
||||
kargs->exit_signal)
|
||||
return false;
|
||||
|
|
@ -2761,6 +2786,9 @@ SYSCALL_DEFINE2(clone3, struct clone_args __user *, uargs, size_t, size)
|
|||
int err;
|
||||
|
||||
struct kernel_clone_args kargs;
|
||||
pid_t set_tid[MAX_PID_NS_LEVEL];
|
||||
|
||||
kargs.set_tid = set_tid;
|
||||
|
||||
err = copy_clone_args_from_user(&kargs, uargs, size);
|
||||
if (err)
|
||||
|
|
|
|||
70
kernel/pid.c
70
kernel/pid.c
|
|
@ -157,7 +157,8 @@ void free_pid(struct pid *pid)
|
|||
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 *set_tid,
|
||||
size_t set_tid_size)
|
||||
{
|
||||
struct pid *pid;
|
||||
enum pid_type type;
|
||||
|
|
@ -166,6 +167,17 @@ struct pid *alloc_pid(struct pid_namespace *ns)
|
|||
struct upid *upid;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
/*
|
||||
* set_tid_size contains the size of the set_tid array. Starting at
|
||||
* the most nested currently active PID namespace it tells alloc_pid()
|
||||
* which PID to set for a process in that most nested PID namespace
|
||||
* up to set_tid_size PID namespaces. It does not have to set the PID
|
||||
* for a process in all nested PID namespaces but set_tid_size must
|
||||
* never be greater than the current ns->level + 1.
|
||||
*/
|
||||
if (set_tid_size > ns->level + 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
|
||||
if (!pid)
|
||||
return ERR_PTR(retval);
|
||||
|
|
@ -174,24 +186,54 @@ struct pid *alloc_pid(struct pid_namespace *ns)
|
|||
pid->level = ns->level;
|
||||
|
||||
for (i = ns->level; i >= 0; i--) {
|
||||
int pid_min = 1;
|
||||
int tid = 0;
|
||||
|
||||
if (set_tid_size) {
|
||||
tid = set_tid[ns->level - i];
|
||||
|
||||
retval = -EINVAL;
|
||||
if (tid < 1 || tid >= pid_max)
|
||||
goto out_free;
|
||||
/*
|
||||
* Also fail if a PID != 1 is requested and
|
||||
* no PID 1 exists.
|
||||
*/
|
||||
if (tid != 1 && !tmp->child_reaper)
|
||||
goto out_free;
|
||||
retval = -EPERM;
|
||||
if (!checkpoint_restore_ns_capable(tmp->user_ns))
|
||||
goto out_free;
|
||||
set_tid_size--;
|
||||
}
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
spin_lock_irq(&pidmap_lock);
|
||||
|
||||
/*
|
||||
* init really needs pid 1, but after reaching the maximum
|
||||
* wrap back to RESERVED_PIDS
|
||||
*/
|
||||
if (idr_get_cursor(&tmp->idr) > RESERVED_PIDS)
|
||||
pid_min = RESERVED_PIDS;
|
||||
if (tid) {
|
||||
nr = idr_alloc(&tmp->idr, NULL, tid,
|
||||
tid + 1, GFP_ATOMIC);
|
||||
/*
|
||||
* If ENOSPC is returned it means that the PID is
|
||||
* alreay in use. Return EEXIST in that case.
|
||||
*/
|
||||
if (nr == -ENOSPC)
|
||||
nr = -EEXIST;
|
||||
} else {
|
||||
int pid_min = 1;
|
||||
/*
|
||||
* init really needs pid 1, but after reaching the
|
||||
* maximum wrap back to RESERVED_PIDS
|
||||
*/
|
||||
if (idr_get_cursor(&tmp->idr) > RESERVED_PIDS)
|
||||
pid_min = RESERVED_PIDS;
|
||||
|
||||
/*
|
||||
* Store a null pointer so find_pid_ns does not find
|
||||
* a partially initialized PID (see below).
|
||||
*/
|
||||
nr = idr_alloc_cyclic(&tmp->idr, NULL, pid_min,
|
||||
pid_max, GFP_ATOMIC);
|
||||
/*
|
||||
* Store a null pointer so find_pid_ns does not find
|
||||
* a partially initialized PID (see below).
|
||||
*/
|
||||
nr = idr_alloc_cyclic(&tmp->idr, NULL, pid_min,
|
||||
pid_max, GFP_ATOMIC);
|
||||
}
|
||||
spin_unlock_irq(&pidmap_lock);
|
||||
idr_preload_end();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@
|
|||
|
||||
static DEFINE_MUTEX(pid_caches_mutex);
|
||||
static struct kmem_cache *pid_ns_cachep;
|
||||
/* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */
|
||||
#define MAX_PID_NS_LEVEL 32
|
||||
/* Write once array, filled from the beginning. */
|
||||
static struct kmem_cache *pid_cache[MAX_PID_NS_LEVEL];
|
||||
|
||||
|
|
@ -272,7 +270,7 @@ static int pid_ns_ctl_handler(struct ctl_table *table, int write,
|
|||
struct ctl_table tmp = *table;
|
||||
int ret, next;
|
||||
|
||||
if (write && !ns_capable(pid_ns->user_ns, CAP_SYS_ADMIN))
|
||||
if (write && !checkpoint_restore_ns_capable(pid_ns->user_ns))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
|
|
|
|||
13
kernel/sys.c
13
kernel/sys.c
|
|
@ -2005,12 +2005,15 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data
|
|||
|
||||
if (prctl_map.exe_fd != (u32)-1) {
|
||||
/*
|
||||
* Make sure the caller has the rights to
|
||||
* change /proc/pid/exe link: only local sys admin should
|
||||
* be allowed to.
|
||||
* Check if the current user is checkpoint/restore capable.
|
||||
* At the time of this writing, it checks for CAP_SYS_ADMIN
|
||||
* or CAP_CHECKPOINT_RESTORE.
|
||||
* Note that a user with access to ptrace can masquerade an
|
||||
* arbitrary program as any executable, even setuid ones.
|
||||
* This may have implications in the tomoyo subsystem.
|
||||
*/
|
||||
if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN))
|
||||
return -EINVAL;
|
||||
if (!checkpoint_restore_ns_capable(current_user_ns()))
|
||||
return -EPERM;
|
||||
|
||||
error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd);
|
||||
if (error)
|
||||
|
|
|
|||
Loading…
Reference in a new issue