* [PATCH 4.19/5.4/5.10/5.15/6.1 0/1] sch_netem: fix issues in netem_change() vs get_dist_table()
@ 2023-08-13 20:07 Fedor Pchelkin
2023-08-13 20:07 ` [PATCH 4.19/5.4/5.10/5.15/6.1 1/1] " Fedor Pchelkin
2023-08-13 20:22 ` [PATCH 4.19/5.4/5.10/5.15/6.1 0/1] " Greg Kroah-Hartman
0 siblings, 2 replies; 3+ messages in thread
From: Fedor Pchelkin @ 2023-08-13 20:07 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable
Cc: Fedor Pchelkin, Jamal Hadi Salim, Eric Dumazet, Jakub Kicinski,
Simon Horman, netdev, linux-kernel, Alexey Khoroshilov,
lvc-project, Stephen Hemminger
Commit 2174a08db80d ("sch_netem: acquire qdisc lock in netem_change()")
was backported to older stables where it is causing 'sleeping in invalid
context' bug. The following patch fixes the problem and can be cleanly
applied to the stable branches affected. It was backported to 6.4.y about
a month ago.
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 4.19/5.4/5.10/5.15/6.1 1/1] sch_netem: fix issues in netem_change() vs get_dist_table()
2023-08-13 20:07 [PATCH 4.19/5.4/5.10/5.15/6.1 0/1] sch_netem: fix issues in netem_change() vs get_dist_table() Fedor Pchelkin
@ 2023-08-13 20:07 ` Fedor Pchelkin
2023-08-13 20:22 ` [PATCH 4.19/5.4/5.10/5.15/6.1 0/1] " Greg Kroah-Hartman
1 sibling, 0 replies; 3+ messages in thread
From: Fedor Pchelkin @ 2023-08-13 20:07 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable
Cc: Fedor Pchelkin, Jamal Hadi Salim, Eric Dumazet, Jakub Kicinski,
Simon Horman, netdev, linux-kernel, Alexey Khoroshilov,
lvc-project, Stephen Hemminger, syzbot
From: Eric Dumazet <edumazet@google.com>
commit 11b73313c12403f617b47752db0ab3deef201af7 upstream.
In blamed commit, I missed that get_dist_table() was allocating
memory using GFP_KERNEL, and acquiring qdisc lock to perform
the swap of newly allocated table with current one.
In this patch, get_dist_table() is allocating memory and
copy user data before we acquire the qdisc lock.
Then we perform swap operations while being protected by the lock.
Note that after this patch netem_change() no longer can do partial changes.
If an error is returned, qdisc conf is left unchanged.
Fixes: 2174a08db80d ("sch_netem: acquire qdisc lock in netem_change()")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Link: https://lore.kernel.org/r/20230622181503.2327695-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
---
net/sched/sch_netem.c | 59 ++++++++++++++++++-------------------------
1 file changed, 25 insertions(+), 34 deletions(-)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index e79be1b3e74d..b93ec2a3454e 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -773,12 +773,10 @@ static void dist_free(struct disttable *d)
* signed 16 bit values.
*/
-static int get_dist_table(struct Qdisc *sch, struct disttable **tbl,
- const struct nlattr *attr)
+static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)
{
size_t n = nla_len(attr)/sizeof(__s16);
const __s16 *data = nla_data(attr);
- spinlock_t *root_lock;
struct disttable *d;
int i;
@@ -793,13 +791,7 @@ static int get_dist_table(struct Qdisc *sch, struct disttable **tbl,
for (i = 0; i < n; i++)
d->table[i] = data[i];
- root_lock = qdisc_root_sleeping_lock(sch);
-
- spin_lock_bh(root_lock);
- swap(*tbl, d);
- spin_unlock_bh(root_lock);
-
- dist_free(d);
+ *tbl = d;
return 0;
}
@@ -956,6 +948,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
{
struct netem_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_NETEM_MAX + 1];
+ struct disttable *delay_dist = NULL;
+ struct disttable *slot_dist = NULL;
struct tc_netem_qopt *qopt;
struct clgstate old_clg;
int old_loss_model = CLG_RANDOM;
@@ -966,6 +960,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
if (ret < 0)
return ret;
+ if (tb[TCA_NETEM_DELAY_DIST]) {
+ ret = get_dist_table(&delay_dist, tb[TCA_NETEM_DELAY_DIST]);
+ if (ret)
+ goto table_free;
+ }
+
+ if (tb[TCA_NETEM_SLOT_DIST]) {
+ ret = get_dist_table(&slot_dist, tb[TCA_NETEM_SLOT_DIST]);
+ if (ret)
+ goto table_free;
+ }
+
sch_tree_lock(sch);
/* backup q->clg and q->loss_model */
old_clg = q->clg;
@@ -975,26 +981,17 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]);
if (ret) {
q->loss_model = old_loss_model;
+ q->clg = old_clg;
goto unlock;
}
} else {
q->loss_model = CLG_RANDOM;
}
- if (tb[TCA_NETEM_DELAY_DIST]) {
- ret = get_dist_table(sch, &q->delay_dist,
- tb[TCA_NETEM_DELAY_DIST]);
- if (ret)
- goto get_table_failure;
- }
-
- if (tb[TCA_NETEM_SLOT_DIST]) {
- ret = get_dist_table(sch, &q->slot_dist,
- tb[TCA_NETEM_SLOT_DIST]);
- if (ret)
- goto get_table_failure;
- }
-
+ if (delay_dist)
+ swap(q->delay_dist, delay_dist);
+ if (slot_dist)
+ swap(q->slot_dist, slot_dist);
sch->limit = qopt->limit;
q->latency = PSCHED_TICKS2NS(qopt->latency);
@@ -1044,17 +1041,11 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
unlock:
sch_tree_unlock(sch);
- return ret;
-get_table_failure:
- /* recover clg and loss_model, in case of
- * q->clg and q->loss_model were modified
- * in get_loss_clg()
- */
- q->clg = old_clg;
- q->loss_model = old_loss_model;
-
- goto unlock;
+table_free:
+ dist_free(delay_dist);
+ dist_free(slot_dist);
+ return ret;
}
static int netem_init(struct Qdisc *sch, struct nlattr *opt,
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 4.19/5.4/5.10/5.15/6.1 0/1] sch_netem: fix issues in netem_change() vs get_dist_table()
2023-08-13 20:07 [PATCH 4.19/5.4/5.10/5.15/6.1 0/1] sch_netem: fix issues in netem_change() vs get_dist_table() Fedor Pchelkin
2023-08-13 20:07 ` [PATCH 4.19/5.4/5.10/5.15/6.1 1/1] " Fedor Pchelkin
@ 2023-08-13 20:22 ` Greg Kroah-Hartman
1 sibling, 0 replies; 3+ messages in thread
From: Greg Kroah-Hartman @ 2023-08-13 20:22 UTC (permalink / raw)
To: Fedor Pchelkin
Cc: stable, Jamal Hadi Salim, Eric Dumazet, Jakub Kicinski,
Simon Horman, netdev, linux-kernel, Alexey Khoroshilov,
lvc-project, Stephen Hemminger
On Sun, Aug 13, 2023 at 11:07:45PM +0300, Fedor Pchelkin wrote:
> Commit 2174a08db80d ("sch_netem: acquire qdisc lock in netem_change()")
> was backported to older stables where it is causing 'sleeping in invalid
> context' bug. The following patch fixes the problem and can be cleanly
> applied to the stable branches affected. It was backported to 6.4.y about
> a month ago.
Now queued up, thanks.
greg k-h
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-08-13 20:22 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-13 20:07 [PATCH 4.19/5.4/5.10/5.15/6.1 0/1] sch_netem: fix issues in netem_change() vs get_dist_table() Fedor Pchelkin
2023-08-13 20:07 ` [PATCH 4.19/5.4/5.10/5.15/6.1 1/1] " Fedor Pchelkin
2023-08-13 20:22 ` [PATCH 4.19/5.4/5.10/5.15/6.1 0/1] " Greg Kroah-Hartman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox