stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h
       [not found] <20200818131227.37020-1-colyli@suse.de>
@ 2020-08-18 13:12 ` Coly Li
  2020-08-18 16:24   ` Christoph Hellwig
  2020-08-18 13:12 ` [PATCH v7 2/6] nvme-tcp: check page by sendpage_ok() before calling kernel_sendpage() Coly Li
  2020-08-18 13:12 ` [PATCH v7 3/6] tcp: use sendpage_ok() to detect misused .sendpage Coly Li
  2 siblings, 1 reply; 9+ messages in thread
From: Coly Li @ 2020-08-18 13:12 UTC (permalink / raw)
  To: linux-block, linux-nvme, netdev, open-iscsi, linux-scsi, ceph-devel
  Cc: linux-kernel, Coly Li, Chaitanya Kulkarni, Christoph Hellwig,
	Hannes Reinecke, Jan Kara, Jens Axboe, Mikhail Skorzhinskii,
	Philipp Reisner, Sagi Grimberg, Vlastimil Babka, stable

The original problem was from nvme-over-tcp code, who mistakenly uses
kernel_sendpage() to send pages allocated by __get_free_pages() without
__GFP_COMP flag. Such pages don't have refcount (page_count is 0) on
tail pages, sending them by kernel_sendpage() may trigger a kernel panic
from a corrupted kernel heap, because these pages are incorrectly freed
in network stack as page_count 0 pages.

This patch introduces a helper sendpage_ok(), it returns true if the
checking page,
- is not slab page: PageSlab(page) is false.
- has page refcount: page_count(page) is not zero

All drivers who want to send page to remote end by kernel_sendpage()
may use this helper to check whether the page is OK. If the helper does
not return true, the driver should try other non sendpage method (e.g.
sock_no_sendpage()) to handle the page.

Signed-off-by: Coly Li <colyli@suse.de>
Cc: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Jan Kara <jack@suse.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Mikhail Skorzhinskii <mskorzhinskiy@solarflare.com>
Cc: Philipp Reisner <philipp.reisner@linbit.com>
Cc: Sagi Grimberg <sagi@grimberg.me>
Cc: Vlastimil Babka <vbabka@suse.com>
Cc: stable@vger.kernel.org
---
 include/linux/net.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/linux/net.h b/include/linux/net.h
index d48ff1180879..05db8690f67e 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -21,6 +21,7 @@
 #include <linux/rcupdate.h>
 #include <linux/once.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
 #include <linux/sockptr.h>
 
 #include <uapi/linux/net.h>
@@ -286,6 +287,21 @@ do {									\
 #define net_get_random_once_wait(buf, nbytes)			\
 	get_random_once_wait((buf), (nbytes))
 
+/*
+ * E.g. XFS meta- & log-data is in slab pages, or bcache meta
+ * data pages, or other high order pages allocated by
+ * __get_free_pages() without __GFP_COMP, which have a page_count
+ * of 0 and/or have PageSlab() set. We cannot use send_page for
+ * those, as that does get_page(); put_page(); and would cause
+ * either a VM_BUG directly, or __page_cache_release a page that
+ * would actually still be referenced by someone, leading to some
+ * obscure delayed Oops somewhere else.
+ */
+static inline bool sendpage_ok(struct page *page)
+{
+	return  !PageSlab(page) && page_count(page) >= 1;
+}
+
 int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
 		   size_t num, size_t len);
 int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v7 2/6] nvme-tcp: check page by sendpage_ok() before calling kernel_sendpage()
       [not found] <20200818131227.37020-1-colyli@suse.de>
  2020-08-18 13:12 ` [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h Coly Li
@ 2020-08-18 13:12 ` Coly Li
  2020-08-18 13:12 ` [PATCH v7 3/6] tcp: use sendpage_ok() to detect misused .sendpage Coly Li
  2 siblings, 0 replies; 9+ messages in thread
From: Coly Li @ 2020-08-18 13:12 UTC (permalink / raw)
  To: linux-block, linux-nvme, netdev, open-iscsi, linux-scsi, ceph-devel
  Cc: linux-kernel, Coly Li, Chaitanya Kulkarni, Christoph Hellwig,
	Hannes Reinecke, Jan Kara, Jens Axboe, Mikhail Skorzhinskii,
	Philipp Reisner, Sagi Grimberg, Vlastimil Babka, stable

Currently nvme_tcp_try_send_data() doesn't use kernel_sendpage() to
send slab pages. But for pages allocated by __get_free_pages() without
__GFP_COMP, which also have refcount as 0, they are still sent by
kernel_sendpage() to remote end, this is problematic.

The new introduced helper sendpage_ok() checks both PageSlab tag and
page_count counter, and returns true if the checking page is OK to be
sent by kernel_sendpage().

This patch fixes the page checking issue of nvme_tcp_try_send_data()
with sendpage_ok(). If sendpage_ok() returns true, send this page by
kernel_sendpage(), otherwise use sock_no_sendpage to handle this page.

Signed-off-by: Coly Li <colyli@suse.de>
Cc: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Jan Kara <jack@suse.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Mikhail Skorzhinskii <mskorzhinskiy@solarflare.com>
Cc: Philipp Reisner <philipp.reisner@linbit.com>
Cc: Sagi Grimberg <sagi@grimberg.me>
Cc: Vlastimil Babka <vbabka@suse.com>
Cc: stable@vger.kernel.org
---
 drivers/nvme/host/tcp.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 62fbaecdc960..902fe742762b 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -912,12 +912,11 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
 		else
 			flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST;
 
-		/* can't zcopy slab pages */
-		if (unlikely(PageSlab(page))) {
-			ret = sock_no_sendpage(queue->sock, page, offset, len,
+		if (sendpage_ok(page)) {
+			ret = kernel_sendpage(queue->sock, page, offset, len,
 					flags);
 		} else {
-			ret = kernel_sendpage(queue->sock, page, offset, len,
+			ret = sock_no_sendpage(queue->sock, page, offset, len,
 					flags);
 		}
 		if (ret <= 0)
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v7 3/6] tcp: use sendpage_ok() to detect misused .sendpage
       [not found] <20200818131227.37020-1-colyli@suse.de>
  2020-08-18 13:12 ` [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h Coly Li
  2020-08-18 13:12 ` [PATCH v7 2/6] nvme-tcp: check page by sendpage_ok() before calling kernel_sendpage() Coly Li
@ 2020-08-18 13:12 ` Coly Li
  2 siblings, 0 replies; 9+ messages in thread
From: Coly Li @ 2020-08-18 13:12 UTC (permalink / raw)
  To: linux-block, linux-nvme, netdev, open-iscsi, linux-scsi, ceph-devel
  Cc: linux-kernel, Coly Li, Eric Dumazet, Vasily Averin,
	David S . Miller, stable

commit a10674bf2406 ("tcp: detecting the misuse of .sendpage for Slab
objects") adds the checks for Slab pages, but the pages don't have
page_count are still missing from the check.

Network layer's sendpage method is not designed to send page_count 0
pages neither, therefore both PageSlab() and page_count() should be
both checked for the sending page. This is exactly what sendpage_ok()
does.

This patch uses sendpage_ok() in do_tcp_sendpages() to detect misused
.sendpage, to make the code more robust.

Fixes: a10674bf2406 ("tcp: detecting the misuse of .sendpage for Slab objects")
Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Coly Li <colyli@suse.de>
Cc: Vasily Averin <vvs@virtuozzo.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: stable@vger.kernel.org
---
 net/ipv4/tcp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 31f3b858db81..2135ee7c806d 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -970,7 +970,8 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
 	long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
 	if (IS_ENABLED(CONFIG_DEBUG_VM) &&
-	    WARN_ONCE(PageSlab(page), "page must not be a Slab one"))
+	    WARN_ONCE(!sendpage_ok(page),
+		      "page must not be a Slab one and have page_count > 0"))
 		return -EINVAL;
 
 	/* Wait for a connection to finish. One exception is TCP Fast Open
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h
  2020-08-18 13:12 ` [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h Coly Li
@ 2020-08-18 16:24   ` Christoph Hellwig
  2020-08-18 16:33     ` Coly Li
  0 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2020-08-18 16:24 UTC (permalink / raw)
  To: Coly Li
  Cc: linux-block, linux-nvme, netdev, open-iscsi, linux-scsi,
	ceph-devel, linux-kernel, Chaitanya Kulkarni, Christoph Hellwig,
	Hannes Reinecke, Jan Kara, Jens Axboe, Mikhail Skorzhinskii,
	Philipp Reisner, Sagi Grimberg, Vlastimil Babka, stable

I think we should go for something simple like this instead:

---
From 4867e158ee86ebd801b4c267e8f8a4a762a71343 Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Tue, 18 Aug 2020 18:19:23 +0200
Subject: net: bypass ->sendpage for slab pages

Sending Slab or tail pages into ->sendpage will cause really strange
delayed oops.  Prevent it right in the networking code instead of
requiring drivers to work around the fact.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 net/socket.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/socket.c b/net/socket.c
index dbbe8ea7d395da..fbc82eb96d18ce 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -3638,7 +3638,12 @@ EXPORT_SYMBOL(kernel_getpeername);
 int kernel_sendpage(struct socket *sock, struct page *page, int offset,
 		    size_t size, int flags)
 {
-	if (sock->ops->sendpage)
+	/*
+	 * sendpage does manipulates the refcount of the passed in page, which
+	 * does not work for Slab pages, or for tails of non-__GFP_COMP
+	 * high order pages.
+	 */
+	if (sock->ops->sendpage && !PageSlab(page) && page_count(page) > 0)
 		return sock->ops->sendpage(sock, page, offset, size, flags);
 
 	return sock_no_sendpage(sock, page, offset, size, flags);
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h
  2020-08-18 16:24   ` Christoph Hellwig
@ 2020-08-18 16:33     ` Coly Li
  2020-08-18 19:49       ` Christoph Hellwig
  0 siblings, 1 reply; 9+ messages in thread
From: Coly Li @ 2020-08-18 16:33 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-block, linux-nvme, netdev, open-iscsi, linux-scsi,
	ceph-devel, linux-kernel, Chaitanya Kulkarni, Hannes Reinecke,
	Jan Kara, Jens Axboe, Mikhail Skorzhinskii, Philipp Reisner,
	Sagi Grimberg, Vlastimil Babka, stable

On 2020/8/19 00:24, Christoph Hellwig wrote:
> I think we should go for something simple like this instead:

This idea is fine to me. Should a warning message be through here? IMHO
the driver still sends an improper page in, fix it in silence is too
kind or over nice to the buggy driver(s).

And maybe the fix in nvme-tcp driver and do_tcp_sendpages() are still
necessary. I am not network expert, this is my opinion for reference.

Coly Li

> ---
> From 4867e158ee86ebd801b4c267e8f8a4a762a71343 Mon Sep 17 00:00:00 2001
> From: Christoph Hellwig <hch@lst.de>
> Date: Tue, 18 Aug 2020 18:19:23 +0200
> Subject: net: bypass ->sendpage for slab pages
> 
> Sending Slab or tail pages into ->sendpage will cause really strange
> delayed oops.  Prevent it right in the networking code instead of
> requiring drivers to work around the fact.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  net/socket.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/net/socket.c b/net/socket.c
> index dbbe8ea7d395da..fbc82eb96d18ce 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -3638,7 +3638,12 @@ EXPORT_SYMBOL(kernel_getpeername);
>  int kernel_sendpage(struct socket *sock, struct page *page, int offset,
>  		    size_t size, int flags)
>  {
> -	if (sock->ops->sendpage)
> +	/*
> +	 * sendpage does manipulates the refcount of the passed in page, which
> +	 * does not work for Slab pages, or for tails of non-__GFP_COMP
> +	 * high order pages.
> +	 */
> +	if (sock->ops->sendpage && !PageSlab(page) && page_count(page) > 0)
>  		return sock->ops->sendpage(sock, page, offset, size, flags);
>  
>  	return sock_no_sendpage(sock, page, offset, size, flags);
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h
  2020-08-18 16:33     ` Coly Li
@ 2020-08-18 19:49       ` Christoph Hellwig
  2020-08-19  4:22         ` Coly Li
  0 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2020-08-18 19:49 UTC (permalink / raw)
  To: Coly Li
  Cc: Christoph Hellwig, linux-block, linux-nvme, netdev, open-iscsi,
	linux-scsi, ceph-devel, linux-kernel, Chaitanya Kulkarni,
	Hannes Reinecke, Jan Kara, Jens Axboe, Mikhail Skorzhinskii,
	Philipp Reisner, Sagi Grimberg, Vlastimil Babka, stable

On Wed, Aug 19, 2020 at 12:33:37AM +0800, Coly Li wrote:
> On 2020/8/19 00:24, Christoph Hellwig wrote:
> > I think we should go for something simple like this instead:
> 
> This idea is fine to me. Should a warning message be through here? IMHO
> the driver still sends an improper page in, fix it in silence is too
> kind or over nice to the buggy driver(s).

I don't think a warning is a good idea.  An API that does the right
thing underneath and doesn't require boiler plate code in most callers
is the right API.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h
  2020-08-18 19:49       ` Christoph Hellwig
@ 2020-08-19  4:22         ` Coly Li
  2020-09-23  8:43           ` Christoph Hellwig
  0 siblings, 1 reply; 9+ messages in thread
From: Coly Li @ 2020-08-19  4:22 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-block, linux-nvme, netdev, open-iscsi, linux-scsi,
	ceph-devel, linux-kernel, Chaitanya Kulkarni, Hannes Reinecke,
	Jan Kara, Jens Axboe, Mikhail Skorzhinskii, Philipp Reisner,
	Sagi Grimberg, Vlastimil Babka, stable

On 2020/8/19 03:49, Christoph Hellwig wrote:
> On Wed, Aug 19, 2020 at 12:33:37AM +0800, Coly Li wrote:
>> On 2020/8/19 00:24, Christoph Hellwig wrote:
>>> I think we should go for something simple like this instead:
>>
>> This idea is fine to me. Should a warning message be through here? IMHO
>> the driver still sends an improper page in, fix it in silence is too
>> kind or over nice to the buggy driver(s).
> 
> I don't think a warning is a good idea.  An API that does the right
> thing underneath and doesn't require boiler plate code in most callers
> is the right API.
> 

Then I don't have more comment.

Thanks.

Coly Li

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h
  2020-08-19  4:22         ` Coly Li
@ 2020-09-23  8:43           ` Christoph Hellwig
  2020-09-23  8:45             ` Coly Li
  0 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2020-09-23  8:43 UTC (permalink / raw)
  To: Coly Li
  Cc: Christoph Hellwig, linux-block, linux-nvme, netdev, open-iscsi,
	linux-scsi, ceph-devel, linux-kernel, Chaitanya Kulkarni,
	Hannes Reinecke, Jan Kara, Jens Axboe, Mikhail Skorzhinskii,
	Philipp Reisner, Sagi Grimberg, Vlastimil Babka, stable

On Wed, Aug 19, 2020 at 12:22:05PM +0800, Coly Li wrote:
> On 2020/8/19 03:49, Christoph Hellwig wrote:
> > On Wed, Aug 19, 2020 at 12:33:37AM +0800, Coly Li wrote:
> >> On 2020/8/19 00:24, Christoph Hellwig wrote:
> >>> I think we should go for something simple like this instead:
> >>
> >> This idea is fine to me. Should a warning message be through here? IMHO
> >> the driver still sends an improper page in, fix it in silence is too
> >> kind or over nice to the buggy driver(s).
> > 
> > I don't think a warning is a good idea.  An API that does the right
> > thing underneath and doesn't require boiler plate code in most callers
> > is the right API.
> > 
> 
> Then I don't have more comment.

So given the feedback from Dave I suspect we should actually resurrect
this series, sorry for the noise.  And in this case I think we do need
the warning in kernel_sendpage.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h
  2020-09-23  8:43           ` Christoph Hellwig
@ 2020-09-23  8:45             ` Coly Li
  0 siblings, 0 replies; 9+ messages in thread
From: Coly Li @ 2020-09-23  8:45 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-block, linux-nvme, netdev, open-iscsi, linux-scsi,
	ceph-devel, linux-kernel, Chaitanya Kulkarni, Hannes Reinecke,
	Jan Kara, Jens Axboe, Mikhail Skorzhinskii, Philipp Reisner,
	Sagi Grimberg, Vlastimil Babka, stable

On 2020/9/23 16:43, Christoph Hellwig wrote:
> On Wed, Aug 19, 2020 at 12:22:05PM +0800, Coly Li wrote:
>> On 2020/8/19 03:49, Christoph Hellwig wrote:
>>> On Wed, Aug 19, 2020 at 12:33:37AM +0800, Coly Li wrote:
>>>> On 2020/8/19 00:24, Christoph Hellwig wrote:
>>>>> I think we should go for something simple like this instead:
>>>>
>>>> This idea is fine to me. Should a warning message be through here? IMHO
>>>> the driver still sends an improper page in, fix it in silence is too
>>>> kind or over nice to the buggy driver(s).
>>>
>>> I don't think a warning is a good idea.  An API that does the right
>>> thing underneath and doesn't require boiler plate code in most callers
>>> is the right API.
>>>
>>
>> Then I don't have more comment.
> 
> So given the feedback from Dave I suspect we should actually resurrect
> this series, sorry for the noise.  And in this case I think we do need
> the warning in kernel_sendpage.
> 

Copied, then I will post a v8 series, which adding a warning message in
kernel_sendpage() if non-acceptible paage sent in.

Coly Li

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2020-09-23  8:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20200818131227.37020-1-colyli@suse.de>
2020-08-18 13:12 ` [PATCH v7 1/6] net: introduce helper sendpage_ok() in include/linux/net.h Coly Li
2020-08-18 16:24   ` Christoph Hellwig
2020-08-18 16:33     ` Coly Li
2020-08-18 19:49       ` Christoph Hellwig
2020-08-19  4:22         ` Coly Li
2020-09-23  8:43           ` Christoph Hellwig
2020-09-23  8:45             ` Coly Li
2020-08-18 13:12 ` [PATCH v7 2/6] nvme-tcp: check page by sendpage_ok() before calling kernel_sendpage() Coly Li
2020-08-18 13:12 ` [PATCH v7 3/6] tcp: use sendpage_ok() to detect misused .sendpage Coly Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).