sched/fair: WARN and refuse to set buddy when !se->on_rq
PATCH v2 1/1 sched/fair: WARN and refuse to set buddy when !se->on_rq
If we set a next or last buddy for a se that is not on_rq, we will end up taking a NULL pointer dereference in wakeup_preempt_entity via pick_next_task_fair.
Detect when we would be about to do that, throw a warning and then refuse to actually set it.
This has been suggested at least twice[0][1]: just do it.
[0] https://marc.info/?l=linux-kernel&m=146651668921468&w=2
[1] https://lkml.org/lkml/2016/6/16/663
---
I recently had to debug a problem with these (we hadn't backported Konstantin's patches in this area) and this would have saved a lot of time/pain.
v2: use SCHED_WARN_ON to restrict when the test is run. This is a
macro for WARN_ON_ONCE, which is convenient.
--- kernel/sched/fair.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
kernel/sched/fair.c +8 -2
@@ -6168,8 +6168,11 @@ static void set_last_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->last = se; + } }static void set_next_buddy (struct sched_entity *se)
@@ -6177,8 +6180,11 @@ static void set_next_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->next = se; + } }static void set_skip_buddy (struct sched_entity *se)
Signature · 1 line
2.11.0
Hi Konstantin and Peter,
Just checking if this version was OK with you - I hadn't heard anything and I noticed it's not in -next so I just wanted to check to see if there were any other changes you wanted.
Regards,
Daniel
Quoted 62 lines · Daniel Axtens
If we set a next or last buddy for a se that is not
on_rq, we will end up taking a NULL pointer dereference inwakeup_preempt_entityviapick_next_task_fair.Detect when we would be about to do that, throw a warning and then refuse to actually set it.
This has been suggested at least twice[0][1]: just do it.
[0] https://marc.info/?l=linux-kernel&m=146651668921468&w=2
[1] https://lkml.org/lkml/2016/6/16/663Cc Konstantin Khlebnikov <[email protected]>Cc Ben Segall <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Thomas Gleixner <[email protected]>Signed-off-by Daniel Axtens <[email protected]>---
I recently had to debug a problem with these (we hadn't backported Konstantin's patches in this area) and this would have saved a lot of time/pain.
v2: use
SCHED_WARN_ONto restrict when the test is run. This is a
macro forWARN_ON_ONCE, which is convenient.--- kernel/sched/fair.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)kernel/sched/fair.c +8
-2@@ -6168,8 +6168,11 @@ static void set_last_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->last = se; + } }static void set_next_buddy (struct sched_entity *se)@@ -6177,8 +6180,11 @@ static void set_next_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->next = se; + } }static void set_skip_buddy (struct sched_entity *se)Signature · 1 line
2.11.0
Quoted 5 lines · Daniel Axtens
Hi Konstantin and Peter,
Just checking if this version was OK with you - I hadn't heard anything and I noticed it's not in -next so I just wanted to check to see if there were any other changes you wanted.
Looks good for me. Exactly that debug helped me alot at that time.
Quoted 69 lines
Regards,
DanielQuoted 62 lines · Daniel Axtens
If we set a next or last buddy for a se that is not
on_rq, we will end up taking a NULL pointer dereference inwakeup_preempt_entityviapick_next_task_fair.Detect when we would be about to do that, throw a warning and then refuse to actually set it.
This has been suggested at least twice[0][1]: just do it.
[0] https://marc.info/?l=linux-kernel&m=146651668921468&w=2
[1] https://lkml.org/lkml/2016/6/16/663Cc Konstantin Khlebnikov <[email protected]>Cc Ben Segall <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Thomas Gleixner <[email protected]>Signed-off-by Daniel Axtens <[email protected]>---
I recently had to debug a problem with these (we hadn't backported Konstantin's patches in this area) and this would have saved a lot of time/pain.
v2: use
SCHED_WARN_ONto restrict when the test is run. This is a
macro forWARN_ON_ONCE, which is convenient.--- kernel/sched/fair.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)kernel/sched/fair.c +8
-2@@ -6168,8 +6168,11 @@ static void set_last_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->last = se; + } }static void set_next_buddy (struct sched_entity *se)@@ -6177,8 +6180,11 @@ static void set_next_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->next = se; + } }static void set_skip_buddy (struct sched_entity *se)Signature · 1 line
2.11.0
PATCH 1/1 sched/debug: Fix SCHED_WARN_ON() to return a value on !CONFIG_SCHED_DEBUG as well
In reply to Daniel AxtensQuoted 35 lines · Daniel Axtens
If we set a next or last buddy for a se that is not
on_rq, we will end up taking a NULL pointer dereference inwakeup_preempt_entityviapick_next_task_fair.Detect when we would be about to do that, throw a warning and then refuse to actually set it.
This has been suggested at least twice[0][1]: just do it.
[0] https://marc.info/?l=linux-kernel&m=146651668921468&w=2
[1] https://lkml.org/lkml/2016/6/16/663Cc Konstantin Khlebnikov <[email protected]>Cc Ben Segall <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Thomas Gleixner <[email protected]>Signed-off-by Daniel Axtens <[email protected]>---
I recently had to debug a problem with these (we hadn't backported Konstantin's patches in this area) and this would have saved a lot of time/pain.
v2: use
SCHED_WARN_ONto restrict when the test is run. This is a
macro forWARN_ON_ONCE, which is convenient.--- kernel/sched/fair.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)kernel/sched/fair.c +0
-0
kernel/sched/fair.c static void set_last_buddy(struct sched_entity *se) · line 6175
Quoted 9 lines
kernel/sched/fair.c +4
-1@@ -6168,8 +6168,11 @@ static void set_last_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->last = se; + }
This won't build in the !CONFIG_SCHED_DEBUG case, because of the naive definition in sched.h:
#define SCHED_WARN_ON(x) ((void)(x))
That should be changed to something like:
#define SCHED_WARN_ON(x) ((void)(x))
I've applied the fix below. (untested at the moment)
Thanks,
Ingo
========================>
Quoted 1 line
From
6d3aed3d8a0573d0a6eb1160ccd0a0713f4dbc2fMon Sep 17 00:00:00 2001
From: Ingo Molnar <[email protected]>
Date: Tue, 20 Jun 2017 12:24:42 +0200
Subject: [PATCH] sched/debug: Fix SCHED_WARN_ON() to return a value on !CONFIG_SCHED_DEBUG as well
This definition of SCHED_WARN_ON():
#define SCHED_WARN_ON(x) ((void)(x))
is not fully compatible with the 'real' WARN_ON_ONCE() primitive, as it has no return value, so it cannot be used in conditionals.
Fix it.
--- kernel/sched/sched.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/sched/sched.h +2 -2
@@ -39,9 +39,9 @@#include "cpuacct.h" #ifdef CONFIG_SCHED_DEBUG -#define SCHED_WARN_ON (x) WARN_ONCE(x, #x) +# define SCHED_WARN_ON (x) WARN_ONCE(x, #x)#else -#define SCHED_WARN_ON (x) ((void)(x)) +# define SCHED_WARN_ON (x) ({ (void)(x), 0; })#endif struct rq ;
Re: [PATCH] sched/debug: Fix SCHED_WARN_ON() to return a value on !CONFIG_SCHED_DEBUG as well
Hi Ingo,
Good catch - thanks for picking that up and taking the patch!
Regards,
Daniel
Quoted 105 lines · Daniel Axtens
Quoted 36 lines
If we set a next or last buddy for a se that is not
on_rq, we will end up taking a NULL pointer dereference inwakeup_preempt_entityviapick_next_task_fair.Detect when we would be about to do that, throw a warning and then refuse to actually set it.
This has been suggested at least twice[0][1]: just do it.
[0] https://marc.info/?l=linux-kernel&m=146651668921468&w=2
[1] https://lkml.org/lkml/2016/6/16/663Cc Konstantin Khlebnikov <[email protected]>Cc Ben Segall <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Thomas Gleixner <[email protected]>Signed-off-by Daniel Axtens <[email protected]>---
I recently had to debug a problem with these (we hadn't backported Konstantin's patches in this area) and this would have saved a lot of time/pain.
v2: use
SCHED_WARN_ONto restrict when the test is run. This is a
macro forWARN_ON_ONCE, which is convenient.--- kernel/sched/fair.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)kernel/sched/fair.c +0
-0kernel/sched/fair.c static void set_last_buddy(struct sched_entity *se) · line 6175
Quoted 9 lines
kernel/sched/fair.c +4
-1@@ -6168,8 +6168,11 @@ static void set_last_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->last = se; + }This won't build in the !CONFIG_SCHED_DEBUG case, because of the naive definition in
sched.h:#define
SCHED_WARN_ON(x)((void)(x))That should be changed to something like:
#define
SCHED_WARN_ON(x)((void)(x))I've applied the fix below. (untested at the moment)
Thanks,
Ingo
========================>
From6d3aed3d8a0573d0a6eb1160ccd0a0713f4dbc2fMon Sep 17 00:00:00 2001
From: Ingo Molnar <[email protected]>
Date: Tue, 20 Jun 2017 12:24:42 +0200
Subject: [PATCH] sched/debug: FixSCHED_WARN_ON()to return a value on !CONFIG_SCHED_DEBUG as wellThis definition of
SCHED_WARN_ON():#define
SCHED_WARN_ON(x)((void)(x))is not fully compatible with the 'real'
WARN_ON_ONCE()primitive, as it has no return value, so it cannot be used in conditionals.Fix it.
Cc Daniel Axtens <[email protected]>Cc Konstantin Khlebnikov <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Mike Galbraith <[email protected]>Cc Thomas Gleixner <[email protected]>Cc Linus Torvalds <[email protected]>Signed-off-by Ingo Molnar <[email protected]>--- kernel/sched/sched.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)kernel/sched/sched.h +2
-2@@ -39,9 +39,9 @@#include "cpuacct.h" #ifdef CONFIG_SCHED_DEBUG -#define SCHED_WARN_ON (x) WARN_ONCE(x, #x) +# define SCHED_WARN_ON (x) WARN_ONCE(x, #x)#else -#define SCHED_WARN_ON (x) ((void)(x)) +# define SCHED_WARN_ON (x) ({ (void)(x), 0; })#endif struct rq ;
tip-bot for Daniel Axtens
merge bot[tip:sched/core] sched/fair: WARN() and refuse to set buddy when !se->on_rq
In reply to Daniel Axtenssched/fair: WARN() and refuse to set buddy when !se->on_rq
Commit-ID: c5ae366e12b2bd56fc7d7e9d484836bec9ddc110 Gitweb: http://git.kernel.org/tip/c5ae366e12b2bd56fc7d7e9d484836bec9ddc110 Author: Daniel Axtens <[email protected]> AuthorDate: Thu, 11 May 2017 06:11:39 +1000 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 20 Jun 2017 12:26:52 +0200
sched/fair: WARN() and refuse to set buddy when !se->on_rq
If we set a next or last buddy for a se that is not on_rq, we will end up taking a NULL pointer dereference in wakeup_preempt_entity via pick_next_task_fair.
Detect when we would be about to do that, throw a warning and then refuse to actually set it.
This has been suggested at least twice:
https://marc.info/?l=linux-kernel&m=146651668921468&w=2
https://lkml.org/lkml/2016/6/16/663
I recently had to debug a problem with these (we hadn't backported Konstantin's patches in this area) and this would have saved a lot of time/pain.
Just do it.
--- kernel/sched/fair.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
kernel/sched/fair.c +8 -2
@@ -6164,8 +6164,11 @@ static void set_last_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->last = se; + } }static void set_next_buddy (struct sched_entity *se)
@@ -6173,8 +6176,11 @@ static void set_next_buddy(struct sched_entity *se)if (entity_is_task (se) &&unlikely (task_of (se)->policy ==SCHED_IDLE ))return ; -for_each_sched_entity (se) +for_each_sched_entity (se) { +if (SCHED_WARN_ON (!se->on_rq)) +return ;cfs_rq_of (se)->next = se; + } }static void set_skip_buddy (struct sched_entity *se)