From 458b37a82d3b4c33fce1334414011a8818f52326 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 1 Aug 2022 18:25:11 +0000 Subject: [PATCH 01/24] FROMLIST: binder: fix UAF of ref->proc caused by race condition A transaction of type BINDER_TYPE_WEAK_HANDLE can fail to increment the reference for a node. In this case, the target proc normally releases the failed reference upon close as expected. However, if the target is dying in parallel the call will race with binder_deferred_release(), so the target could have released all of its references by now leaving the cleanup of the new failed reference unhandled. The transaction then ends and the target proc gets released making the ref->proc now a dangling pointer. Later on, ref->node is closed and we attempt to take spin_lock(&ref->proc->inner_lock), which leads to the use-after-free bug reported below. Let's fix this by cleaning up the failed reference on the spot instead of relying on the target to do so. ================================================================== BUG: KASAN: use-after-free in _raw_spin_lock+0xa8/0x150 Write of size 4 at addr ffff5ca207094238 by task kworker/1:0/590 CPU: 1 PID: 590 Comm: kworker/1:0 Not tainted 5.19.0-rc8 #10 Hardware name: linux,dummy-virt (DT) Workqueue: events binder_deferred_func Call trace: dump_backtrace.part.0+0x1d0/0x1e0 show_stack+0x18/0x70 dump_stack_lvl+0x68/0x84 print_report+0x2e4/0x61c kasan_report+0xa4/0x110 kasan_check_range+0xfc/0x1a4 __kasan_check_write+0x3c/0x50 _raw_spin_lock+0xa8/0x150 binder_deferred_func+0x5e0/0x9b0 process_one_work+0x38c/0x5f0 worker_thread+0x9c/0x694 kthread+0x188/0x190 ret_from_fork+0x10/0x20 Signed-off-by: Carlos Llamas Acked-by: Christian Brauner (Microsoft) Bug: 239630375 Link: https://lore.kernel.org/all/20220801182511.3371447-1-cmllamas@google.com/ Signed-off-by: Carlos Llamas Change-Id: I5085dd0dc805a780a64c057e5819f82dd8f02868 (cherry picked from commit ae3fa5d16a02ba7c7b170e0e1ab56d6f0ba33964) --- drivers/android/binder.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d42c1c13e0a1..b80fd4f87fa4 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1470,6 +1470,18 @@ static int binder_inc_ref_for_node(struct binder_proc *proc, } ret = binder_inc_ref_olocked(ref, strong, target_list); *rdata = ref->data; + if (ret && ref == new_ref) { + /* + * Cleanup the failed reference here as the target + * could now be dead and have already released its + * references by now. Calling on the new reference + * with strong=0 and a tmp_refs will not decrement + * the node. The new_ref gets kfree'd below. + */ + binder_cleanup_ref_olocked(new_ref); + ref = NULL; + } + binder_proc_unlock(proc); if (new_ref && ref != new_ref) /* From fffb2b5bad71f89821ffb37aba9d87754c010c4b Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 21 Jul 2022 09:10:50 -0700 Subject: [PATCH 02/24] BACKPORT: Bluetooth: L2CAP: Fix use-after-free caused by l2cap_chan_put commit d0be8347c623e0ac4202a1d4e0373882821f56b0 upstream. This fixes the following trace which is caused by hci_rx_work starting up *after* the final channel reference has been put() during sock_close() but *before* the references to the channel have been destroyed, so instead the code now rely on kref_get_unless_zero/l2cap_chan_hold_unless_zero to prevent referencing a channel that is about to be destroyed. refcount_t: increment on 0; use-after-free. BUG: KASAN: use-after-free in refcount_dec_and_test+0x20/0xd0 Read of size 4 at addr ffffffc114f5bf18 by task kworker/u17:14/705 CPU: 4 PID: 705 Comm: kworker/u17:14 Tainted: G S W 4.14.234-00003-g1fb6d0bd49a4-dirty #28 Hardware name: Qualcomm Technologies, Inc. SM8150 V2 PM8150 Google Inc. MSM sm8150 Flame DVT (DT) Workqueue: hci0 hci_rx_work Call trace: dump_backtrace+0x0/0x378 show_stack+0x20/0x2c dump_stack+0x124/0x148 print_address_description+0x80/0x2e8 __kasan_report+0x168/0x188 kasan_report+0x10/0x18 __asan_load4+0x84/0x8c refcount_dec_and_test+0x20/0xd0 l2cap_chan_put+0x48/0x12c l2cap_recv_frame+0x4770/0x6550 l2cap_recv_acldata+0x44c/0x7a4 hci_acldata_packet+0x100/0x188 hci_rx_work+0x178/0x23c process_one_work+0x35c/0x95c worker_thread+0x4cc/0x960 kthread+0x1a8/0x1c4 ret_from_fork+0x10/0x18 Bug: 165329981 Cc: stable@kernel.org Reported-by: Lee Jones Signed-off-by: Luiz Augusto von Dentz Tested-by: Lee Jones Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Lee Jones Change-Id: I6efae55d8014740aebc8c3534846c2d249068b29 --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 61 +++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 8efc2419a815..b2046b02d11d 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -802,6 +802,7 @@ enum { }; void l2cap_chan_hold(struct l2cap_chan *c); +struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c); void l2cap_chan_put(struct l2cap_chan *c); static inline void l2cap_chan_lock(struct l2cap_chan *chan) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 959a16b13303..286fca6a9ab2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -110,7 +110,8 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, } /* Find channel with given SCID. - * Returns locked channel. */ + * Returns a reference locked channel. + */ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { @@ -118,15 +119,19 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); - if (c) - l2cap_chan_lock(c); + if (c) { + /* Only lock if chan reference is not 0 */ + c = l2cap_chan_hold_unless_zero(c); + if (c) + l2cap_chan_lock(c); + } mutex_unlock(&conn->chan_lock); return c; } /* Find channel with given DCID. - * Returns locked channel. + * Returns a reference locked channel. */ static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) @@ -135,8 +140,12 @@ static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn, mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_dcid(conn, cid); - if (c) - l2cap_chan_lock(c); + if (c) { + /* Only lock if chan reference is not 0 */ + c = l2cap_chan_hold_unless_zero(c); + if (c) + l2cap_chan_lock(c); + } mutex_unlock(&conn->chan_lock); return c; @@ -161,8 +170,12 @@ static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); - if (c) - l2cap_chan_lock(c); + if (c) { + /* Only lock if chan reference is not 0 */ + c = l2cap_chan_hold_unless_zero(c); + if (c) + l2cap_chan_lock(c); + } mutex_unlock(&conn->chan_lock); return c; @@ -496,6 +509,16 @@ void l2cap_chan_hold(struct l2cap_chan *c) kref_get(&c->kref); } +struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c) +{ + BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref)); + + if (!kref_get_unless_zero(&c->kref)) + return NULL; + + return c; +} + void l2cap_chan_put(struct l2cap_chan *c) { BT_DBG("chan %p orig refcnt %d", c, kref_read(&c->kref)); @@ -1812,7 +1835,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, src_match = !bacmp(&c->src, src); dst_match = !bacmp(&c->dst, dst); if (src_match && dst_match) { - l2cap_chan_hold(c); + c = l2cap_chan_hold_unless_zero(c); + if (!c) + continue; + read_unlock(&chan_list_lock); return c; } @@ -1827,7 +1853,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, } if (c1) - l2cap_chan_hold(c1); + c1 = l2cap_chan_hold_unless_zero(c1); read_unlock(&chan_list_lock); @@ -4221,6 +4247,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, unlock: l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return err; } @@ -4334,6 +4361,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, done: l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return err; } @@ -5062,6 +5090,7 @@ send_move_response: l2cap_send_move_chan_rsp(chan, result); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return 0; } @@ -5154,6 +5183,7 @@ static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result) } l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid, @@ -5183,6 +5213,7 @@ static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid, l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static int l2cap_move_channel_rsp(struct l2cap_conn *conn, @@ -5246,6 +5277,7 @@ static int l2cap_move_channel_confirm(struct l2cap_conn *conn, l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return 0; } @@ -5281,6 +5313,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, } l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return 0; } @@ -5653,12 +5686,11 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn, if (credits > max_credits) { BT_ERR("LE credits overflow"); l2cap_send_disconn_req(chan, ECONNRESET); - l2cap_chan_unlock(chan); /* Return 0 so that we don't trigger an unnecessary * command reject packet. */ - return 0; + goto unlock; } chan->tx_credits += credits; @@ -5669,7 +5701,9 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn, if (chan->tx_credits) chan->ops->resume(chan); +unlock: l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return 0; } @@ -6983,6 +7017,7 @@ drop: done: l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, @@ -7386,7 +7421,7 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, if (src_type != c->src_type) continue; - l2cap_chan_hold(c); + c = l2cap_chan_hold_unless_zero(c); read_unlock(&chan_list_lock); return c; } From 88c3fd64615d0c4f9121b06481217110a660df30 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Fri, 3 Jun 2022 17:45:15 +0000 Subject: [PATCH 03/24] ANDROID: binder: fold common setup of node_prio The setup of node_prio is always the same, so just fold this logic into binder_transaction_priority() to avoid duplication. Let's pass the node reference instead, which also gives access to node->inherit_rt. There is no functional impact from this patch. Bug: 148101660 Signed-off-by: Carlos Llamas Change-Id: Ib390204556e69c4bc8492cd9cd873773f9cdce42 (cherry picked from commit 498bf715b77c68e54d0289fa66e3f112278f87dc) [cmllamas: fixed minor merge conflicts] --- drivers/android/binder.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index b80fd4f87fa4..d4685c94e530 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -727,10 +727,13 @@ static void binder_restore_priority(struct task_struct *task, static void binder_transaction_priority(struct task_struct *task, struct binder_transaction *t, - struct binder_priority node_prio, - bool inherit_rt) + struct binder_node *node) { struct binder_priority desired_prio = t->priority; + const struct binder_priority node_prio = { + .sched_policy = node->sched_policy, + .prio = node->min_priority, + }; if (t->set_priority_called) return; @@ -739,7 +742,7 @@ static void binder_transaction_priority(struct task_struct *task, t->saved_priority.sched_policy = task->policy; t->saved_priority.prio = task->normal_prio; - if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) { + if (!node->inherit_rt && is_rt_policy(desired_prio.sched_policy)) { desired_prio.prio = NICE_TO_PRIO(0); desired_prio.sched_policy = SCHED_NORMAL; } @@ -2488,14 +2491,11 @@ static int binder_proc_transaction(struct binder_transaction *t, struct binder_thread *thread) { struct binder_node *node = t->buffer->target_node; - struct binder_priority node_prio; bool oneway = !!(t->flags & TF_ONE_WAY); bool pending_async = false; BUG_ON(!node); binder_node_lock(node); - node_prio.prio = node->min_priority; - node_prio.sched_policy = node->sched_policy; if (oneway) { BUG_ON(thread); @@ -2523,8 +2523,7 @@ static int binder_proc_transaction(struct binder_transaction *t, thread = binder_select_thread_ilocked(proc); if (thread) { - binder_transaction_priority(thread->task, t, node_prio, - node->inherit_rt); + binder_transaction_priority(thread->task, t, node); binder_enqueue_thread_work_ilocked(thread, &t->work); } else if (!pending_async) { binder_enqueue_work_ilocked(&t->work, &proc->todo); @@ -4197,14 +4196,10 @@ retry: BUG_ON(t->buffer == NULL); if (t->buffer->target_node) { struct binder_node *target_node = t->buffer->target_node; - struct binder_priority node_prio; trd->target.ptr = target_node->ptr; trd->cookie = target_node->cookie; - node_prio.sched_policy = target_node->sched_policy; - node_prio.prio = target_node->min_priority; - binder_transaction_priority(current, t, node_prio, - target_node->inherit_rt); + binder_transaction_priority(current, t, target_node); cmd = BR_TRANSACTION; } else { trd->target.ptr = 0; From 807b6742c9ccfa1f18a77de9ca13eaef34b4163e Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 6 Jun 2022 20:27:12 +0000 Subject: [PATCH 04/24] ANDROID: binder: pass desired priority by reference Avoid making unnecessary stack copies of struct binder_priority and pass the argument by reference instead. Rename 'desired_prio' to 'desired' to match the usage in other priority functions. There is no functional impact from this patch. Bug: 148101660 Signed-off-by: Carlos Llamas Change-Id: I66ff5305296e7b9dba56ed265236f2af518f66e0 (cherry picked from commit 52d85f8a16467ce0bca374f885de24918f017371) [cmllamas: fixed minor merge conflict] --- drivers/android/binder.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d4685c94e530..32eb39fd1504 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -651,19 +651,19 @@ static int to_kernel_prio(int policy, int user_priority) } static void binder_do_set_priority(struct task_struct *task, - struct binder_priority desired, + const struct binder_priority *desired, bool verify) { int priority; /* user-space prio value */ bool has_cap_nice; - unsigned int policy = desired.sched_policy; + unsigned int policy = desired->sched_policy; - if (task->policy == policy && task->normal_prio == desired.prio) + if (task->policy == policy && task->normal_prio == desired->prio) return; has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE); - priority = to_userspace_prio(policy, desired.prio); + priority = to_userspace_prio(policy, desired->prio); if (verify && is_rt_policy(policy) && !has_cap_nice) { long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO); @@ -688,16 +688,16 @@ static void binder_do_set_priority(struct task_struct *task, } } - if (policy != desired.sched_policy || - to_kernel_prio(policy, priority) != desired.prio) + if (policy != desired->sched_policy || + to_kernel_prio(policy, priority) != desired->prio) binder_debug(BINDER_DEBUG_PRIORITY_CAP, "%d: priority %d not allowed, using %d instead\n", - task->pid, desired.prio, + task->pid, desired->prio, to_kernel_prio(policy, priority)); trace_binder_set_priority(task->tgid, task->pid, task->normal_prio, to_kernel_prio(policy, priority), - desired.prio); + desired->prio); /* Set the actual priority */ if (task->policy != policy || is_rt_policy(policy)) { @@ -714,13 +714,13 @@ static void binder_do_set_priority(struct task_struct *task, } static void binder_set_priority(struct task_struct *task, - struct binder_priority desired) + const struct binder_priority *desired) { binder_do_set_priority(task, desired, /* verify = */ true); } static void binder_restore_priority(struct task_struct *task, - struct binder_priority desired) + const struct binder_priority *desired) { binder_do_set_priority(task, desired, /* verify = */ false); } @@ -729,7 +729,7 @@ static void binder_transaction_priority(struct task_struct *task, struct binder_transaction *t, struct binder_node *node) { - struct binder_priority desired_prio = t->priority; + struct binder_priority desired = t->priority; const struct binder_priority node_prio = { .sched_policy = node->sched_policy, .prio = node->min_priority, @@ -742,9 +742,9 @@ static void binder_transaction_priority(struct task_struct *task, t->saved_priority.sched_policy = task->policy; t->saved_priority.prio = task->normal_prio; - if (!node->inherit_rt && is_rt_policy(desired_prio.sched_policy)) { - desired_prio.prio = NICE_TO_PRIO(0); - desired_prio.sched_policy = SCHED_NORMAL; + if (!node->inherit_rt && is_rt_policy(desired.sched_policy)) { + desired.prio = NICE_TO_PRIO(0); + desired.sched_policy = SCHED_NORMAL; } if (node_prio.prio < t->priority.prio || @@ -757,10 +757,10 @@ static void binder_transaction_priority(struct task_struct *task, * SCHED_FIFO, prefer SCHED_FIFO, since it can * run unbounded, unlike SCHED_RR. */ - desired_prio = node_prio; + desired = node_prio; } - binder_set_priority(task, desired_prio); + binder_set_priority(task, &desired); trace_android_vh_binder_set_priority(t, task); } @@ -3189,7 +3189,7 @@ static void binder_transaction(struct binder_proc *proc, binder_inner_proc_unlock(target_proc); wake_up_interruptible_sync(&target_thread->wait); trace_android_vh_binder_restore_priority(in_reply_to, current); - binder_restore_priority(current, in_reply_to->saved_priority); + binder_restore_priority(current, &in_reply_to->saved_priority); binder_free_transaction(in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); @@ -3303,7 +3303,7 @@ err_invalid_target_handle: BUG_ON(thread->return_error.cmd != BR_OK); if (in_reply_to) { trace_android_vh_binder_restore_priority(in_reply_to, current); - binder_restore_priority(current, in_reply_to->saved_priority); + binder_restore_priority(current, &in_reply_to->saved_priority); thread->return_error.cmd = BR_TRANSACTION_COMPLETE; binder_enqueue_thread_work(thread, &thread->return_error.work); binder_send_failed_reply(in_reply_to, return_error); @@ -3974,7 +3974,7 @@ retry: binder_stop_on_user_error < 2); } trace_android_vh_binder_restore_priority(NULL, current); - binder_restore_priority(current, proc->default_priority); + binder_restore_priority(current, &proc->default_priority); } if (non_block) { From 308230b9d7519873a0ca01e31a0acacc8d7cb105 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 6 Jun 2022 20:49:40 +0000 Subject: [PATCH 05/24] ANDROID: binder: switch task argument for binder_thread Refactor binder priority functions to take in 'struct binder_thread *' instead of just 'struct task_struct *'. This allows access to other thread fields used in subsequent patches. In any case, the same task reference is still available under thread->task. There is no functional impact from this patch. Bug: 148101660 Signed-off-by: Carlos Llamas Change-Id: I67b599884580d957d776500e467827e5035c99f6 (cherry picked from commit 759d98484b5b51932d3d11651fa83c6bb268ce03) --- drivers/android/binder.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 32eb39fd1504..3e406ccbc2be 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -650,10 +650,11 @@ static int to_kernel_prio(int policy, int user_priority) return MAX_USER_RT_PRIO - 1 - user_priority; } -static void binder_do_set_priority(struct task_struct *task, +static void binder_do_set_priority(struct binder_thread *thread, const struct binder_priority *desired, bool verify) { + struct task_struct *task = thread->task; int priority; /* user-space prio value */ bool has_cap_nice; unsigned int policy = desired->sched_policy; @@ -713,22 +714,23 @@ static void binder_do_set_priority(struct task_struct *task, set_user_nice(task, priority); } -static void binder_set_priority(struct task_struct *task, +static void binder_set_priority(struct binder_thread *thread, const struct binder_priority *desired) { - binder_do_set_priority(task, desired, /* verify = */ true); + binder_do_set_priority(thread, desired, /* verify = */ true); } -static void binder_restore_priority(struct task_struct *task, +static void binder_restore_priority(struct binder_thread *thread, const struct binder_priority *desired) { - binder_do_set_priority(task, desired, /* verify = */ false); + binder_do_set_priority(thread, desired, /* verify = */ false); } -static void binder_transaction_priority(struct task_struct *task, +static void binder_transaction_priority(struct binder_thread *thread, struct binder_transaction *t, struct binder_node *node) { + struct task_struct *task = thread->task; struct binder_priority desired = t->priority; const struct binder_priority node_prio = { .sched_policy = node->sched_policy, @@ -760,7 +762,7 @@ static void binder_transaction_priority(struct task_struct *task, desired = node_prio; } - binder_set_priority(task, &desired); + binder_set_priority(thread, &desired); trace_android_vh_binder_set_priority(t, task); } @@ -2523,7 +2525,7 @@ static int binder_proc_transaction(struct binder_transaction *t, thread = binder_select_thread_ilocked(proc); if (thread) { - binder_transaction_priority(thread->task, t, node); + binder_transaction_priority(thread, t, node); binder_enqueue_thread_work_ilocked(thread, &t->work); } else if (!pending_async) { binder_enqueue_work_ilocked(&t->work, &proc->todo); @@ -3189,7 +3191,7 @@ static void binder_transaction(struct binder_proc *proc, binder_inner_proc_unlock(target_proc); wake_up_interruptible_sync(&target_thread->wait); trace_android_vh_binder_restore_priority(in_reply_to, current); - binder_restore_priority(current, &in_reply_to->saved_priority); + binder_restore_priority(thread, &in_reply_to->saved_priority); binder_free_transaction(in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); @@ -3303,7 +3305,7 @@ err_invalid_target_handle: BUG_ON(thread->return_error.cmd != BR_OK); if (in_reply_to) { trace_android_vh_binder_restore_priority(in_reply_to, current); - binder_restore_priority(current, &in_reply_to->saved_priority); + binder_restore_priority(thread, &in_reply_to->saved_priority); thread->return_error.cmd = BR_TRANSACTION_COMPLETE; binder_enqueue_thread_work(thread, &thread->return_error.work); binder_send_failed_reply(in_reply_to, return_error); @@ -3974,7 +3976,7 @@ retry: binder_stop_on_user_error < 2); } trace_android_vh_binder_restore_priority(NULL, current); - binder_restore_priority(current, &proc->default_priority); + binder_restore_priority(thread, &proc->default_priority); } if (non_block) { @@ -4199,7 +4201,7 @@ retry: trd->target.ptr = target_node->ptr; trd->cookie = target_node->cookie; - binder_transaction_priority(current, t, target_node); + binder_transaction_priority(thread, t, target_node); cmd = BR_TRANSACTION; } else { trd->target.ptr = 0; From da97a10882ba78cc036cc6b7b006dd057029b2e4 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 6 Jun 2022 20:11:41 +0000 Subject: [PATCH 06/24] ANDROID: binder: fix race in priority restore During a reply, the target gets woken up and then the priority of the replier is restored. The order is such to allow the target to process the reply ASAP. Otherwise, we risk the sender getting scheduled out before the wakeup happens. This strategy reduces transaction latency. However, a subsequent transaction from the same target could be started before the priority of the replier gets restored. At this point we save the wrong priority and it gets reinstated at the end of the transaction. This patch allows the incoming transaction to detect the race condition and save the correct next priority. Additionally, the replier will abort its pending priority restore which allows the new transaction to always run at the desired priority. Bug: 148101660 Signed-off-by: Carlos Llamas Change-Id: I6fec41ae1a1342023f78212ab1f984e26f068221 (cherry picked from commit cac827f2619b280d418e546a09f25da600dafe5a) [cmllamas: fixed trivial merge conflict] --- drivers/android/binder.c | 49 +++++++++++++++++++++++++++++-- drivers/android/binder_internal.h | 16 ++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 3e406ccbc2be..1c21e4157b13 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -700,6 +700,20 @@ static void binder_do_set_priority(struct binder_thread *thread, to_kernel_prio(policy, priority), desired->prio); + spin_lock(&thread->prio_lock); + if (!verify && thread->prio_state == BINDER_PRIO_ABORT) { + /* + * A new priority has been set by an incoming nested + * transaction. Abort this priority restore and allow + * the transaction to run at the new desired priority. + */ + spin_unlock(&thread->prio_lock); + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: %s: aborting priority restore\n", + thread->pid, __func__); + return; + } + /* Set the actual priority */ if (task->policy != policy || is_rt_policy(policy)) { struct sched_param params; @@ -712,6 +726,9 @@ static void binder_do_set_priority(struct binder_thread *thread, } if (is_fair_policy(policy)) set_user_nice(task, priority); + + thread->prio_state = BINDER_PRIO_SET; + spin_unlock(&thread->prio_lock); } static void binder_set_priority(struct binder_thread *thread, @@ -741,8 +758,6 @@ static void binder_transaction_priority(struct binder_thread *thread, return; t->set_priority_called = true; - t->saved_priority.sched_policy = task->policy; - t->saved_priority.prio = task->normal_prio; if (!node->inherit_rt && is_rt_policy(desired.sched_policy)) { desired.prio = NICE_TO_PRIO(0); @@ -762,6 +777,25 @@ static void binder_transaction_priority(struct binder_thread *thread, desired = node_prio; } + spin_lock(&thread->prio_lock); + if (thread->prio_state == BINDER_PRIO_PENDING) { + /* + * Task is in the process of changing priorities + * saving its current values would be incorrect. + * Instead, save the pending priority and signal + * the task to abort the priority restore. + */ + t->saved_priority = thread->prio_next; + thread->prio_state = BINDER_PRIO_ABORT; + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: saved pending priority %d\n", + current->pid, thread->prio_next.prio); + } else { + t->saved_priority.sched_policy = task->policy; + t->saved_priority.prio = task->normal_prio; + } + spin_unlock(&thread->prio_lock); + binder_set_priority(thread, &desired); trace_android_vh_binder_set_priority(t, task); } @@ -2612,6 +2646,7 @@ static void binder_transaction(struct binder_proc *proc, int t_debug_id = atomic_inc_return(&binder_last_id); char *secctx = NULL; u32 secctx_sz = 0; + bool is_nested = false; e = binder_transaction_log_add(&binder_transaction_log); e->debug_id = t_debug_id; @@ -2788,6 +2823,7 @@ static void binder_transaction(struct binder_proc *proc, atomic_inc(&from->tmp_ref); target_thread = from; spin_unlock(&tmp->lock); + is_nested = true; break; } spin_unlock(&tmp->lock); @@ -2852,6 +2888,7 @@ static void binder_transaction(struct binder_proc *proc, t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; + t->is_nested = is_nested; if (!(t->flags & TF_ONE_WAY) && binder_supported_policy(current->policy)) { /* Inherit supported policies for synchronous transactions */ @@ -3189,6 +3226,12 @@ static void binder_transaction(struct binder_proc *proc, binder_enqueue_thread_work_ilocked(target_thread, &t->work); target_proc->outstanding_txns++; binder_inner_proc_unlock(target_proc); + if (in_reply_to->is_nested) { + spin_lock(&thread->prio_lock); + thread->prio_state = BINDER_PRIO_PENDING; + thread->prio_next = in_reply_to->saved_priority; + spin_unlock(&thread->prio_lock); + } wake_up_interruptible_sync(&target_thread->wait); trace_android_vh_binder_restore_priority(in_reply_to, current); binder_restore_priority(thread, &in_reply_to->saved_priority); @@ -4431,6 +4474,8 @@ static struct binder_thread *binder_get_thread_ilocked( thread->return_error.cmd = BR_OK; thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR; thread->reply_error.cmd = BR_OK; + spin_lock_init(&thread->prio_lock); + thread->prio_state = BINDER_PRIO_SET; INIT_LIST_HEAD(&new_thread->waiting_thread_node); return thread; } diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index e32807fbb732..78870970ec71 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -366,6 +366,12 @@ struct binder_priority { int prio; }; +enum binder_prio_state { + BINDER_PRIO_SET, /* desired priority set */ + BINDER_PRIO_PENDING, /* initiated a saved priority restore */ + BINDER_PRIO_ABORT, /* abort the pending priority restore */ +}; + /** * struct binder_proc - binder process bookkeeping * @proc_node: element for binder_procs list @@ -526,6 +532,12 @@ static inline const struct cred *binder_get_cred(struct binder_proc *proc) * when outstanding transactions are cleaned up * (protected by @proc->inner_lock) * @task: struct task_struct for this thread + * @prio_lock: protects thread priority fields + * @prio_next: saved priority to be restored next + * (protected by @prio_lock) + * @prio_state: state of the priority restore process as + * defined by enum binder_prio_state + * (protected by @prio_lock) * * Bookkeeping structure for binder threads. */ @@ -546,6 +558,9 @@ struct binder_thread { atomic_t tmp_ref; bool is_dead; struct task_struct *task; + spinlock_t prio_lock; + struct binder_priority prio_next; + enum binder_prio_state prio_state; }; /** @@ -582,6 +597,7 @@ struct binder_transaction { struct binder_priority priority; struct binder_priority saved_priority; bool set_priority_called; + bool is_nested; kuid_t sender_euid; struct list_head fd_fixups; binder_uintptr_t security_ctx; From 012ab662e2d5370a7632abac5f110f509604b918 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Fri, 22 Jul 2022 01:19:38 +0000 Subject: [PATCH 07/24] ANDROID: binder: fix pending prio state for early exit When calling binder_do_set_priority() with the same policy and priority values as the current task, we exit early since there is nothing to do. However, the BINDER_PRIO_PENDING state might be set and in this case we fail to update it. A subsequent call to binder_transaction_priority() will then read an incorrect state and save the wrong priority. Fix this by setting thread->prio_state to BINDER_PRIO_SET on our way out. Bug: 199309216 Fixes: cac827f2619b ("ANDROID: binder: fix race in priority restore") Signed-off-by: Carlos Llamas Change-Id: I21e906cf4b2ebee908af41fe101ecd458ae1991c (cherry picked from commit 72193be6d4bd9ad29dacd998c14dff97f7a6c6c9) --- drivers/android/binder.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 1c21e4157b13..d6c3b9f7816c 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -659,8 +659,13 @@ static void binder_do_set_priority(struct binder_thread *thread, bool has_cap_nice; unsigned int policy = desired->sched_policy; - if (task->policy == policy && task->normal_prio == desired->prio) + if (task->policy == policy && task->normal_prio == desired->prio) { + spin_lock(&thread->prio_lock); + if (thread->prio_state == BINDER_PRIO_PENDING) + thread->prio_state = BINDER_PRIO_SET; + spin_unlock(&thread->prio_lock); return; + } has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE); From 3cf0f8245dbc54c81b8994d530e47232be36e5eb Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 12 May 2021 17:52:58 +0800 Subject: [PATCH 08/24] BACKPORT: f2fs: compress: remove unneeded preallocation commit 8f1d49832636 upstream. We will reserve iblocks for compression saved, so during compressed cluster overwrite, we don't need to preallocate blocks for later write. In addition, it adds a bug_on to detect wrong reserved iblock number in __f2fs_cluster_blocks(). Bug fix in the original patch by Jaegeuk: If we released compressed blocks having an immutable bit, we can see less number of compressed block addresses. Let's fix wrong BUG_ON. Bug: 237904436 Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Change-Id: I673af616581a9e7bf711e60d1588856f24f65dc9 --- fs/f2fs/compress.c | 27 +++------------------------ fs/f2fs/file.c | 4 ---- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 1a829bec2051..cdb98a4364e1 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -809,6 +809,9 @@ static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr) ret++; } } + + f2fs_bug_on(F2FS_I_SB(inode), + !compr && ret != cc->cluster_size && !IS_IMMUTABLE(inode)); } fail: f2fs_put_dnode(&dn); @@ -879,21 +882,16 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); struct address_space *mapping = cc->inode->i_mapping; struct page *page; - struct dnode_of_data dn; sector_t last_block_in_bio; unsigned fgp_flag = FGP_LOCK | FGP_WRITE | FGP_CREAT; pgoff_t start_idx = start_idx_of_cluster(cc); int i, ret; - bool prealloc; retry: ret = f2fs_cluster_blocks(cc, false); if (ret <= 0) return ret; - /* compressed case */ - prealloc = (ret < cc->cluster_size); - ret = f2fs_init_compress_ctx(cc); if (ret) return ret; @@ -949,25 +947,6 @@ retry: } } - if (prealloc) { - __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); - - set_new_dnode(&dn, cc->inode, NULL, NULL, 0); - - for (i = cc->cluster_size - 1; i > 0; i--) { - ret = f2fs_get_block(&dn, start_idx + i); - if (ret) { - i = cc->cluster_size; - break; - } - - if (dn.data_blkaddr != NEW_ADDR) - break; - } - - __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); - } - if (likely(!ret)) { *fsdata = cc->rpages; *pagep = cc->rpages[offset_in_cluster(cc, index)]; diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index b42b1fa737bd..d2e863eee10d 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -80,10 +80,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) err = ret; goto err; } else if (ret) { - if (ret < F2FS_I(inode)->i_cluster_size) { - err = -EAGAIN; - goto err; - } need_alloc = false; } } From 862905912886ca4e1aee337b14ca21662d834395 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Thu, 30 Jul 2020 14:09:28 +0900 Subject: [PATCH 09/24] BACKPORT: f2fs: make file immutable even if releasing zero compression block commit 567c4bf54a85 upstream. When we use F2FS_IOC_RELEASE_COMPRESS_BLOCKS ioctl, if we can't find any compressed blocks in the file even with large file size, the ioctl just ends up without changing the file's status as immutable. It makes the user, who expects that the file is immutable when it returns successfully, confused. Bug: 237904436 Signed-off-by: Daeho Jeong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Change-Id: I2c96428442e69b69c7064096d2e1ce8e2b99cc09 --- fs/f2fs/file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index d2e863eee10d..42b2e200efb1 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -3528,14 +3528,14 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) if (ret) goto out; - if (!F2FS_I(inode)->i_compr_blocks) - goto out; - F2FS_I(inode)->i_flags |= F2FS_IMMUTABLE_FL; f2fs_set_inode_flags(inode); inode->i_ctime = current_time(inode); f2fs_mark_inode_dirty_sync(inode, true); + if (!F2FS_I(inode)->i_compr_blocks) + goto out; + down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); down_write(&F2FS_I(inode)->i_mmap_sem); From d2e72fa0b995aa3047b38157ab5c647c927fe019 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Tue, 8 Sep 2020 11:44:10 +0900 Subject: [PATCH 10/24] BACKPORT: f2fs: change i_compr_blocks of inode to atomic value commit c2759ebaf7e8 upstream. writepages() can be concurrently invoked for the same file by different threads such as a thread fsyncing the file and a kworker kernel thread. So, changing i_compr_blocks without protection is racy and we need to protect it by changing it with atomic type value. Plus, we don't need a 64bit value for i_compr_blocks, so just we will use a atomic value, not atomic64. Bug: 237904436 Signed-off-by: Daeho Jeong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Change-Id: I11f837249078d1b7ef50ac9c156c375542c714b3 --- fs/f2fs/f2fs.h | 17 ++++++++++------- fs/f2fs/file.c | 22 ++++++++++++---------- fs/f2fs/inode.c | 11 +++++++---- fs/f2fs/super.c | 1 + 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 4103f757476d..1573e26f1c67 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -814,7 +814,7 @@ struct f2fs_inode_info { struct timespec64 i_disk_time[4];/* inode disk times */ /* for file compress */ - u64 i_compr_blocks; /* # of compressed blocks */ + atomic_t i_compr_blocks; /* # of compressed blocks */ unsigned char i_compress_algorithm; /* algorithm type */ unsigned char i_log_cluster_size; /* log of cluster size */ unsigned int i_cluster_size; /* cluster size */ @@ -3942,17 +3942,19 @@ static inline void set_compress_context(struct inode *inode) f2fs_mark_inode_dirty_sync(inode, true); } -static inline u64 f2fs_disable_compressed_file(struct inode *inode) +static inline u32 f2fs_disable_compressed_file(struct inode *inode) { struct f2fs_inode_info *fi = F2FS_I(inode); + u32 i_compr_blocks; if (!f2fs_compressed_file(inode)) return 0; if (S_ISREG(inode->i_mode)) { if (get_dirty_pages(inode)) return 1; - if (fi->i_compr_blocks) - return fi->i_compr_blocks; + i_compr_blocks = atomic_read(&fi->i_compr_blocks); + if (i_compr_blocks) + return i_compr_blocks; } fi->i_flags &= ~F2FS_COMPR_FL; @@ -4070,16 +4072,17 @@ static inline void f2fs_i_compr_blocks_update(struct inode *inode, u64 blocks, bool add) { int diff = F2FS_I(inode)->i_cluster_size - blocks; + struct f2fs_inode_info *fi = F2FS_I(inode); /* don't update i_compr_blocks if saved blocks were released */ - if (!add && !F2FS_I(inode)->i_compr_blocks) + if (!add && !atomic_read(&fi->i_compr_blocks)) return; if (add) { - F2FS_I(inode)->i_compr_blocks += diff; + atomic_add(diff, &fi->i_compr_blocks); stat_add_compr_blocks(inode, diff); } else { - F2FS_I(inode)->i_compr_blocks -= diff; + atomic_sub(diff, &fi->i_compr_blocks); stat_sub_compr_blocks(inode, diff); } f2fs_mark_inode_dirty_sync(inode, true); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 42b2e200efb1..de5c5781c12a 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -557,7 +557,7 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count) bool compressed_cluster = false; int cluster_index = 0, valid_blocks = 0; int cluster_size = F2FS_I(dn->inode)->i_cluster_size; - bool released = !F2FS_I(dn->inode)->i_compr_blocks; + bool released = !atomic_read(&F2FS_I(dn->inode)->i_compr_blocks); if (IS_INODE(dn->node_page) && f2fs_has_extra_attr(dn->inode)) base = get_extra_isize(dn->inode); @@ -3429,7 +3429,7 @@ static int f2fs_get_compress_blocks(struct file *filp, unsigned long arg) if (!f2fs_compressed_file(inode)) return -EINVAL; - blocks = F2FS_I(inode)->i_compr_blocks; + blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks); return put_user(blocks, (u64 __user *)arg); } @@ -3533,7 +3533,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) inode->i_ctime = current_time(inode); f2fs_mark_inode_dirty_sync(inode, true); - if (!F2FS_I(inode)->i_compr_blocks) + if (!atomic_read(&F2FS_I(inode)->i_compr_blocks)) goto out; down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); @@ -3581,14 +3581,15 @@ out: if (ret >= 0) { ret = put_user(released_blocks, (u64 __user *)arg); - } else if (released_blocks && F2FS_I(inode)->i_compr_blocks) { + } else if (released_blocks && + atomic_read(&F2FS_I(inode)->i_compr_blocks)) { set_sbi_flag(sbi, SBI_NEED_FSCK); f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx " - "iblocks=%llu, released=%u, compr_blocks=%llu, " + "iblocks=%llu, released=%u, compr_blocks=%u, " "run fsck to fix.", __func__, inode->i_ino, inode->i_blocks, released_blocks, - F2FS_I(inode)->i_compr_blocks); + atomic_read(&F2FS_I(inode)->i_compr_blocks)); } return ret; @@ -3676,7 +3677,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) if (ret) return ret; - if (F2FS_I(inode)->i_compr_blocks) + if (atomic_read(&F2FS_I(inode)->i_compr_blocks)) goto out; f2fs_balance_fs(F2FS_I_SB(inode), true); @@ -3740,14 +3741,15 @@ out: if (ret >= 0) { ret = put_user(reserved_blocks, (u64 __user *)arg); - } else if (reserved_blocks && F2FS_I(inode)->i_compr_blocks) { + } else if (reserved_blocks && + atomic_read(&F2FS_I(inode)->i_compr_blocks)) { set_sbi_flag(sbi, SBI_NEED_FSCK); f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx " - "iblocks=%llu, reserved=%u, compr_blocks=%llu, " + "iblocks=%llu, reserved=%u, compr_blocks=%u, " "run fsck to fix.", __func__, inode->i_ino, inode->i_blocks, reserved_blocks, - F2FS_I(inode)->i_compr_blocks); + atomic_read(&F2FS_I(inode)->i_compr_blocks)); } return ret; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 446e8d6fb5a2..ec22c2343c80 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -442,7 +442,8 @@ static int do_read_inode(struct inode *inode) (fi->i_flags & F2FS_COMPR_FL)) { if (F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_log_cluster_size)) { - fi->i_compr_blocks = le64_to_cpu(ri->i_compr_blocks); + atomic_set(&fi->i_compr_blocks, + le64_to_cpu(ri->i_compr_blocks)); fi->i_compress_algorithm = ri->i_compress_algorithm; fi->i_log_cluster_size = ri->i_log_cluster_size; fi->i_cluster_size = 1 << fi->i_log_cluster_size; @@ -460,7 +461,7 @@ static int do_read_inode(struct inode *inode) stat_inc_inline_inode(inode); stat_inc_inline_dir(inode); stat_inc_compr_inode(inode); - stat_add_compr_blocks(inode, F2FS_I(inode)->i_compr_blocks); + stat_add_compr_blocks(inode, atomic_read(&fi->i_compr_blocks)); return 0; } @@ -619,7 +620,8 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page) F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize, i_log_cluster_size)) { ri->i_compr_blocks = - cpu_to_le64(F2FS_I(inode)->i_compr_blocks); + cpu_to_le64(atomic_read( + &F2FS_I(inode)->i_compr_blocks)); ri->i_compress_algorithm = F2FS_I(inode)->i_compress_algorithm; ri->i_log_cluster_size = @@ -768,7 +770,8 @@ no_delete: stat_dec_inline_dir(inode); stat_dec_inline_inode(inode); stat_dec_compr_inode(inode); - stat_sub_compr_blocks(inode, F2FS_I(inode)->i_compr_blocks); + stat_sub_compr_blocks(inode, + atomic_read(&F2FS_I(inode)->i_compr_blocks)); if (likely(!f2fs_cp_error(sbi) && !is_sbi_flag_set(sbi, SBI_CP_DISABLED))) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 92f279cdaea1..b3aa350ccdd1 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1054,6 +1054,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) /* Initialize f2fs-specific inode info */ atomic_set(&fi->dirty_pages, 0); + atomic_set(&fi->i_compr_blocks, 0); init_rwsem(&fi->i_sem); spin_lock_init(&fi->i_size_lock); INIT_LIST_HEAD(&fi->dirty_list); From d2972f90d6f1c3948e94a99baa4eef080082eb8a Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 26 Dec 2020 18:07:01 +0800 Subject: [PATCH 11/24] BACKPORT: f2fs: enforce the immutable flag on open files commit e0fcd01510ad upstream. This patch ports commit 02b016ca7f99 ("ext4: enforce the immutable flag on open files") to f2fs. According to the chattr man page, "a file with the 'i' attribute cannot be modified..." Historically, this was only enforced when the file was opened, per the rest of the description, "... and the file can not be opened in write mode". There is general agreement that we should standardize all file systems to prevent modifications even for files that were opened at the time the immutable flag is set. Eventually, a change to enforce this at the VFS layer should be landing in mainline. Bug: 237904436 Cc: stable@kernel.org Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Change-Id: I9c74498ed3174309ff14158c8c3ad6dee6e1c8ca --- fs/f2fs/file.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index de5c5781c12a..7ce9e4a1a263 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -58,6 +58,9 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) bool need_alloc = true; int err = 0; + if (unlikely(IS_IMMUTABLE(inode))) + return VM_FAULT_SIGBUS; + if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; goto err; @@ -874,6 +877,14 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) return -EIO; + if (unlikely(IS_IMMUTABLE(inode))) + return -EPERM; + + if (unlikely(IS_APPEND(inode) && + (attr->ia_valid & (ATTR_MODE | ATTR_UID | + ATTR_GID | ATTR_TIMES_SET)))) + return -EPERM; + if ((attr->ia_valid & ATTR_SIZE) && !f2fs_is_compress_backend_ready(inode)) return -EOPNOTSUPP; @@ -3888,6 +3899,11 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) inode_lock(inode); } + if (unlikely(IS_IMMUTABLE(inode))) { + ret = -EPERM; + goto unlock; + } + ret = generic_write_checks(iocb, from); if (ret > 0) { bool preallocated = false; @@ -3952,6 +3968,7 @@ write: if (ret > 0) f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret); } +unlock: inode_unlock(inode); out: trace_f2fs_file_write_iter(inode, iocb->ki_pos, From 601b2ed3e6948e4583c6760247702a894aded9af Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 25 May 2021 11:39:35 -0700 Subject: [PATCH 12/24] BACKPORT: f2fs: introduce FI_COMPRESS_RELEASED instead of using IMMUTABLE bit commit c61404153eb6 upstream. Once we release compressed blocks, we used to set IMMUTABLE bit. But it turned out it disallows every fs operations which we don't need for compression. Let's just prevent writing data only. Bug: 237904436 Signed-off-by: Jaegeuk Kim Change-Id: I3f91a67da56fe26e39a776a5bc595aa809dc804b --- fs/f2fs/compress.c | 3 ++- fs/f2fs/f2fs.h | 6 ++++++ fs/f2fs/file.c | 18 ++++++++++++------ include/linux/f2fs_fs.h | 1 + 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index cdb98a4364e1..e8bd9d205ce6 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -811,7 +811,8 @@ static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr) } f2fs_bug_on(F2FS_I_SB(inode), - !compr && ret != cc->cluster_size && !IS_IMMUTABLE(inode)); + !compr && ret != cc->cluster_size && + !is_inode_flag_set(cc->inode, FI_COMPRESS_RELEASED)); } fail: f2fs_put_dnode(&dn); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 1573e26f1c67..f988467a156e 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -762,6 +762,7 @@ enum { FI_VERITY_IN_PROGRESS, /* building fs-verity Merkle tree */ FI_COMPRESSED_FILE, /* indicate file's data can be compressed */ FI_MMAP_FILE, /* indicate file was mmapped */ + FI_COMPRESS_RELEASED, /* compressed blocks were released */ FI_MAX, /* max flag, never be used */ }; @@ -2663,6 +2664,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode, case FI_DATA_EXIST: case FI_INLINE_DOTS: case FI_PIN_FILE: + case FI_COMPRESS_RELEASED: f2fs_mark_inode_dirty_sync(inode, true); } } @@ -2784,6 +2786,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri) set_bit(FI_EXTRA_ATTR, fi->flags); if (ri->i_inline & F2FS_PIN_FILE) set_bit(FI_PIN_FILE, fi->flags); + if (ri->i_inline & F2FS_COMPRESS_RELEASED) + set_bit(FI_COMPRESS_RELEASED, fi->flags); } static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) @@ -2804,6 +2808,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |= F2FS_EXTRA_ATTR; if (is_inode_flag_set(inode, FI_PIN_FILE)) ri->i_inline |= F2FS_PIN_FILE; + if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) + ri->i_inline |= F2FS_COMPRESS_RELEASED; } static inline int f2fs_has_extra_attr(struct inode *inode) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 7ce9e4a1a263..18cb286a07ad 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -61,6 +61,9 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) if (unlikely(IS_IMMUTABLE(inode))) return VM_FAULT_SIGBUS; + if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) + return VM_FAULT_SIGBUS; + if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; goto err; @@ -3530,7 +3533,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) goto out; } - if (IS_IMMUTABLE(inode)) { + if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { ret = -EINVAL; goto out; } @@ -3539,8 +3542,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) if (ret) goto out; - F2FS_I(inode)->i_flags |= F2FS_IMMUTABLE_FL; - f2fs_set_inode_flags(inode); + set_inode_flag(inode, FI_COMPRESS_RELEASED); inode->i_ctime = current_time(inode); f2fs_mark_inode_dirty_sync(inode, true); @@ -3695,7 +3697,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) inode_lock(inode); - if (!IS_IMMUTABLE(inode)) { + if (!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { ret = -EINVAL; goto unlock_inode; } @@ -3740,8 +3742,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) up_write(&F2FS_I(inode)->i_mmap_sem); if (ret >= 0) { - F2FS_I(inode)->i_flags &= ~F2FS_IMMUTABLE_FL; - f2fs_set_inode_flags(inode); + clear_inode_flag(inode, FI_COMPRESS_RELEASED); inode->i_ctime = current_time(inode); f2fs_mark_inode_dirty_sync(inode, true); } @@ -3904,6 +3905,11 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) goto unlock; } + if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { + ret = -EPERM; + goto unlock; + } + ret = generic_write_checks(iocb, from); if (ret > 0) { bool preallocated = false; diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index a5dbb57a687f..2a4b89735544 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -229,6 +229,7 @@ struct f2fs_extent { #define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20 /* file having extra attribute */ #define F2FS_PIN_FILE 0x40 /* file should not be gced */ +#define F2FS_COMPRESS_RELEASED 0x80 /* file released compressed blocks */ struct f2fs_inode { __le16 i_mode; /* file mode */ From d7b2931cce22c39bee1c4e2234c25668d0cebe7e Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 26 Jan 2021 17:00:42 -0800 Subject: [PATCH 13/24] FROMGIT: f2fs: flush data when enabling checkpoint back During checkpoint=disable period, f2fs bypasses all the synchronous IOs such as sync and fsync. So, when enabling it back, we must flush all of them in order to keep the data persistent. Otherwise, suddern power-cut right after enabling checkpoint will cause data loss. Bug: 171063590 Fixes: 4354994f097d ("f2fs: checkpoint disabling") Cc: stable@vger.kernel.org Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim (cherry picked from commit 8d52dbb373579b48f5758dd0cdd2ac0fb4e5be7f git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git dev) Signed-off-by: Jaegeuk Kim Change-Id: Iaca2d6fc1841fffa8677d5d592732c94241fb3fb --- fs/f2fs/super.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index b3aa350ccdd1..22a7bb8a33eb 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1780,6 +1780,9 @@ restore_flag: static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) { + /* we should flush all the data to keep data consistency */ + sync_inodes_sb(sbi->sb); + down_write(&sbi->gc_lock); f2fs_dirty_to_prefree(sbi); From f711e743ecfe09a1a1a8813cf68fa41bca58b2ea Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 19 Aug 2021 14:00:57 -0700 Subject: [PATCH 14/24] UPSTREAM: f2fs: guarantee to write dirty data when enabling checkpoint back We must flush all the dirty data when enabling checkpoint back. Let's guarantee that first by adding a retry logic on sync_inodes_sb(). In addition to that, this patch adds to flush data in fsync when checkpoint is disabled, which can mitigate the sync_inodes_sb() failures in advance. Bug: 194449609 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim (cherry picked from commit dddd3d65293a52c2c3850c19b1e5115712e534d8) Change-Id: I5bbef7386ddbb44fd925262fb68a8ef0a4960993 (cherry picked from commit 90c60a51f510da64554abe9c6b748ed624543192) --- fs/f2fs/file.c | 5 ++--- fs/f2fs/super.c | 11 ++++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 18cb286a07ad..645032ff4ada 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -260,8 +260,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, }; unsigned int seq_id = 0; - if (unlikely(f2fs_readonly(inode->i_sb) || - is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + if (unlikely(f2fs_readonly(inode->i_sb))) return 0; trace_f2fs_sync_file_enter(inode); @@ -275,7 +274,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, ret = file_write_and_wait_range(file, start, end); clear_inode_flag(inode, FI_NEED_IPU); - if (ret) { + if (ret || is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret); return ret; } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 22a7bb8a33eb..f8f67446d6c8 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1780,8 +1780,17 @@ restore_flag: static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) { + int retry = DEFAULT_RETRY_IO_COUNT; + /* we should flush all the data to keep data consistency */ - sync_inodes_sb(sbi->sb); + do { + sync_inodes_sb(sbi->sb); + cond_resched(); + congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); + } while (get_pages(sbi, F2FS_DIRTY_DATA) && retry--); + + if (unlikely(retry < 0)) + f2fs_warn(sbi, "checkpoint=enable has some unwritten data."); down_write(&sbi->gc_lock); f2fs_dirty_to_prefree(sbi); From 7e4f9722315dbe0b6c7b5cb32590d6f48ed160dd Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 30 Nov 2021 10:22:39 -0800 Subject: [PATCH 15/24] ANDROID: f2fs: check nr_pages for readahead Old kernel versions have the issue, since upstream f2fs removed this flow by: commit d4384de9eb5e ("f2fs: Remove readahead collision detection"). Bug: 206148707 Signed-off-by: Jaegeuk Kim Fixes: 8c95605c41a1 ("f2fs: avoid readahead race condition") Change-Id: I3a95f0b436d0a5ee420f41d892401a8d79d4fe79 --- fs/f2fs/data.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index d377ea025f74..b30fbd5fd545 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2359,6 +2359,10 @@ int f2fs_mpage_readpages(struct address_space *mapping, unsigned max_nr_pages = nr_pages; int ret = 0; + /* this is real from f2fs_merkle_tree_readahead() in old kernel only. */ + if (!nr_pages) + return 0; + map.m_pblk = 0; map.m_lblk = 0; map.m_len = 0; From 17bdd623f3f85b3bffc44ec26acc5b7250d813b4 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Thu, 4 Nov 2021 16:22:01 +0800 Subject: [PATCH 16/24] UPSTREAM: f2fs: fix UAF in f2fs_available_free_memory if2fs_fill_super -> f2fs_build_segment_manager -> create_discard_cmd_control -> f2fs_start_discard_thread It invokes kthread_run to create a thread and run issue_discard_thread. However, if f2fs_build_node_manager fails, the control flow goes to free_nm and calls f2fs_destroy_node_manager. This function will free sbi->nm_info. However, if issue_discard_thread accesses sbi->nm_info after the deallocation, but before the f2fs_stop_discard_thread, it will cause UAF(Use-after-free). -> f2fs_destroy_segment_manager -> destroy_discard_cmd_control -> f2fs_stop_discard_thread Fix this by stopping discard thread before f2fs_destroy_node_manager. Note that, the commit d6d2b491a82e1 introduces the call of f2fs_available_free_memory into issue_discard_thread. Cc: stable@vger.kernel.org Fixes: d6d2b491a82e ("f2fs: allow to change discard policy based on cached discard cmds") Signed-off-by: Dongliang Mu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim (cherry picked from commit 5429c9dbc9025f9a166f64e22e3a69c94fd5b29b) Signed-off-by: Lee Jones Change-Id: If121b453455b11b2aded8ba8a3899faad431dbd3 --- fs/f2fs/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index f8f67446d6c8..5cf915a636a2 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3914,6 +3914,8 @@ free_node_inode: free_stats: f2fs_destroy_stats(sbi); free_nm: + /* stop discard thread before destroying node manager */ + f2fs_stop_discard_thread(sbi); f2fs_destroy_node_manager(sbi); free_sm: f2fs_destroy_segment_manager(sbi); From 26eb689452c87bf2ffc6f680215a1ceefd2328ab Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 3 Aug 2022 20:33:54 -0700 Subject: [PATCH 17/24] BACKPORT: f2fs: do not set compression bit if kernel doesn't support If kernel doesn't have CONFIG_F2FS_FS_COMPRESSION, a file having FS_COMPR_FL via ioctl(FS_IOC_SETFLAGS) is unaccessible due to f2fs_is_compress_backend_ready(). Let's avoid it. Bug: 240921972 Signed-off-by: Jaegeuk Kim (cherry picked from commit d5a44717f6e0f0943808671e36b1909619707016) Change-Id: Ieb0f8945175ea5ccb0060690e882f054360fb8f0 --- fs/f2fs/f2fs.h | 7 ++++++- fs/f2fs/file.c | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index f988467a156e..1caa0e72cd64 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3932,8 +3932,9 @@ static inline int f2fs_init_compress_mempool(void) { return 0; } static inline void f2fs_destroy_compress_mempool(void) { } #endif -static inline void set_compress_context(struct inode *inode) +static inline int set_compress_context(struct inode *inode) { +#ifdef CONFIG_F2FS_FS_COMPRESSION struct f2fs_sb_info *sbi = F2FS_I_SB(inode); F2FS_I(inode)->i_compress_algorithm = @@ -3946,6 +3947,10 @@ static inline void set_compress_context(struct inode *inode) set_inode_flag(inode, FI_COMPRESSED_FILE); stat_inc_compr_inode(inode); f2fs_mark_inode_dirty_sync(inode, true); + return 0; +#else + return -EOPNOTSUPP; +#endif } static inline u32 f2fs_disable_compressed_file(struct inode *inode) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 645032ff4ada..c62855f9cbd4 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1847,8 +1847,8 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) if (iflags & F2FS_COMPR_FL) { if (!f2fs_may_compress(inode)) return -EINVAL; - - set_compress_context(inode); + if (set_compress_context(inode)) + return -EOPNOTSUPP; } } if ((iflags ^ masked_flags) & F2FS_NOCOMP_FL) { From f19e834b290bf611931266b4535ee4fde5f18012 Mon Sep 17 00:00:00 2001 From: Chetan C R Date: Wed, 20 Jul 2022 11:37:05 +0530 Subject: [PATCH 18/24] soc: qcom: socinfo: Get SKU ID from kernel command line Get the softsku_idx value by reading it from kernel command line and write it to sysfs file So, that post boot scripts get this values. Change-Id: I7a46b3d3d3db7d34ab4f29d5fe1ea79a5ed654d1 Signed-off-by: Chetan C R --- drivers/soc/qcom/socinfo.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index ae7a1d7bc62a..28da4da94895 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -187,6 +187,9 @@ static struct socinfo { #define SMEM_IMAGE_VERSION_OEM_OFFSET 95 #define SMEM_IMAGE_VERSION_PARTITION_APPS 10 +int softsku_id; +module_param_named(softsku_id, softsku_id, int, 0644); + /* Version 2 */ static uint32_t socinfo_get_raw_id(void) { From ce70d10e46302d6e49163e796314b14190c95b54 Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Thu, 1 Sep 2022 19:24:58 +0530 Subject: [PATCH 19/24] defconfig: sdxlemur: Enable configs on sdxlemur Enable some additional configs on sdxlemur. Change-Id: If4bfdad7b6755b5f5532ec5b21d6272d7894fd34 Signed-off-by: Rohit Agarwal --- arch/arm/configs/vendor/sdxlemur.config | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 6513330d1a85..f9323a93463e 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -468,3 +468,39 @@ CONFIG_NET_ACT_CT=y CONFIG_NET_TC_SKB_EXT=y CONFIG_NET_SCH_FIFO=y CONFIG_NET_SCHED_ACT_MPLS_QGKI=y +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=y +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_CRYPT is not set +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_INIT is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +CONFIG_DM_VERITY=y +# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set +# CONFIG_DM_VERITY_AVB is not set +# CONFIG_DM_VERITY_FEC is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_DM_BOW is not set +# CONFIG_DEVMEM is not set +CONFIG_DAX=y +CONFIG_LSM_MMAP_MIN_ADDR=32768 From fd5a3b3d328d5ab95d6a543aed89c0e12580c8d8 Mon Sep 17 00:00:00 2001 From: Mohammed Siddiq Date: Fri, 12 Nov 2021 10:57:00 +0530 Subject: [PATCH 20/24] cnss2: Add code to fallback to non-contiguous FW mem allocation Add code to fallback to non-contiguous FW mem allocation on failure to allocate contiguous memory. Change-Id: Idbc7ff7f9ea4d2157e3b549dde8ee090a0f0b412 Signed-off-by: Mohammed Siddiq --- drivers/net/wireless/cnss2/pci.c | 43 +++++++++++++++++++++++--------- drivers/net/wireless/cnss2/qmi.c | 7 ++++-- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 6e4530cdd0db..4b8f78da518d 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ #include #include @@ -3984,15 +3986,27 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) for (i = 0; i < plat_priv->fw_mem_seg_len; i++) { if (!fw_mem[i].va && fw_mem[i].size) { +retry: fw_mem[i].va = dma_alloc_attrs(dev, fw_mem[i].size, &fw_mem[i].pa, GFP_KERNEL, fw_mem[i].attrs); if (!fw_mem[i].va) { + if ((fw_mem[i].attrs & + DMA_ATTR_FORCE_CONTIGUOUS)) { + fw_mem[i].attrs &= + ~DMA_ATTR_FORCE_CONTIGUOUS; + + cnss_pr_dbg("Fallback to non-contiguous memory for FW, Mem type: %u\n", + fw_mem[i].type); + goto retry; + } + cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n", fw_mem[i].size, fw_mem[i].type); - BUG(); + CNSS_ASSERT(0); + return -ENOMEM; } } } @@ -5083,17 +5097,21 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic) mhi_dump_sfr(pci_priv->mhi_ctrl); - cnss_pr_dbg("Collect remote heap dump segment\n"); - for (i = 0, j = 0; i < plat_priv->fw_mem_seg_len; i++) { if (fw_mem[i].type == CNSS_MEM_TYPE_DDR) { - cnss_pci_add_dump_seg(pci_priv, dump_seg, - CNSS_FW_REMOTE_HEAP, j, - fw_mem[i].va, fw_mem[i].pa, - fw_mem[i].size); - dump_seg++; - dump_data->nentries++; - j++; + if (fw_mem[i].attrs & DMA_ATTR_FORCE_CONTIGUOUS) { + cnss_pr_dbg("Collect remote heap dump segment\n"); + cnss_pci_add_dump_seg(pci_priv, dump_seg, + CNSS_FW_REMOTE_HEAP, j, + fw_mem[i].va, + fw_mem[i].pa, + fw_mem[i].size); + dump_seg++; + dump_data->nentries++; + j++; + } else { + cnss_pr_dbg("Skip remote heap dumps as it is non-contiguous\n"); + } } } @@ -5138,7 +5156,8 @@ void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv) } for (i = 0, j = 0; i < plat_priv->fw_mem_seg_len; i++) { - if (fw_mem[i].type == CNSS_MEM_TYPE_DDR) { + if (fw_mem[i].type == CNSS_MEM_TYPE_DDR && + (fw_mem[i].attrs & DMA_ATTR_FORCE_CONTIGUOUS)) { cnss_pci_remove_dump_seg(pci_priv, dump_seg, CNSS_FW_REMOTE_HEAP, j, fw_mem[i].va, fw_mem[i].pa, diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index d0f85455de8e..157c90506d30 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ #include #include @@ -2206,7 +2208,8 @@ static void cnss_wlfw_request_mem_ind_cb(struct qmi_handle *qmi_wlfw, ind_msg->mem_seg[i].size, ind_msg->mem_seg[i].type); plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type; plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size; - if (plat_priv->fw_mem[i].type == CNSS_MEM_TYPE_DDR) + if (!plat_priv->fw_mem[i].va && + plat_priv->fw_mem[i].type == CNSS_MEM_TYPE_DDR) plat_priv->fw_mem[i].attrs |= DMA_ATTR_FORCE_CONTIGUOUS; } From 5f6ae20b0c460b9bfb1c58d0668d7d44eeb9d17b Mon Sep 17 00:00:00 2001 From: Chetan C R Date: Fri, 9 Sep 2022 14:09:17 +0530 Subject: [PATCH 21/24] soc: qcom: socinfo: correct the name of softsku_id Correct the softsku_id name to softsku_idx So, that post boot scripts get this values. Change-Id: Id7674a0557a99586b6b26f3cb3eab2819c90d272 Signed-off-by: Chetan C R --- drivers/soc/qcom/socinfo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 28da4da94895..89b16a71793f 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -187,8 +187,8 @@ static struct socinfo { #define SMEM_IMAGE_VERSION_OEM_OFFSET 95 #define SMEM_IMAGE_VERSION_PARTITION_APPS 10 -int softsku_id; -module_param_named(softsku_id, softsku_id, int, 0644); +int softsku_idx; +module_param_named(softsku_idx, softsku_idx, int, 0644); /* Version 2 */ static uint32_t socinfo_get_raw_id(void) From 747163a77d9d6c9929399361f651e0eb1fc3c4cc Mon Sep 17 00:00:00 2001 From: Zeng Tao Date: Fri, 17 Jan 2020 09:52:52 +0800 Subject: [PATCH 22/24] cpu-topology: Don't error on more than CONFIG_NR_CPUS CPUs in device tree When the kernel is configured with CONFIG_NR_CPUS smaller than the number of CPU nodes in the device tree(DT), all the CPU nodes parsing done to fetch topology information will fail. This is not reasonable as it is valid to have all the physical CPUs in the system in the DT. Let us just skip such CPU DT nodes that are not used in the kernel rather than returning an error. Change-Id: I56c6629d341b0e143372f8d643abb0c012f7e5ae Reviewed-by: Sudeep Holla Signed-off-by: Zeng Tao Link: https://lore.kernel.org/r/1579225973-32423-1-git-send-email-prime.zeng@hisilicon.com Git-commit: f3c19481820cca412a768ae1d6737f59b68acfed Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Greg Kroah-Hartman Signed-off-by: Shivnandan Kumar --- drivers/base/arch_topology.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 27fdce4dc835..81169261a549 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -278,6 +278,16 @@ core_initcall(free_raw_capacity); #endif #if defined(CONFIG_ARM64) || defined(CONFIG_RISCV) +/* + * This function returns the logic cpu number of the node. + * There are basically three kinds of return values: + * (1) logic cpu number which is > 0. + * (2) -ENODEV when the device tree(DT) node is valid and found in the DT but + * there is no possible logical CPU in the kernel to match. This happens + * when CONFIG_NR_CPUS is configure to be smaller than the number of + * CPU nodes in DT. We need to just ignore this case. + * (3) -1 if the node does not exist in the device tree + */ static int __init get_cpu_for_node(struct device_node *node) { struct device_node *cpu_node; @@ -291,7 +301,8 @@ static int __init get_cpu_for_node(struct device_node *node) if (cpu >= 0) topology_parse_cpu_capacity(cpu_node, cpu); else - pr_crit("Unable to find CPU node for %pOF\n", cpu_node); + pr_info("CPU node for %pOF exist but the possible cpu range is :%*pbl\n", + cpu_node, cpumask_pr_args(cpu_possible_mask)); of_node_put(cpu_node); return cpu; @@ -316,9 +327,8 @@ static int __init parse_core(struct device_node *core, int package_id, cpu_topology[cpu].package_id = package_id; cpu_topology[cpu].core_id = core_id; cpu_topology[cpu].thread_id = i; - } else { - pr_err("%pOF: Can't get CPU for thread\n", - t); + } else if (cpu != -ENODEV) { + pr_err("%pOF: Can't get CPU for thread\n", t); of_node_put(t); return -EINVAL; } @@ -337,7 +347,7 @@ static int __init parse_core(struct device_node *core, int package_id, cpu_topology[cpu].package_id = package_id; cpu_topology[cpu].core_id = core_id; - } else if (leaf) { + } else if (leaf && cpu != -ENODEV) { pr_err("%pOF: Can't get CPU for leaf core\n", core); return -EINVAL; } From e7b535d30d035ecd16e083059a92475b3aad8209 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Tue, 9 Aug 2022 20:53:28 -0700 Subject: [PATCH 23/24] msm: ipa3: Add multi IDU support for external router mode FR Update ext router mode IOCTL to get an array of delegated prefixes and their corresponding IDU WAN IP. Change-Id: I8ea6a98f8f0f894409e9c5af4db0bd37b46778b2 Signed-off-by: Michael Adisumarta --- include/uapi/linux/msm_ipa.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 63f21763394a..b6ad02a7ea3c 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -219,6 +219,11 @@ #define IPA_CV2X_SUPPORT +/** + * Max number of delegated IDUs for prefix delegation FR + */ +#define IPA_PREFIX_MAPPING_MAX 16 + /** * the attributes of the rule (routing or filtering) */ @@ -3423,14 +3428,20 @@ enum ipa_ext_router_mode { * struct ipa_ioc_ext_router_info - provide ext_router info * @ipa_ext_router_mode: prefix sharing, prefix delegation, or disabled mode * @pdn_name: PDN interface name - * @ipv6_addr: the prefix addr used for dummy or delegated prefixes + * @ipv6_addr: the prefix addr used for the dummy prefix. (prefix sharing mode) * @ipv6_mask: the ipv6 mask used to mask above addr to get the correct prefix + * @num_of_del_prefix_mapping: number of delegated prefix to IDU IP mapping + * @idu_del_wan_ip: array of IDU WAN IP to be mapped to a delegated prefix + * @idu_del_client_prefix: Array of delegated prefixes */ struct ipa_ioc_ext_router_info { enum ipa_ext_router_mode mode; char pdn_name[IPA_RESOURCE_NAME_MAX]; uint32_t ipv6_addr[4]; uint32_t ipv6_mask[4]; + int num_of_idu_prefix_mapping; + uint32_t idu_wan_ip[IPA_PREFIX_MAPPING_MAX][4]; + uint32_t idu_client_prefix[IPA_PREFIX_MAPPING_MAX][4]; }; /** From 1414389bb28129335b6b1253ca0b1a7b6568e2f8 Mon Sep 17 00:00:00 2001 From: rnamala Date: Wed, 21 Sep 2022 11:13:42 +0530 Subject: [PATCH 24/24] msm: adsprpc: fix UAF process init_mem Process init memory allowed to initialize only once to fix possible improper acecss from remote processor. Change-Id: Ic1a13738146fcf0d170abd76b50bdc6a75871755 Acked-by: Ranjith Goud Namala Signed-off-by: rnamala --- drivers/char/adsprpc.c | 21 +++++++++++---------- drivers/char/adsprpc_shared.h | 5 +++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 1856ed432056..56d93e1ccb27 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -656,7 +656,7 @@ struct fastrpc_file { /* Flag to indicate ram dump collection status*/ bool is_ramdump_pend; /* Flag to indicate dynamic process creation status*/ - bool in_process_create; + enum fastrpc_process_create_state dsp_process_state; }; static struct fastrpc_apps gfa; @@ -3755,13 +3755,13 @@ static int fastrpc_init_create_dynamic_process(struct fastrpc_file *fl, } inbuf; spin_lock(&fl->hlock); - if (fl->in_process_create) { + if (fl->dsp_process_state) { err = -EALREADY; ADSPRPC_ERR("Already in create dynamic process\n"); spin_unlock(&fl->hlock); return err; } - fl->in_process_create = true; + fl->dsp_process_state = PROCESS_CREATE_IS_INPROGRESS; spin_unlock(&fl->hlock); inbuf.pgid = fl->tgid; inbuf.namelen = strlen(current->comm) + 1; @@ -3916,9 +3916,11 @@ bail: fastrpc_mmap_free(file, 0); mutex_unlock(&fl->map_mutex); } - if (err) { + spin_lock(&fl->hlock); locked = 1; + if (err) { + fl->dsp_process_state = PROCESS_CREATE_DEFAULT; if (!IS_ERR_OR_NULL(fl->init_mem)) { init_mem = fl->init_mem; fl->init_mem = NULL; @@ -3926,14 +3928,13 @@ bail: locked = 0; fastrpc_buf_free(init_mem, 0); } + } else { + fl->dsp_process_state = PROCESS_CREATE_SUCCESS; + } if (locked) { spin_unlock(&fl->hlock); locked = 0; - } } - spin_lock(&fl->hlock); - fl->in_process_create = false; - spin_unlock(&fl->hlock); return err; } @@ -5355,7 +5356,7 @@ skip_dump_wait: spin_lock(&fl->apps->hlock); hlist_del_init(&fl->hn); fl->is_ramdump_pend = false; - fl->in_process_create = false; + fl->dsp_process_state = PROCESS_CREATE_DEFAULT; spin_unlock(&fl->apps->hlock); kfree(fl->debug_buf); kfree(fl->gidlist.gids); @@ -5773,7 +5774,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->qos_request = 0; fl->dsp_proc_init = 0; fl->is_ramdump_pend = false; - fl->in_process_create = false; + fl->dsp_process_state = PROCESS_CREATE_DEFAULT; init_completion(&fl->work); fl->file_close = FASTRPC_PROCESS_DEFAULT_STATE; filp->private_data = fl; diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index 264ca2b5aa65..905479dd5bd5 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -513,6 +513,11 @@ enum fastrpc_response_flags { COMPLETE_SIGNAL = 3 }; +enum fastrpc_process_create_state { + PROCESS_CREATE_DEFAULT = 0, /* Process is not created */ + PROCESS_CREATE_IS_INPROGRESS = 1, /* Process creation is in progress */ + PROCESS_CREATE_SUCCESS = 2, /* Process creation is successful */ +}; struct smq_invoke_rspv2 { uint64_t ctx; /* invoke caller context */ int retval; /* invoke return value */