* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
@ 2019-07-22 11:47 Dan Carpenter
2019-07-22 11:50 ` Dan Carpenter
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Dan Carpenter @ 2019-07-22 11:47 UTC (permalink / raw)
To: target-devel
On Mon, Jul 22, 2019 at 12:23:56PM +0800, laokz wrote:
> Hello,
>
> A couple of weeks ago, I reported the respect author/maintainers. Haven't
> got reply yet, so I come here.
>
> The following is based on kernel 5.2-rc6.
>
> include/linux/kfifo.h::kfifo_init() initialize a fifo using a preallocated
> buffer. It requests the buffer size should be power_of_two, if not so, the
> actual worker __kfifo_init() will round UP it to the next power of two. For
> it just records the new size in fifo's internal parameters, does not touch
> the real buffer, obviously this may introduce buffer overflow.
>
> In the source tree, I found an instance.
>
> In drivers/scsi/ibmvscsi_tgt/libsrp.c::srp_iu_pool_alloc(), it calls
> kcalloc() and kfifo_init() with buffer size=max*sizeof(void
> *)=INITIAL_SRP_LIMIT*sizeof(void *), most likely be
> 800*8d00. That is NOT power of 2, KFIFO will treat it as 8192 big! Bad.
>
> Here is its only call-chain:
> #define INITIAL_SRP_LIMIT 800 /* ibmvscsi_tgt.c */
> ibmvscsis_probe()::vscsi->request_limit=INITIAL_SRP_LIMIT
> -> srp_target_alloc(,vscsi->request_limit,) /* libsrp.c */
> ->srp_iu_pool_alloc(,nr,) /* nr=vscsi->request_limit */
> ->kfifo_init(,max*sizeof(void *),) /* max=nr */
>
> I know before kernel 3.9 __kfifo_init() algorithm was rounddown. I don't
> know why changed to roundup, but it is safe and more robust to rounddown
> instead of roundup.
>
> If i'm wrong, please let me know also. Thanks.
It looks like you're right. Probably the fix is to:
1) Change INITIAL_SRP_LIMIT to 8192
2) Change kfifo_init() to round down like you say
3) Add a WARN_ONCE() in kfifo_alloc and kfifo_init() if the size isn't
a power of two.
regards,
dan carpenter
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
@ 2019-07-22 11:50 ` Dan Carpenter
2019-08-02 7:30 ` Greg KH
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Dan Carpenter @ 2019-07-22 11:50 UTC (permalink / raw)
To: target-devel
On Mon, Jul 22, 2019 at 02:47:00PM +0300, Dan Carpenter wrote:
> On Mon, Jul 22, 2019 at 12:23:56PM +0800, laokz wrote:
> > Hello,
> >
> > A couple of weeks ago, I reported the respect author/maintainers. Haven't
> > got reply yet, so I come here.
> >
> > The following is based on kernel 5.2-rc6.
> >
> > include/linux/kfifo.h::kfifo_init() initialize a fifo using a preallocated
> > buffer. It requests the buffer size should be power_of_two, if not so, the
> > actual worker __kfifo_init() will round UP it to the next power of two. For
> > it just records the new size in fifo's internal parameters, does not touch
> > the real buffer, obviously this may introduce buffer overflow.
> >
> > In the source tree, I found an instance.
> >
> > In drivers/scsi/ibmvscsi_tgt/libsrp.c::srp_iu_pool_alloc(), it calls
> > kcalloc() and kfifo_init() with buffer size=max*sizeof(void
> > *)=INITIAL_SRP_LIMIT*sizeof(void *), most likely be
> > 800*8d00. That is NOT power of 2, KFIFO will treat it as 8192 big! Bad.
> >
> > Here is its only call-chain:
> > #define INITIAL_SRP_LIMIT 800 /* ibmvscsi_tgt.c */
> > ibmvscsis_probe()::vscsi->request_limit=INITIAL_SRP_LIMIT
> > -> srp_target_alloc(,vscsi->request_limit,) /* libsrp.c */
> > ->srp_iu_pool_alloc(,nr,) /* nr=vscsi->request_limit */
> > ->kfifo_init(,max*sizeof(void *),) /* max=nr */
> >
> > I know before kernel 3.9 __kfifo_init() algorithm was rounddown. I don't
> > know why changed to roundup, but it is safe and more robust to rounddown
> > instead of roundup.
> >
> > If i'm wrong, please let me know also. Thanks.
>
> It looks like you're right. Probably the fix is to:
> 1) Change INITIAL_SRP_LIMIT to 8192
I meant 1024 not 8192.
regards,
dan carpenter
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
2019-07-22 11:50 ` Dan Carpenter
@ 2019-08-02 7:30 ` Greg KH
2019-08-29 17:21 ` Kees Cook
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Greg KH @ 2019-08-02 7:30 UTC (permalink / raw)
To: target-devel
On Mon, Jul 22, 2019 at 09:26:23PM +0800, laokz wrote:
> Hello Dan,
>
> On Mon, Jul 22, 2019 at 14:50 +0300,Dan Carpenter wrote:
> > > It looks like you're right. Probably the fix is to:
> > > 1) Change INITIAL_SRP_LIMIT to 8192
> >
> > I meant 1024 not 8192.
>
> Nice to see that. It really helped for me. Thank you very much.
Did anything ever happen with this? Was a patch submitted to resolve
this issue?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
2019-07-22 11:50 ` Dan Carpenter
2019-08-02 7:30 ` Greg KH
@ 2019-08-29 17:21 ` Kees Cook
2019-08-29 18:48 ` Linus Torvalds
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Kees Cook @ 2019-08-29 17:21 UTC (permalink / raw)
To: target-devel
On Tue, Aug 06, 2019 at 06:27:13PM +0800, laokz wrote:
> On Fri, Aug 2, 2019 at 09:30 +0200,Greg KH wrote:
> > On Mon, Jul 22, 2019 at 09:26:23PM +0800, laokz wrote:
> > > Hello Dan,
> > >
> > > On Mon, Jul 22, 2019 at 14:50 +0300,Dan Carpenter wrote:
> > > > > It looks like you're right. Probably the fix is to:
> > > > > 1) Change INITIAL_SRP_LIMIT to 8192
> > > >
> > > > I meant 1024 not 8192.
> > >
> > > Nice to see that. It really helped for me. Thank you very much.
> >
> > Did anything ever happen with this? Was a patch submitted to resolve
> > this issue?
> Sorry for the late reply. I didn't submit any patch, for as newbie I wasn't
> quite sure about the severity of this issue. The developers may do their
> choice.
It's worth fixing regardless. :) Did a patch get sent for this?
--
Kees Cook
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
` (2 preceding siblings ...)
2019-08-29 17:21 ` Kees Cook
@ 2019-08-29 18:48 ` Linus Torvalds
2019-08-29 19:32 ` Linus Torvalds
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Linus Torvalds @ 2019-08-29 18:48 UTC (permalink / raw)
To: target-devel
On Tue, Aug 6, 2019 at 3:29 AM laokz <laokz@foxmail.com> wrote:
>
> Sorry for the late reply. I didn't submit any patch, for as newbie I wasn't
> quite sure about the severity of this issue. The developers may do their
> choice.
It does seem pretty bad.
Also, INIT_KFIFO() and DECLARE_KFIFO() should probably have a
BUILD_BUG_ON(!__is_kfifo_ptr && !is_power_of_2(ARRAY_SIZE(__tmp->buf)));
or something. Probably worth indirection through a helper macro to set
the ".mask" field.
And yes, commit dfe2a77fd243 ("kfifo: fix kfifo_alloc() and
kfifo_init()") seems wrong, It's fine for the __kfifo_alloc() case
where we actually allocate the rounded-up size, but it's completely
wrong for the __kfifo_init() case where somebody _else_ allocated the
size.
So the kfifo_init() case needs to just use a round_down, and possibly
add a WARN_ON_ONCE() too.
Anybody?
Linus
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
` (3 preceding siblings ...)
2019-08-29 18:48 ` Linus Torvalds
@ 2019-08-29 19:32 ` Linus Torvalds
2019-08-29 19:40 ` Stefani Seibold
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Linus Torvalds @ 2019-08-29 19:32 UTC (permalink / raw)
To: target-devel
[-- Attachment #1: Type: text/plain, Size: 194 bytes --]
On Thu, Aug 29, 2019 at 11:48 AM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> Anybody?
This is ENTIRELY UNTESTED.
Anybody willing to test and take ownership?
Linus
[-- Attachment #2: patch.diff --]
[-- Type: text/x-patch, Size: 1915 bytes --]
include/linux/kfifo.h | 12 ++++++++----
lib/kfifo.c | 4 +++-
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h
index fc4b0b10210f..078f52c20aad 100644
--- a/include/linux/kfifo.h
+++ b/include/linux/kfifo.h
@@ -117,6 +117,12 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
*/
#define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo
+#define VERIFY_POWER_OF2(x) \
+ ((x)+BUILD_BUG_ON_ZERO((x) & ((x)-1)))
+
+#define __KFIFO_MASK_SIZE(fifo) \
+ (__is_kfifo_ptr(&(fifo)) ? 0 : VERIFY_POWER_OF2(ARRAY_SIZE((fifo).buf)) - 1)
+
/**
* INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO
* @fifo: name of the declared fifo datatype
@@ -127,7 +133,7 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
struct __kfifo *__kfifo = &__tmp->kfifo; \
__kfifo->in = 0; \
__kfifo->out = 0; \
- __kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\
+ __kfifo->mask = __KFIFO_MASK_SIZE(fifo); \
__kfifo->esize = sizeof(*__tmp->buf); \
__kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \
})
@@ -147,9 +153,7 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
{ \
.in = 0, \
.out = 0, \
- .mask = __is_kfifo_ptr(&(fifo)) ? \
- 0 : \
- ARRAY_SIZE((fifo).buf) - 1, \
+ .mask = __KFIFO_MASK_SIZE(fifo), \
.esize = sizeof(*(fifo).buf), \
.data = __is_kfifo_ptr(&(fifo)) ? \
NULL : \
diff --git a/lib/kfifo.c b/lib/kfifo.c
index 117ad0e7fbf4..7f145cb41e6d 100644
--- a/lib/kfifo.c
+++ b/lib/kfifo.c
@@ -68,7 +68,9 @@ int __kfifo_init(struct __kfifo *fifo, void *buffer,
{
size /= esize;
- size = roundup_pow_of_two(size);
+ /* Warn because we had a bug here and would round up */
+ if (WARN_ON_ONCE(!is_power_of_2(size)))
+ size = rounddown_pow_of_two(size);
fifo->in = 0;
fifo->out = 0;
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
` (4 preceding siblings ...)
2019-08-29 19:32 ` Linus Torvalds
@ 2019-08-29 19:40 ` Stefani Seibold
2019-08-29 19:42 ` Kees Cook
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Stefani Seibold @ 2019-08-29 19:40 UTC (permalink / raw)
To: target-devel
Hi Linus,
i am back from vacation next week. I will have a look on it.
Stefani
Am Donnerstag, den 29.08.2019, 12:32 -0700 schrieb Linus Torvalds:
> On Thu, Aug 29, 2019 at 11:48 AM Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> > Anybody?
>
> This is ENTIRELY UNTESTED.
>
> Anybody willing to test and take ownership?
>
> Linus
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
` (5 preceding siblings ...)
2019-08-29 19:40 ` Stefani Seibold
@ 2019-08-29 19:42 ` Kees Cook
2019-08-29 21:51 ` Will Deacon
2019-09-01 17:38 ` Linus Torvalds
8 siblings, 0 replies; 10+ messages in thread
From: Kees Cook @ 2019-08-29 19:42 UTC (permalink / raw)
To: target-devel
On Thu, Aug 29, 2019 at 12:32:41PM -0700, Linus Torvalds wrote:
> On Thu, Aug 29, 2019 at 11:48 AM Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
> > Anybody?
>
> This is ENTIRELY UNTESTED.
>
> Anybody willing to test and take ownership?
I don't know this code at all, but note below...
>
> Linus
> include/linux/kfifo.h | 12 ++++++++----
> lib/kfifo.c | 4 +++-
> 2 files changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h
> index fc4b0b10210f..078f52c20aad 100644
> --- a/include/linux/kfifo.h
> +++ b/include/linux/kfifo.h
> @@ -117,6 +117,12 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
> */
> #define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo
>
> +#define VERIFY_POWER_OF2(x) \
> + ((x)+BUILD_BUG_ON_ZERO((x) & ((x)-1)))
> +
> +#define __KFIFO_MASK_SIZE(fifo) \
> + (__is_kfifo_ptr(&(fifo)) ? 0 : VERIFY_POWER_OF2(ARRAY_SIZE((fifo).buf)) - 1)
> +
> /**
> * INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO
> * @fifo: name of the declared fifo datatype
> @@ -127,7 +133,7 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
> struct __kfifo *__kfifo = &__tmp->kfifo; \
> __kfifo->in = 0; \
> __kfifo->out = 0; \
> - __kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\
> + __kfifo->mask = __KFIFO_MASK_SIZE(fifo); \
I think this should be:
+ __kfifo->mask = __KFIFO_MASK_SIZE(*__tmp); \
? I didn't compile it, but I saw the others were using (fifo).buf but
this was using __tmp->buf.
> __kfifo->esize = sizeof(*__tmp->buf); \
> __kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \
> })
> @@ -147,9 +153,7 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
> { \
> .in = 0, \
> .out = 0, \
> - .mask = __is_kfifo_ptr(&(fifo)) ? \
> - 0 : \
> - ARRAY_SIZE((fifo).buf) - 1, \
> + .mask = __KFIFO_MASK_SIZE(fifo), \
> .esize = sizeof(*(fifo).buf), \
> .data = __is_kfifo_ptr(&(fifo)) ? \
> NULL : \
> diff --git a/lib/kfifo.c b/lib/kfifo.c
> index 117ad0e7fbf4..7f145cb41e6d 100644
> --- a/lib/kfifo.c
> +++ b/lib/kfifo.c
> @@ -68,7 +68,9 @@ int __kfifo_init(struct __kfifo *fifo, void *buffer,
> {
> size /= esize;
>
> - size = roundup_pow_of_two(size);
> + /* Warn because we had a bug here and would round up */
> + if (WARN_ON_ONCE(!is_power_of_2(size)))
> + size = rounddown_pow_of_two(size);
>
> fifo->in = 0;
> fifo->out = 0;
--
Kees Cook
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
` (6 preceding siblings ...)
2019-08-29 19:42 ` Kees Cook
@ 2019-08-29 21:51 ` Will Deacon
2019-09-01 17:38 ` Linus Torvalds
8 siblings, 0 replies; 10+ messages in thread
From: Will Deacon @ 2019-08-29 21:51 UTC (permalink / raw)
To: target-devel
On Thu, Aug 29, 2019 at 01:00:21PM -0700, Linus Torvalds wrote:
> [ at the dentist, sorry for mobile html gunk ]
>
> On Thu, Aug 29, 2019, 12:42 Kees Cook <keescook@chromium.org> wrote:
>
> On Thu,
>
> I don't know this code at all, but note below...
>
> > + __kfifo->mask = __KFIFO_MASK_SIZE(fifo); \
>
> I think this should be:
>
> + __kfifo->mask = __KFIFO_MASK_SIZE(*__tmp); \
>
> ?
>
>
> If it matters, we're in deep doo-doo. It only uses the type of the thing, not
> the value, so it's immaterial. I think it's easier to use the original type
> rather than the temporary that we created using it..
>
> But that's the least of my worries in that code.
If it makes you feel any better [perhaps as a distraction from the dreaded
dentist], the memory ordering side of things is suspicious as well:
https://lore.kernel.org/lkml/CAGXu5jKkqf-9ksvNTCS5xgB_JtfvCc=Eot2uWYYP8rpoKLw=mg@mail.gmail.com/
When I started pulling on it, it all fell apart, so I haven't had a
chance to do a proper set of fixes.
Will
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bug report: KFIFO kfifo_init() may introduce buffer overflow
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
` (7 preceding siblings ...)
2019-08-29 21:51 ` Will Deacon
@ 2019-09-01 17:38 ` Linus Torvalds
8 siblings, 0 replies; 10+ messages in thread
From: Linus Torvalds @ 2019-09-01 17:38 UTC (permalink / raw)
To: target-devel
On Sun, Sep 1, 2019 at 10:11 AM laokz <laokz@foxmail.com> wrote:
>
> At first glance, I thought this issue was serious, based on user space
> experience. Later I realized it may be trivial in kernel space, for kmalloc
> also using roundup_power_of_2 algorithm through SLAB/SLUB.
No, there are definitely slab sizes that aren't always powers of two.
It may be that almost by mistake, the particular one problem you point
out (ibmvscsi_tgt) ends up having its allocation grown to a power of
two, so it's not a problem in practice, but you definitely found a
bug.
I ended up doing a minimal half-revert in commit ab9bb6318b09
("Partially revert "kfifo: fix kfifo_alloc() and kfifo_init()"") which
fixes the basic problem.
> > Also, INIT_KFIFO() and DECLARE_KFIFO() should probably have a
> >
> > BUILD_BUG_ON(!__is_kfifo_ptr && !is_power_of_2(ARRAY_SIZE(__tmp-
> > >buf)));
> >
> > or something. Probably worth indirection through a helper macro to set
> > the ".mask" field.
>
> Now, I learned that actual scenario may be more complex and uncontrollable
> in some degree, supposing this issue had a statically allocated buffer. So,
> it's worth to use least cost to keep kernel from potential damage.
It turns out that DECLARE_KFIFO ends up protecting against bad kfifo
sizes, because __STRUCT_KFIFO() does this:
type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \
which is making sure that size is at least 2 and a power-of-two. If it
isn't, the compiler will error out due to a negative array size thanks
to that check.
So it's _probably_ the case that the only actual problem was
kfifo_init() itself. And yes, it's quite possible that the only user
that didn't use a power of two ended up having SLAB round that
allocation up for the size it *did* use.
But your bug report was valid, and I'd love you to double-check all
this. Code that just happens to work by mistake is still a serious bug
waiting to happen.
Thanks,
Linus
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2019-09-01 17:38 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-07-22 11:47 Bug report: KFIFO kfifo_init() may introduce buffer overflow Dan Carpenter
2019-07-22 11:50 ` Dan Carpenter
2019-08-02 7:30 ` Greg KH
2019-08-29 17:21 ` Kees Cook
2019-08-29 18:48 ` Linus Torvalds
2019-08-29 19:32 ` Linus Torvalds
2019-08-29 19:40 ` Stefani Seibold
2019-08-29 19:42 ` Kees Cook
2019-08-29 21:51 ` Will Deacon
2019-09-01 17:38 ` Linus Torvalds
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.