Re: [PATCH v6 2/5] nfs: track number of pinned pages in nfs_page

Pranjal Shrivastava <[email protected]>
Newsgroups org.kernel.vger.linux-pci,dev.linux.lists.sashiko-reviews
Message-ID <[email protected]>
On Fri, Aug 14, 2026 at 02:47:13PM +0000, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] Latent stack out-of-bounds read by passing a single local stack variable to unpin_user_pages() with a dynamically loaded length.
> --
> 
> --- Patch [2]: [PATCH v6 2/5] nfs: track number of pinned pages in nfs_page ---
> commit 1fad80f498aa716421accabc5c2572235b589709
> Author: Pranjal Shrivastava <[email protected]>
> 
> nfs: track number of pinned pages in nfs_page
> 
> This commit adds wb_nr_pinned to struct nfs_page to track the number
> of pinned pages. It updates request creation and cleanup helpers to
> ensure that only primary requests perform the final unpinning operation.
> 
> > diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
> > index a562cfe2a126d..b9ccf2a87e3c9 100644
> > --- a/fs/nfs/pagelist.c
> > +++ b/fs/nfs/pagelist.c
> 
> [ ... ]
> 
> > @@ -567,8 +572,8 @@ static void nfs_clear_request(struct nfs_page *req)
> >  
> >  	if (folio != NULL) {
> >  		if (test_and_clear_bit(PG_PINNED, &req->wb_flags)) {
> > -			if (req == req->wb_head)
> > -				unpin_user_folio(folio, 1);
> > +			if (req->wb_nr_pinned > 0)
> > +				unpin_user_folio(folio, req->wb_nr_pinned);
> >  		} else {
> >  			folio_put(folio);
> >  		}
> > @@ -576,8 +581,8 @@ static void nfs_clear_request(struct nfs_page *req)
> >  		clear_bit(PG_FOLIO, &req->wb_flags);
> >  	} else if (page != NULL) {
> >  		if (test_and_clear_bit(PG_PINNED, &req->wb_flags)) {
> > -			if (req == req->wb_head)
> > -				unpin_user_page(page);
> > +			if (req->wb_nr_pinned > 0)
> > +				unpin_user_pages(&page, req->wb_nr_pinned);
> 
> [Severity: Medium]
> Could this lead to an out-of-bounds stack read if wb_nr_pinned is ever
> greater than 1?
> 
> Looking at nfs_clear_request(), page is declared as a single local pointer
> on the stack:
> 
> static void nfs_clear_request(struct nfs_page *req)
> {
> 	...
> 	struct page *page = req->wb_page;
> 
> If req->wb_nr_pinned exceeds 1, unpin_user_pages() will read adjacent stack
> memory to interpret as struct page pointers. While wb_nr_pinned is currently
> hardcoded to 1 when a request is created from a page, passing a dynamically
> loaded length alongside a pointer to a single local stack variable seems
> prone to future regressions.
> 

In this (non-folio) path wb_nr_pinned would always ever be 1. Although,
I think we could use unpin_user_page (singular) here.

Thanks,
Praan

> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.