summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c12
-rw-r--r--kernel/nsproxy.c2
-rw-r--r--kernel/nstree.c80
-rw-r--r--kernel/panic.c5
-rw-r--r--kernel/power/energy_model.c4
-rw-r--r--kernel/power/suspend.c20
-rw-r--r--kernel/signal.c5
-rw-r--r--kernel/trace/Kconfig1
-rw-r--r--kernel/trace/bpf_trace.c15
-rw-r--r--kernel/ucount.c28
-rw-r--r--kernel/user_namespace.c5
-rw-r--r--kernel/watch_queue.c2
12 files changed, 103 insertions, 76 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index 18b6dd851642..8b108ed37152 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -971,10 +971,10 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
dup_user_cpus_ptr(tsk, orig, node);
/*
- * One for the user space visible state that goes away when reaped.
- * One for the scheduler.
+ * Nobody can keep the task while copy_process() may still fail, which
+ * frees it no matter what.
*/
- refcount_set(&tsk->rcu_users, 2);
+ refcount_set(&tsk->rcu_users, 0);
/* One for the rcu users */
refcount_set(&tsk->usage, 1);
#ifdef CONFIG_BLK_DEV_IO_TRACE
@@ -2510,6 +2510,12 @@ __latent_entropy struct task_struct *copy_process(
/* No more failure paths after this point. */
/*
+ * One for the user space visible state that goes away when reaped.
+ * One for the scheduler.
+ */
+ refcount_set(&p->rcu_users, 2);
+
+ /*
* Copy seccomp details explicitly here, in case they were changed
* before holding sighand lock.
*/
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 454427b09ed9..2dcf105e8ee2 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -355,6 +355,7 @@ static int prepare_nsset(unsigned flags, struct nsset *nsset)
{
struct task_struct *me = current;
+ nsset->flags = flags;
nsset->nsproxy = create_new_namespaces(0, me, current_user_ns(), me->fs);
if (IS_ERR(nsset->nsproxy))
return PTR_ERR(nsset->nsproxy);
@@ -375,7 +376,6 @@ static int prepare_nsset(unsigned flags, struct nsset *nsset)
goto out;
}
- nsset->flags = flags;
return 0;
out:
diff --git a/kernel/nstree.c b/kernel/nstree.c
index 831f279d174a..a756ae2e7881 100644
--- a/kernel/nstree.c
+++ b/kernel/nstree.c
@@ -408,15 +408,12 @@ struct klistns {
u32 ns_type;
struct user_namespace *user_ns;
bool userns_capable;
- struct ns_common *first_ns;
};
static void __free_klistns_free(const struct klistns *kls)
{
if (kls->user_ns_id != LISTNS_CURRENT_USER)
put_user_ns(kls->user_ns);
- if (kls->first_ns && kls->first_ns->ops)
- kls->first_ns->ops->put(kls->first_ns);
}
#define NS_ALL (PID_NS | USER_NS | MNT_NS | UTS_NS | IPC_NS | NET_NS | CGROUP_NS | TIME_NS)
@@ -459,10 +456,13 @@ static inline int prepare_klistns(struct klistns *kls, struct ns_id_req *kreq,
}
/*
- * Lookup a namespace owned by owner with id >= ns_id.
- * Returns the namespace with the smallest id that is >= ns_id.
+ * Lookup a namespace owned by owner with id > ns_id.
+ * Returns the namespace with the smallest id that is > ns_id.
+ *
+ * No reference is taken. The caller must hold rcu_read_lock() and may only
+ * use the result as the starting point of an RCU list walk.
*/
-static struct ns_common *lookup_ns_owner_at(u64 ns_id, struct ns_common *owner)
+static struct ns_common *lookup_ns_owner_after(u64 ns_id, struct ns_common *owner)
{
struct ns_common *ret = NULL;
struct rb_node *node;
@@ -476,18 +476,14 @@ static struct ns_common *lookup_ns_owner_at(u64 ns_id, struct ns_common *owner)
struct ns_common *ns;
ns = node_to_ns_owner(node);
- if (ns_id <= ns->ns_id) {
+ if (ns_id < ns->ns_id) {
ret = ns;
- if (ns_id == ns->ns_id)
- break;
node = node->rb_left;
} else {
node = node->rb_right;
}
}
- if (ret)
- ret = ns_get_unless_inactive(ret);
return ret;
}
@@ -560,25 +556,27 @@ static ssize_t do_listns_userns(struct klistns *kls)
return -EINVAL;
kls->user_ns = to_user_ns(ns);
- /*
- * Use the rbtree to find the first namespace we care about and
- * then use it's list entry to iterate from there.
- */
- if (kls->last_ns_id) {
- kls->first_ns = lookup_ns_owner_at(kls->last_ns_id + 1, ns);
- if (!kls->first_ns)
- return -ENOENT;
- first_ns = kls->first_ns;
- }
-
ret = 0;
head = &to_ns_common(kls->user_ns)->ns_owner_root.ns_list_head;
kls->userns_capable = may_see_all_namespaces();
rcu_read_lock();
- if (!first_ns)
+ /*
+ * Use the rbtree to find the first namespace we care about and
+ * then use it's list entry to iterate from there. That namespace
+ * is filtered like any other, so the walk doesn't end early just
+ * because it is inactive or already dying.
+ */
+ if (kls->last_ns_id) {
+ first_ns = lookup_ns_owner_after(kls->last_ns_id, ns);
+ if (!first_ns) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ } else {
first_ns = list_entry_rcu(head->next, typeof(*first_ns), ns_owner_node.ns_list_entry);
+ }
ns = first_ns;
list_for_each_entry_from_rcu(ns, head, ns_owner_node.ns_list_entry) {
@@ -613,10 +611,13 @@ static ssize_t do_listns_userns(struct klistns *kls)
}
/*
- * Lookup a namespace with id >= ns_id in either the unified tree or a type-specific tree.
- * Returns the namespace with the smallest id that is >= ns_id.
+ * Lookup a namespace with id > ns_id in either the unified tree or a type-specific tree.
+ * Returns the namespace with the smallest id that is > ns_id.
+ *
+ * No reference is taken. The caller must hold rcu_read_lock() and may only
+ * use the result as the starting point of an RCU list walk.
*/
-static struct ns_common *lookup_ns_id_at(u64 ns_id, int ns_type)
+static struct ns_common *lookup_ns_id_after(u64 ns_id, int ns_type)
{
struct ns_common *ret = NULL;
struct ns_tree_root *ns_tree = NULL;
@@ -643,21 +644,14 @@ static struct ns_common *lookup_ns_id_at(u64 ns_id, int ns_type)
else
ns = node_to_ns_unified(node);
- if (ns_id <= ns->ns_id) {
- if (ns_type)
- ret = node_to_ns(node);
- else
- ret = node_to_ns_unified(node);
- if (ns_id == ns->ns_id)
- break;
+ if (ns_id < ns->ns_id) {
+ ret = ns;
node = node->rb_left;
} else {
node = node->rb_right;
}
}
- if (ret)
- ret = ns_get_unless_inactive(ret);
return ret;
}
@@ -707,13 +701,6 @@ static ssize_t do_listns(struct klistns *kls)
return -EINVAL;
}
- if (kls->last_ns_id) {
- kls->first_ns = lookup_ns_id_at(kls->last_ns_id + 1, ns_type);
- if (!kls->first_ns)
- return -ENOENT;
- first_ns = kls->first_ns;
- }
-
ret = 0;
if (ns_tree)
head = &ns_tree->ns_list_head;
@@ -722,8 +709,15 @@ static ssize_t do_listns(struct klistns *kls)
rcu_read_lock();
- if (!first_ns)
+ if (kls->last_ns_id) {
+ first_ns = lookup_ns_id_after(kls->last_ns_id, ns_type);
+ if (!first_ns) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ } else {
first_ns = first_ns_common(head, ns_tree);
+ }
for (ns = first_ns; !ns_common_is_head(ns, head, ns_tree) && nr_ns_ids;
ns = next_ns_common(ns, ns_tree)) {
diff --git a/kernel/panic.c b/kernel/panic.c
index b824b68fcb08..574ee5a12f92 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -825,7 +825,6 @@ const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
TAINT_FLAG(RANDSTRUCT, 'T', ' '),
TAINT_FLAG(TEST, 'N', ' '),
TAINT_FLAG(FWCTL, 'J', ' '),
- TAINT_FLAG(FORCED_BIND, 'Y', ' '),
};
#undef TAINT_FLAG
@@ -862,9 +861,9 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
* exact size is allocated dynamically; the initial buffer remains
* as a fallback if allocation fails.
*
- * The verbose taint string currently requires up to 344 characters.
+ * The verbose taint string currently requires up to 327 characters.
*/
-#define INIT_TAINT_BUF_MAX 370
+#define INIT_TAINT_BUF_MAX 350
static char init_taint_buf[INIT_TAINT_BUF_MAX] __initdata;
static char *taint_buf __refdata = init_taint_buf;
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index a76089e2ce8c..d19a65461ae8 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -439,7 +439,9 @@ static int em_create_pd(struct device *dev, int nr_states,
cpumask_copy(em_span_cpus(pd), cpus);
} else {
- pd = kzalloc_obj(*pd);
+ /* Readers expect pd->cpus to exist and remain empty. */
+ pd = kzalloc_flex(*pd, cpus,
+ BITS_TO_LONGS(large_cpumask_bits));
if (!pd)
return -ENOMEM;
}
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 57c44268698f..32c055df02da 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -306,20 +306,24 @@ static void platform_resume_finish(suspend_state_t state)
static int platform_suspend_begin(suspend_state_t state)
{
- if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->begin)
- return s2idle_ops->begin();
- else if (suspend_ops && suspend_ops->begin)
+ if (state == PM_SUSPEND_TO_IDLE) {
+ if (s2idle_ops && s2idle_ops->begin)
+ return s2idle_ops->begin();
+ } else if (suspend_ops && suspend_ops->begin) {
return suspend_ops->begin(state);
- else
- return 0;
+ }
+
+ return 0;
}
static void platform_resume_end(suspend_state_t state)
{
- if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->end)
- s2idle_ops->end();
- else if (suspend_ops && suspend_ops->end)
+ if (state == PM_SUSPEND_TO_IDLE) {
+ if (s2idle_ops && s2idle_ops->end)
+ s2idle_ops->end();
+ } else if (suspend_ops && suspend_ops->end) {
suspend_ops->end();
+ }
}
static void platform_recover(suspend_state_t state)
diff --git a/kernel/signal.c b/kernel/signal.c
index cb6ec7054eee..dd770e68faee 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -684,12 +684,13 @@ static int dequeue_synchronous_signal(kernel_siginfo_t *info)
return 0;
/*
- * Return the first synchronous signal in the queue.
+ * Return the first unblocked synchronous signal in the queue.
*/
list_for_each_entry(q, &pending->list, list) {
/* Synchronous signals have a positive si_code */
if ((q->info.si_code > SI_USER) &&
- (sigmask(q->info.si_signo) & SYNCHRONOUS_MASK)) {
+ (sigmask(q->info.si_signo) & SYNCHRONOUS_MASK) &&
+ !sigismember(&tsk->blocked, q->info.si_signo)) {
sync = q;
goto next;
}
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index c41397eccee5..35d043b19332 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -1337,6 +1337,7 @@ source "kernel/trace/rv/Kconfig"
config TRACE_REMOTE
bool
+ select TRACING
config SIMPLE_RING_BUFFER
bool
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 14adfb85fdb2..2aec56d7f3d3 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -974,6 +974,10 @@ BTF_ID(func, vfs_getattr)
BTF_ID(func, filp_close)
BTF_SET_END(btf_allowlist_d_path)
+BTF_SET_START(btf_allowlist_d_path_fentry)
+BTF_ID(func, filp_close_sync)
+BTF_SET_END(btf_allowlist_d_path_fentry)
+
static bool bpf_d_path_allowed(const struct bpf_prog *prog)
{
if (prog->type == BPF_PROG_TYPE_TRACING &&
@@ -983,8 +987,15 @@ static bool bpf_d_path_allowed(const struct bpf_prog *prog)
if (prog->type == BPF_PROG_TYPE_LSM)
return bpf_lsm_is_sleepable_hook(prog->aux->attach_btf_id);
- return btf_id_set_contains(&btf_allowlist_d_path,
- prog->aux->attach_btf_id);
+ if (btf_id_set_contains(&btf_allowlist_d_path,
+ prog->aux->attach_btf_id))
+ return true;
+
+ if (btf_id_set_contains(&btf_allowlist_d_path_fentry,
+ prog->aux->attach_btf_id))
+ return prog->expected_attach_type == BPF_TRACE_FENTRY;
+
+ return false;
}
BTF_ID_LIST_SINGLE(bpf_d_path_btf_ids, struct, path)
diff --git a/kernel/ucount.c b/kernel/ucount.c
index ec8b1445e287..94b70502dc9d 100644
--- a/kernel/ucount.c
+++ b/kernel/ucount.c
@@ -285,9 +285,12 @@ static void do_dec_rlimit_put_ucounts(struct ucounts *ucounts,
{
struct ucounts *iter, *next;
for (iter = ucounts; iter != last; iter = next) {
- long dec = atomic_long_sub_return(1, &iter->rlimit[type]);
- WARN_ON_ONCE(dec < 0);
+ long dec;
+
+ /* Our count pins @iter; once it is dropped @iter may be freed. */
next = iter->ns->ucounts;
+ dec = atomic_long_sub_return(1, &iter->rlimit[type]);
+ WARN_ON_ONCE(dec < 0);
if (dec == 0)
put_ucounts(iter);
}
@@ -308,23 +311,26 @@ long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type,
for (iter = ucounts; iter; iter = iter->ns->ucounts) {
long new = atomic_long_add_return(1, &iter->rlimit[type]);
- if (new < 0 || new > max)
+ /*
+ * Take the extra reference on the 0 -> 1 transition before the
+ * limit check: a rejected walk must not leave a concurrent one
+ * holding the surviving increment with no reference.
+ */
+ if (new == 1 && !get_ucounts(iter))
goto dec_unwind;
+ if (new < 0 || new > max) {
+ /* undo iter too, releasing the reference taken above */
+ do_dec_rlimit_put_ucounts(ucounts, iter->ns->ucounts, type);
+ return 0;
+ }
if (iter == ucounts)
ret = new;
if (!override_rlimit)
max = get_userns_rlimit_max(iter->ns, type);
- /*
- * Grab an extra ucount reference for the caller when
- * the rlimit count was previously 0.
- */
- if (new != 1)
- continue;
- if (!get_ucounts(iter))
- goto dec_unwind;
}
return ret;
dec_unwind:
+ /* get_ucounts() failed for iter: undo iter without a put */
dec = atomic_long_sub_return(1, &iter->rlimit[type]);
WARN_ON_ONCE(dec < 0);
do_dec_rlimit_put_ucounts(ucounts, iter, type);
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 50c374ed4687..cd748e1cbace 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -46,8 +46,11 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
{
/* Start with the same capabilities as init but useless for doing
* anything as the capabilities are bound to the new user namespace.
+ * The exec securebits grant nothing, they are restrictions the task
+ * placed on itself. Keep them and their locks.
*/
- cred->securebits = SECUREBITS_DEFAULT;
+ cred->securebits = SECUREBITS_DEFAULT |
+ (cred->securebits & (SECURE_ALL_UNPRIVILEGED | SECURE_ALL_UNPRIVILEGED << 1));
cred->cap_inheritable = CAP_EMPTY_SET;
cred->cap_permitted = CAP_FULL_SET;
cred->cap_effective = CAP_FULL_SET;
diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c
index 932a88ac1f39..453dcf613205 100644
--- a/kernel/watch_queue.c
+++ b/kernel/watch_queue.c
@@ -212,7 +212,7 @@ void __post_watch_notification(struct watch_list *wlist,
if (watch->id != id)
continue;
n->info &= ~WATCH_INFO_ID;
- n->info |= watch->info_id;
+ n->info |= watch->info_id & WATCH_INFO_ID;
wqueue = rcu_dereference(watch->queue);
wf = rcu_dereference(wqueue->filter);