Message ID | 0-v1-3d5ed1f20d50+104-gup_overflow_jgg@nvidia.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | mm/gup: Do not return 0 from pin_user_pages_fast() for bad args | expand |
On 6/19/23 11:27, Jason Gunthorpe wrote: > These routines are not intended to return zero, the callers cannot do > anything sane with a 0 return. They should return an error which means > future calls to GUP will not succeed, or they should return some non-zero > number of pinned pages which means GUP should be called again. > > If start + nr_pages overflows it should return -EOVERFLOW to signal the > arguments are invalid. > > Syzkaller keeps tripping on this when fuzzing GUP arguments. > > Reported-by: syzbot+353c7be4964c6253f24a@syzkaller.appspotmail.com > Closes: https://lore.kernel.org/all/000000000000094fdd05faa4d3a4@google.com > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> > --- > mm/gup.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > Reviewed-by: John Hubbard <jhubbard@nvidia.com> thanks,
On Mon, Jun 19, 2023 at 03:27:25PM -0300, Jason Gunthorpe wrote: > These routines are not intended to return zero, the callers cannot do > anything sane with a 0 return. They should return an error which means > future calls to GUP will not succeed, or they should return some non-zero > number of pinned pages which means GUP should be called again. > > If start + nr_pages overflows it should return -EOVERFLOW to signal the > arguments are invalid. It's crazy that it wasn't doing this before. > > Syzkaller keeps tripping on this when fuzzing GUP arguments. > > Reported-by: syzbot+353c7be4964c6253f24a@syzkaller.appspotmail.com > Closes: https://lore.kernel.org/all/000000000000094fdd05faa4d3a4@google.com > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> > --- > mm/gup.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/mm/gup.c b/mm/gup.c > index bbe4162365933e..36c587fec574fd 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -2969,7 +2969,7 @@ static int internal_get_user_pages_fast(unsigned long start, > start = untagged_addr(start) & PAGE_MASK; > len = nr_pages << PAGE_SHIFT; > if (check_add_overflow(start, len, &end)) > - return 0; > + return -EOVERFLOW; > if (end > TASK_SIZE_MAX) > return -EFAULT; > if (unlikely(!access_ok((void __user *)start, len))) > > base-commit: b3eacbbcd0dab69ed4c44cbd2d2d72b016762b17 > -- > 2.40.1 > > Reviewed-by: Lorenzo Stoakes <lstoakes@gmail.com>
On 19.06.23 20:27, Jason Gunthorpe wrote: > These routines are not intended to return zero, the callers cannot do > anything sane with a 0 return. They should return an error which means > future calls to GUP will not succeed, or they should return some non-zero > number of pinned pages which means GUP should be called again. > > If start + nr_pages overflows it should return -EOVERFLOW to signal the > arguments are invalid. > > Syzkaller keeps tripping on this when fuzzing GUP arguments. > > Reported-by: syzbot+353c7be4964c6253f24a@syzkaller.appspotmail.com > Closes: https://lore.kernel.org/all/000000000000094fdd05faa4d3a4@google.com > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> > --- > mm/gup.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/mm/gup.c b/mm/gup.c > index bbe4162365933e..36c587fec574fd 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -2969,7 +2969,7 @@ static int internal_get_user_pages_fast(unsigned long start, > start = untagged_addr(start) & PAGE_MASK; > len = nr_pages << PAGE_SHIFT; > if (check_add_overflow(start, len, &end)) > - return 0; > + return -EOVERFLOW; I'm curious if there is any sane use case where that could actually trigger. Smells like something that should be a WARN_ON_ONCE(), but maybe some callers simply pass through what user-space gave them. Anyhow. Reviewed-by: David Hildenbrand <david@redhat.com>
On Wed, Jun 21, 2023 at 01:24:14PM +0200, David Hildenbrand wrote: > > diff --git a/mm/gup.c b/mm/gup.c > > index bbe4162365933e..36c587fec574fd 100644 > > --- a/mm/gup.c > > +++ b/mm/gup.c > > @@ -2969,7 +2969,7 @@ static int internal_get_user_pages_fast(unsigned long start, > > start = untagged_addr(start) & PAGE_MASK; > > len = nr_pages << PAGE_SHIFT; > > if (check_add_overflow(start, len, &end)) > > - return 0; > > + return -EOVERFLOW; > > I'm curious if there is any sane use case where that could actually trigger. > Smells like something that should be a WARN_ON_ONCE(), but maybe some > callers simply pass through what user-space gave them. Yes, that is pretty common to just pass through. Thanks, Jason
diff --git a/mm/gup.c b/mm/gup.c index bbe4162365933e..36c587fec574fd 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -2969,7 +2969,7 @@ static int internal_get_user_pages_fast(unsigned long start, start = untagged_addr(start) & PAGE_MASK; len = nr_pages << PAGE_SHIFT; if (check_add_overflow(start, len, &end)) - return 0; + return -EOVERFLOW; if (end > TASK_SIZE_MAX) return -EFAULT; if (unlikely(!access_ok((void __user *)start, len)))
These routines are not intended to return zero, the callers cannot do anything sane with a 0 return. They should return an error which means future calls to GUP will not succeed, or they should return some non-zero number of pinned pages which means GUP should be called again. If start + nr_pages overflows it should return -EOVERFLOW to signal the arguments are invalid. Syzkaller keeps tripping on this when fuzzing GUP arguments. Reported-by: syzbot+353c7be4964c6253f24a@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/000000000000094fdd05faa4d3a4@google.com Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> --- mm/gup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) base-commit: b3eacbbcd0dab69ed4c44cbd2d2d72b016762b17