From: Daniel Starke <daniel.starke(a)siemens.com>
stable inclusion
from stable-v6.6.33
commit 2ab96b6e81d2a419d3e0d6bec043ea8f31eab86a
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9TAHR
CVE: CVE-2024-36016
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit 47388e807f85948eefc403a8a5fdc5b406a65d5a upstream.
Assuming the following:
- side A configures the n_gsm in basic option mode
- side B sends the header of a basic option mode frame with data length 1
- side A switches to advanced option mode
- side B sends 2 data bytes which exceeds gsm->len
Reason: gsm->len is not used in advanced option mode.
- side A switches to basic option mode
- side B keeps sending until gsm0_receive() writes past gsm->buf
Reason: Neither gsm->state nor gsm->len have been reset after
reconfiguration.
Fix this by changing gsm->count to gsm->len comparison from equal to less
than. Also add upper limit checks against the constant MAX_MRU in
gsm0_receive() and gsm1_receive() to harden against memory corruption of
gsm->len and gsm->mru.
All other checks remain as we still need to limit the data according to the
user configuration and actual payload size.
Reported-by: j51569436(a)gmail.com
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218708
Tested-by: j51569436(a)gmail.com
Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
Cc: stable(a)vger.kernel.org
Signed-off-by: Daniel Starke <daniel.starke(a)siemens.com>
Link: https://lore.kernel.org/r/20240424054842.7741-1-daniel.starke@siemens.com
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Cui GaoSheng <cuigaosheng1(a)huawei.com>
---
drivers/tty/n_gsm.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 0ee7531c9201..f8858865c5bb 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2912,7 +2912,10 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break;
case GSM_DATA: /* Data */
gsm->buf[gsm->count++] = c;
- if (gsm->count == gsm->len) {
+ if (gsm->count >= MAX_MRU) {
+ gsm->bad_size++;
+ gsm->state = GSM_SEARCH;
+ } else if (gsm->count >= gsm->len) {
/* Calculate final FCS for UI frames over all data */
if ((gsm->control & ~PF) != UIH) {
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
@@ -3025,7 +3028,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
gsm->state = GSM_DATA;
break;
case GSM_DATA: /* Data */
- if (gsm->count > gsm->mru) { /* Allow one for the FCS */
+ if (gsm->count > gsm->mru || gsm->count > MAX_MRU) { /* Allow one for the FCS */
gsm->state = GSM_OVERRUN;
gsm->bad_size++;
} else
--
2.34.1
From: Daniel Starke <daniel.starke(a)siemens.com>
stable inclusion
from stable-v5.10.219
commit a200355b429825c9331c1bd70d7bb895c2f06b7d
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9TAHR
CVE: CVE-2024-36016
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit 47388e807f85948eefc403a8a5fdc5b406a65d5a upstream.
Assuming the following:
- side A configures the n_gsm in basic option mode
- side B sends the header of a basic option mode frame with data length 1
- side A switches to advanced option mode
- side B sends 2 data bytes which exceeds gsm->len
Reason: gsm->len is not used in advanced option mode.
- side A switches to basic option mode
- side B keeps sending until gsm0_receive() writes past gsm->buf
Reason: Neither gsm->state nor gsm->len have been reset after
reconfiguration.
Fix this by changing gsm->count to gsm->len comparison from equal to less
than. Also add upper limit checks against the constant MAX_MRU in
gsm0_receive() and gsm1_receive() to harden against memory corruption of
gsm->len and gsm->mru.
All other checks remain as we still need to limit the data according to the
user configuration and actual payload size.
Reported-by: j51569436(a)gmail.com
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218708
Tested-by: j51569436(a)gmail.com
Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
Cc: stable(a)vger.kernel.org
Signed-off-by: Daniel Starke <daniel.starke(a)siemens.com>
Link: https://lore.kernel.org/r/20240424054842.7741-1-daniel.starke@siemens.com
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Cui GaoSheng <cuigaosheng1(a)huawei.com>
---
drivers/tty/n_gsm.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 6cd87e71fecc..594be57f44ec 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2015,8 +2015,12 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break;
case GSM_DATA: /* Data */
gsm->buf[gsm->count++] = c;
- if (gsm->count == gsm->len)
+ if (gsm->count >= MAX_MRU) {
+ gsm->bad_size++;
+ gsm->state = GSM_SEARCH;
+ } else if (gsm->count >= gsm->len) {
gsm->state = GSM_FCS;
+ }
break;
case GSM_FCS: /* FCS follows the packet */
gsm->received_fcs = c;
@@ -2109,7 +2113,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
gsm->state = GSM_DATA;
break;
case GSM_DATA: /* Data */
- if (gsm->count > gsm->mru) { /* Allow one for the FCS */
+ if (gsm->count > gsm->mru || gsm->count > MAX_MRU) { /* Allow one for the FCS */
gsm->state = GSM_OVERRUN;
gsm->bad_size++;
} else
--
2.34.1
From: Daniel Starke <daniel.starke(a)siemens.com>
stable inclusion
from stable-v5.10.219
commit a200355b429825c9331c1bd70d7bb895c2f06b7d
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9TAHR
CVE: CVE-2024-36016
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit 47388e807f85948eefc403a8a5fdc5b406a65d5a upstream.
Assuming the following:
- side A configures the n_gsm in basic option mode
- side B sends the header of a basic option mode frame with data length 1
- side A switches to advanced option mode
- side B sends 2 data bytes which exceeds gsm->len
Reason: gsm->len is not used in advanced option mode.
- side A switches to basic option mode
- side B keeps sending until gsm0_receive() writes past gsm->buf
Reason: Neither gsm->state nor gsm->len have been reset after
reconfiguration.
Fix this by changing gsm->count to gsm->len comparison from equal to less
than. Also add upper limit checks against the constant MAX_MRU in
gsm0_receive() and gsm1_receive() to harden against memory corruption of
gsm->len and gsm->mru.
All other checks remain as we still need to limit the data according to the
user configuration and actual payload size.
Reported-by: j51569436(a)gmail.com
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218708
Tested-by: j51569436(a)gmail.com
Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
Cc: stable(a)vger.kernel.org
Signed-off-by: Daniel Starke <daniel.starke(a)siemens.com>
Link: https://lore.kernel.org/r/20240424054842.7741-1-daniel.starke@siemens.com
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Cui GaoSheng <cuigaosheng1(a)huawei.com>
---
drivers/tty/n_gsm.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 3693ad9f4521..af2412450b10 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2019,8 +2019,12 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break;
case GSM_DATA: /* Data */
gsm->buf[gsm->count++] = c;
- if (gsm->count == gsm->len)
+ if (gsm->count >= MAX_MRU) {
+ gsm->bad_size++;
+ gsm->state = GSM_SEARCH;
+ } else if (gsm->count >= gsm->len) {
gsm->state = GSM_FCS;
+ }
break;
case GSM_FCS: /* FCS follows the packet */
gsm->received_fcs = c;
@@ -2113,7 +2117,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
gsm->state = GSM_DATA;
break;
case GSM_DATA: /* Data */
- if (gsm->count > gsm->mru) { /* Allow one for the FCS */
+ if (gsm->count > gsm->mru || gsm->count > MAX_MRU) { /* Allow one for the FCS */
gsm->state = GSM_OVERRUN;
gsm->bad_size++;
} else
--
2.34.1
From: Daniel Starke <daniel.starke(a)siemens.com>
stable inclusion
from stable-v5.10.219
commit a200355b429825c9331c1bd70d7bb895c2f06b7d
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9TAHR
CVE: CVE-2024-36016
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit 47388e807f85948eefc403a8a5fdc5b406a65d5a upstream.
Assuming the following:
- side A configures the n_gsm in basic option mode
- side B sends the header of a basic option mode frame with data length 1
- side A switches to advanced option mode
- side B sends 2 data bytes which exceeds gsm->len
Reason: gsm->len is not used in advanced option mode.
- side A switches to basic option mode
- side B keeps sending until gsm0_receive() writes past gsm->buf
Reason: Neither gsm->state nor gsm->len have been reset after
reconfiguration.
Fix this by changing gsm->count to gsm->len comparison from equal to less
than. Also add upper limit checks against the constant MAX_MRU in
gsm0_receive() and gsm1_receive() to harden against memory corruption of
gsm->len and gsm->mru.
All other checks remain as we still need to limit the data according to the
user configuration and actual payload size.
Reported-by: j51569436(a)gmail.com
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218708
Tested-by: j51569436(a)gmail.com
Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
Cc: stable(a)vger.kernel.org
Signed-off-by: Daniel Starke <daniel.starke(a)siemens.com>
Link: https://lore.kernel.org/r/20240424054842.7741-1-daniel.starke@siemens.com
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Cui GaoSheng <cuigaosheng1(a)huawei.com>
---
drivers/tty/n_gsm.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 05d9064b4ee7..52a2e613b59a 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1914,8 +1914,12 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break;
case GSM_DATA: /* Data */
gsm->buf[gsm->count++] = c;
- if (gsm->count == gsm->len)
+ if (gsm->count >= MAX_MRU) {
+ gsm->bad_size++;
+ gsm->state = GSM_SEARCH;
+ } else if (gsm->count >= gsm->len) {
gsm->state = GSM_FCS;
+ }
break;
case GSM_FCS: /* FCS follows the packet */
gsm->received_fcs = c;
@@ -1994,7 +1998,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
gsm->state = GSM_DATA;
break;
case GSM_DATA: /* Data */
- if (gsm->count > gsm->mru) { /* Allow one for the FCS */
+ if (gsm->count > gsm->mru || gsm->count > MAX_MRU) { /* Allow one for the FCS */
gsm->state = GSM_OVERRUN;
gsm->bad_size++;
} else
--
2.34.1
From: Rik van Riel <riel(a)surriel.com>
stable inclusion
from stable-v6.6.31
commit ce0e99cae00e3131872936713b7f55eefd53ab86
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9U4LC
CVE: CVE-2024-36916
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
[ Upstream commit beaa51b36012fad5a4d3c18b88a617aea7a9b96d ]
UBSAN catches undefined behavior in blk-iocost, where sometimes
iocg->delay is shifted right by a number that is too large,
resulting in undefined behavior on some architectures.
[ 186.556576] ------------[ cut here ]------------
UBSAN: shift-out-of-bounds in block/blk-iocost.c:1366:23
shift exponent 64 is too large for 64-bit type 'u64' (aka 'unsigned long long')
CPU: 16 PID: 0 Comm: swapper/16 Tainted: G S E N 6.9.0-0_fbk700_debug_rc2_kbuilder_0_gc85af715cac0 #1
Hardware name: Quanta Twin Lakes MP/Twin Lakes Passive MP, BIOS F09_3A23 12/08/2020
Call Trace:
<IRQ>
dump_stack_lvl+0x8f/0xe0
__ubsan_handle_shift_out_of_bounds+0x22c/0x280
iocg_kick_delay+0x30b/0x310
ioc_timer_fn+0x2fb/0x1f80
__run_timer_base+0x1b6/0x250
...
Avoid that undefined behavior by simply taking the
"delay = 0" branch if the shift is too large.
I am not sure what the symptoms of an undefined value
delay will be, but I suspect it could be more than a
little annoying to debug.
Signed-off-by: Rik van Riel <riel(a)surriel.com>
Cc: Tejun Heo <tj(a)kernel.org>
Cc: Josef Bacik <josef(a)toxicpanda.com>
Cc: Jens Axboe <axboe(a)kernel.dk>
Acked-by: Tejun Heo <tj(a)kernel.org>
Link: https://lore.kernel.org/r/20240404123253.0f58010f@imladris.surriel.com
Signed-off-by: Jens Axboe <axboe(a)kernel.dk>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
Signed-off-by: Li Nan <linan122(a)huawei.com>
---
block/blk-iocost.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index 1351db658a78..6a3e8a21c0fc 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -1347,7 +1347,7 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
{
struct ioc *ioc = iocg->ioc;
struct blkcg_gq *blkg = iocg_to_blkg(iocg);
- u64 tdelta, delay, new_delay;
+ u64 tdelta, delay, new_delay, shift;
s64 vover, vover_pct;
u32 hwa;
@@ -1362,8 +1362,9 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
/* calculate the current delay in effect - 1/2 every second */
tdelta = now->now - iocg->delay_at;
- if (iocg->delay)
- delay = iocg->delay >> div64_u64(tdelta, USEC_PER_SEC);
+ shift = div64_u64(tdelta, USEC_PER_SEC);
+ if (iocg->delay && shift < BITS_PER_LONG)
+ delay = iocg->delay >> shift;
else
delay = 0;
--
2.39.2
From: Rik van Riel <riel(a)surriel.com>
stable inclusion
from stable-v5.10.217
commit 62accf6c1d7b433752cb3591bba8967b7a801ad5
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9U4LC
CVE: CVE-2024-36916
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
[ Upstream commit beaa51b36012fad5a4d3c18b88a617aea7a9b96d ]
UBSAN catches undefined behavior in blk-iocost, where sometimes
iocg->delay is shifted right by a number that is too large,
resulting in undefined behavior on some architectures.
[ 186.556576] ------------[ cut here ]------------
UBSAN: shift-out-of-bounds in block/blk-iocost.c:1366:23
shift exponent 64 is too large for 64-bit type 'u64' (aka 'unsigned long long')
CPU: 16 PID: 0 Comm: swapper/16 Tainted: G S E N 6.9.0-0_fbk700_debug_rc2_kbuilder_0_gc85af715cac0 #1
Hardware name: Quanta Twin Lakes MP/Twin Lakes Passive MP, BIOS F09_3A23 12/08/2020
Call Trace:
<IRQ>
dump_stack_lvl+0x8f/0xe0
__ubsan_handle_shift_out_of_bounds+0x22c/0x280
iocg_kick_delay+0x30b/0x310
ioc_timer_fn+0x2fb/0x1f80
__run_timer_base+0x1b6/0x250
...
Avoid that undefined behavior by simply taking the
"delay = 0" branch if the shift is too large.
I am not sure what the symptoms of an undefined value
delay will be, but I suspect it could be more than a
little annoying to debug.
Signed-off-by: Rik van Riel <riel(a)surriel.com>
Cc: Tejun Heo <tj(a)kernel.org>
Cc: Josef Bacik <josef(a)toxicpanda.com>
Cc: Jens Axboe <axboe(a)kernel.dk>
Acked-by: Tejun Heo <tj(a)kernel.org>
Link: https://lore.kernel.org/r/20240404123253.0f58010f@imladris.surriel.com
Signed-off-by: Jens Axboe <axboe(a)kernel.dk>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
Signed-off-by: Li Nan <linan122(a)huawei.com>
---
block/blk-iocost.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index ef12e5d94a3b..edab843d547a 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -1309,7 +1309,7 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
{
struct ioc *ioc = iocg->ioc;
struct blkcg_gq *blkg = iocg_to_blkg(iocg);
- u64 tdelta, delay, new_delay;
+ u64 tdelta, delay, new_delay, shift;
s64 vover, vover_pct;
u32 hwa;
@@ -1324,8 +1324,9 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
/* calculate the current delay in effect - 1/2 every second */
tdelta = now->now - iocg->delay_at;
- if (iocg->delay)
- delay = iocg->delay >> div64_u64(tdelta, USEC_PER_SEC);
+ shift = div64_u64(tdelta, USEC_PER_SEC);
+ if (iocg->delay && shift < BITS_PER_LONG)
+ delay = iocg->delay >> shift;
else
delay = 0;
--
2.39.2
From: Rik van Riel <riel(a)surriel.com>
stable inclusion
from stable-v5.10.217
commit 62accf6c1d7b433752cb3591bba8967b7a801ad5
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9U4LC
CVE: CVE-2024-36916
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
[ Upstream commit beaa51b36012fad5a4d3c18b88a617aea7a9b96d ]
UBSAN catches undefined behavior in blk-iocost, where sometimes
iocg->delay is shifted right by a number that is too large,
resulting in undefined behavior on some architectures.
[ 186.556576] ------------[ cut here ]------------
UBSAN: shift-out-of-bounds in block/blk-iocost.c:1366:23
shift exponent 64 is too large for 64-bit type 'u64' (aka 'unsigned long long')
CPU: 16 PID: 0 Comm: swapper/16 Tainted: G S E N 6.9.0-0_fbk700_debug_rc2_kbuilder_0_gc85af715cac0 #1
Hardware name: Quanta Twin Lakes MP/Twin Lakes Passive MP, BIOS F09_3A23 12/08/2020
Call Trace:
<IRQ>
dump_stack_lvl+0x8f/0xe0
__ubsan_handle_shift_out_of_bounds+0x22c/0x280
iocg_kick_delay+0x30b/0x310
ioc_timer_fn+0x2fb/0x1f80
__run_timer_base+0x1b6/0x250
...
Avoid that undefined behavior by simply taking the
"delay = 0" branch if the shift is too large.
I am not sure what the symptoms of an undefined value
delay will be, but I suspect it could be more than a
little annoying to debug.
Signed-off-by: Rik van Riel <riel(a)surriel.com>
Cc: Tejun Heo <tj(a)kernel.org>
Cc: Josef Bacik <josef(a)toxicpanda.com>
Cc: Jens Axboe <axboe(a)kernel.dk>
Acked-by: Tejun Heo <tj(a)kernel.org>
Link: https://lore.kernel.org/r/20240404123253.0f58010f@imladris.surriel.com
Signed-off-by: Jens Axboe <axboe(a)kernel.dk>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
Signed-off-by: Li Nan <linan122(a)huawei.com>
---
block/blk-iocost.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index ef12e5d94a3b..edab843d547a 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -1309,7 +1309,7 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
{
struct ioc *ioc = iocg->ioc;
struct blkcg_gq *blkg = iocg_to_blkg(iocg);
- u64 tdelta, delay, new_delay;
+ u64 tdelta, delay, new_delay, shift;
s64 vover, vover_pct;
u32 hwa;
@@ -1324,8 +1324,9 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
/* calculate the current delay in effect - 1/2 every second */
tdelta = now->now - iocg->delay_at;
- if (iocg->delay)
- delay = iocg->delay >> div64_u64(tdelta, USEC_PER_SEC);
+ shift = div64_u64(tdelta, USEC_PER_SEC);
+ if (iocg->delay && shift < BITS_PER_LONG)
+ delay = iocg->delay >> shift;
else
delay = 0;
--
2.39.2