| 1 | |
| 2 |
|
| 3 | #include <linux/init.h>
|
| 4 | #include <linux/rcupdate.h>
|
| 5 | #include <linux/refcount.h>
|
| 6 | #include <linux/sched.h>
|
| 7 | #include <linux/sched/coredump.h>
|
| 8 | #include <linux/sched/exec_state.h>
|
| 9 | #include <linux/sched/signal.h>
|
| 10 | #include <linux/slab.h>
|
| 11 | #include <linux/user_namespace.h>
|
| 12 |
|
| 13 | static struct kmem_cache *task_exec_state_cachep;
|
| 14 |
|
| 15 | static void __free_task_exec_state(struct rcu_head *rcu)
|
| 16 | {
|
| 17 | struct task_exec_state *exec_state = container_of(rcu, struct task_exec_state, rcu);
|
| 18 |
|
| 19 | put_user_ns(exec_state->user_ns);
|
| 20 | kmem_cache_free(task_exec_state_cachep, exec_state);
|
| 21 | }
|
| 22 |
|
| 23 | void put_task_exec_state(struct task_exec_state *exec_state)
|
| 24 | {
|
| 25 | if (exec_state && refcount_dec_and_test(&exec_state->count))
|
| 26 | call_rcu(&exec_state->rcu, __free_task_exec_state);
|
| 27 | }
|
| 28 |
|
| 29 | struct task_exec_state *alloc_task_exec_state(struct user_namespace *user_ns)
|
| 30 | {
|
| 31 | struct task_exec_state *exec_state;
|
| 32 |
|
| 33 | exec_state = kmem_cache_alloc(task_exec_state_cachep, GFP_KERNEL);
|
| 34 | if (!exec_state)
|
| 35 | return NULL;
|
| 36 | refcount_set(&exec_state->count, 1);
|
| 37 | exec_state->dumpable = TASK_DUMPABLE_OFF;
|
| 38 | exec_state->user_ns = get_user_ns(user_ns);
|
| 39 | return exec_state;
|
| 40 | }
|
| 41 |
|
| 42 | struct task_exec_state *task_exec_state_rcu(const struct task_struct *tsk)
|
| 43 | {
|
| 44 | struct task_exec_state *exec_state;
|
| 45 |
|
| 46 | exec_state = rcu_dereference_check(tsk->exec_state,
|
| 47 | lockdep_is_held(&tsk->alloc_lock));
|
| 48 | WARN_ON_ONCE(!exec_state);
|
| 49 | return exec_state;
|
| 50 | }
|
| 51 |
|
| 52 | struct task_exec_state *task_exec_state_replace(struct task_struct *tsk,
|
| 53 | struct task_exec_state *exec_state)
|
| 54 | {
|
| 55 | |
| 56 | * Updates must hold both locks so callers needing a consistent
|
| 57 | * snapshot of mm + dumpability are covered.
|
| 58 |
|
| 59 | lockdep_assert_held(&tsk->alloc_lock);
|
| 60 | lockdep_assert_held_write(&tsk->signal->exec_update_lock);
|
| 61 |
|
| 62 | return rcu_replace_pointer(tsk->exec_state, exec_state, true);
|
| 63 | }
|
| 64 |
|
| 65 | |
| 66 | * The non-CLONE_VM clone path: allocate a fresh exec_state and
|
| 67 | * inherit the parent's dumpable mode and user_ns reference. CLONE_VM
|
| 68 | * siblings refcount-share via copy_exec_state() in fork.c; only this
|
| 69 | * path and execve() ever allocate.
|
| 70 |
|
| 71 | int task_exec_state_copy(struct task_struct *tsk)
|
| 72 | {
|
| 73 | struct task_exec_state *src, *dst;
|
| 74 |
|
| 75 | src = rcu_dereference_protected(current->exec_state, true);
|
| 76 | dst = alloc_task_exec_state(src->user_ns);
|
| 77 | if (!dst)
|
| 78 | return -ENOMEM;
|
| 79 | dst->dumpable = READ_ONCE(src->dumpable);
|
| 80 | rcu_assign_pointer(tsk->exec_state, dst);
|
| 81 | return 0;
|
| 82 | }
|
| 83 |
|
| 84 | |
| 85 | * Store TASK_DUMPABLE_* on current->exec_state. All callers
|
| 86 | * (commit_creds, begin_new_exec, prctl(PR_SET_DUMPABLE)) act on the
|
| 87 | * running task, which guarantees ->exec_state is allocated and cannot
|
| 88 | * be replaced under us.
|
| 89 |
|
| 90 | void task_exec_state_set_dumpable(enum task_dumpable value)
|
| 91 | {
|
| 92 | struct task_exec_state *exec_state;
|
| 93 |
|
| 94 | if (WARN_ON_ONCE(value > TASK_DUMPABLE_ROOT))
|
| 95 | value = TASK_DUMPABLE_OFF;
|
| 96 |
|
| 97 | exec_state = rcu_dereference_protected(current->exec_state, true);
|
| 98 |
|
| 99 | if (WARN_ON_ONCE(exec_state == &init_task_exec_state))
|
| 100 | return;
|
| 101 | WRITE_ONCE(exec_state->dumpable, value);
|
| 102 | }
|
| 103 |
|
| 104 | enum task_dumpable task_exec_state_get_dumpable(struct task_struct *task)
|
| 105 | {
|
| 106 | struct task_exec_state *exec_state;
|
| 107 |
|
| 108 | guard(rcu)();
|
| 109 | exec_state = rcu_dereference(task->exec_state);
|
| 110 | return READ_ONCE(exec_state->dumpable);
|
| 111 | }
|
| 112 |
|
| 113 | void __init exec_state_init(void)
|
| 114 | {
|
| 115 | task_exec_state_cachep = kmem_cache_create("task_exec_state",
|
| 116 | sizeof(struct task_exec_state), 0,
|
| 117 | SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT,
|
| 118 | NULL);
|
| 119 | }
|