2022-11-18 14:29:54

by Dominique Martinet

[permalink] [raw]
Subject: [PATCH 1/2] 9p/xen: check logical size for buffer size

trans_xen did not check the data fits into the buffer before copying
from the xen ring, but we probably should.
Add a check that just skips the request and return an error to
userspace if it did not fit

Signed-off-by: Dominique Martinet <[email protected]>
---

This comes more or less as a follow up of a fix for trans_fd:
https://lkml.kernel.org/r/[email protected]
Where msize should be replaced by capacity check, except trans_xen
did not actually use to check the size fits at all.

While we normally trust the hypervisor (they can probably do whatever
they want with our memory), a bug in the 9p server is always possible so
sanity checks never hurt, especially now buffers got drastically smaller
with a recent patch.

My setup for xen is unfortunately long dead so I cannot test this:
Stefano, you've tested v9fs xen patches in the past, would you mind
verifying this works as well?

net/9p/trans_xen.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
index b15c64128c3e..66ceb3b3ae30 100644
--- a/net/9p/trans_xen.c
+++ b/net/9p/trans_xen.c
@@ -208,6 +208,14 @@ static void p9_xen_response(struct work_struct *work)
continue;
}

+ if (h.size > req->rc.capacity) {
+ dev_warn(&priv->dev->dev,
+ "requested packet size too big: %d for tag %d with capacity %zd\n",
+ h.size, h.tag, rreq->rc.capacity);
+ req->status = REQ_STATUS_ERROR;
+ goto recv_error;
+ }
+
memcpy(&req->rc, &h, sizeof(h));
req->rc.offset = 0;

@@ -217,6 +225,7 @@ static void p9_xen_response(struct work_struct *work)
masked_prod, &masked_cons,
XEN_9PFS_RING_SIZE(ring));

+recv_error:
virt_mb();
cons += h.size;
ring->intf->in_cons = cons;
--
2.38.1



2022-11-18 14:35:57

by Dominique Martinet

[permalink] [raw]
Subject: [PATCH 2/2] 9p: ensure logical size fits allocated size

all buffers used to be msize big, but the size can now vary based on
message type and arguments.

Adjut p9_check_error() to check the logical size (request payload) fits
within the allocated size (capacity) rather than msize

Transports normally all check this when the packet is being read, but
might as well stay coherent.

Fixes: 60ece0833b6c ("net/9p: allocate appropriate reduced message buffers")
Signed-off-by: Dominique Martinet <[email protected]>
---

I think with the previous patch this is purely redundant, but better
safe than sorry...
The main problem is that if we didn't find this before we already
overflowed a buffer, so this is quite late!

net/9p/client.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/9p/client.c b/net/9p/client.c
index aaa37b07e30a..45dcc9e5d091 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -514,7 +514,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
int ecode;

err = p9_parse_header(&req->rc, NULL, &type, NULL, 0);
- if (req->rc.size >= c->msize) {
+ if (req->rc.size >= req->rc.capacity) {
p9_debug(P9_DEBUG_ERROR,
"requested packet size too big: %d\n",
req->rc.size);
--
2.38.1


2022-11-19 02:28:33

by Stefano Stabellini

[permalink] [raw]
Subject: Re: [PATCH 1/2] 9p/xen: check logical size for buffer size

On Fri, 18 Nov 2022, Dominique Martinet wrote:
> trans_xen did not check the data fits into the buffer before copying
> from the xen ring, but we probably should.
> Add a check that just skips the request and return an error to
> userspace if it did not fit
>
> Signed-off-by: Dominique Martinet <[email protected]>
> ---
>
> This comes more or less as a follow up of a fix for trans_fd:
> https://lkml.kernel.org/r/[email protected]
> Where msize should be replaced by capacity check, except trans_xen
> did not actually use to check the size fits at all.
>
> While we normally trust the hypervisor (they can probably do whatever
> they want with our memory), a bug in the 9p server is always possible so
> sanity checks never hurt, especially now buffers got drastically smaller
> with a recent patch.
>
> My setup for xen is unfortunately long dead so I cannot test this:
> Stefano, you've tested v9fs xen patches in the past, would you mind
> verifying this works as well?
>
> net/9p/trans_xen.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
> index b15c64128c3e..66ceb3b3ae30 100644
> --- a/net/9p/trans_xen.c
> +++ b/net/9p/trans_xen.c
> @@ -208,6 +208,14 @@ static void p9_xen_response(struct work_struct *work)
> continue;
> }
>
> + if (h.size > req->rc.capacity) {
> + dev_warn(&priv->dev->dev,
> + "requested packet size too big: %d for tag %d with capacity %zd\n",
> + h.size, h.tag, rreq->rc.capacity);

"req" instead of "rreq"

I made this change and tried the two patches together. Unfortunately I
get the following error as soon as I try to write a file:

/bin/sh: can't create /mnt/file: Input/output error


Next I reverted the second patch and only kept this patch. With that, it
worked as usual. It looks like the second patch is the problem. I have
not investigated further.



> + req->status = REQ_STATUS_ERROR;
> + goto recv_error;
> + }
> +
> memcpy(&req->rc, &h, sizeof(h));
> req->rc.offset = 0;
>
> @@ -217,6 +225,7 @@ static void p9_xen_response(struct work_struct *work)
> masked_prod, &masked_cons,
> XEN_9PFS_RING_SIZE(ring));
>
> +recv_error:
> virt_mb();
> cons += h.size;
> ring->intf->in_cons = cons;
> --
> 2.38.1
>

2022-11-19 03:28:42

by Dominique Martinet

[permalink] [raw]
Subject: Re: [PATCH 1/2] 9p/xen: check logical size for buffer size

Thanks a lot, that was fast!

Stefano Stabellini wrote on Fri, Nov 18, 2022 at 05:51:46PM -0800:
> On Fri, 18 Nov 2022, Dominique Martinet wrote:
> > trans_xen did not check the data fits into the buffer before copying
> > from the xen ring, but we probably should.
> > Add a check that just skips the request and return an error to
> > userspace if it did not fit
> >
> > Signed-off-by: Dominique Martinet <[email protected]>
> > ---
> >
> > This comes more or less as a follow up of a fix for trans_fd:
> > https://lkml.kernel.org/r/[email protected]
> > Where msize should be replaced by capacity check, except trans_xen
> > did not actually use to check the size fits at all.
> >
> > While we normally trust the hypervisor (they can probably do whatever
> > they want with our memory), a bug in the 9p server is always possible so
> > sanity checks never hurt, especially now buffers got drastically smaller
> > with a recent patch.
> >
> > My setup for xen is unfortunately long dead so I cannot test this:
> > Stefano, you've tested v9fs xen patches in the past, would you mind
> > verifying this works as well?
> >
> > net/9p/trans_xen.c | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
> > index b15c64128c3e..66ceb3b3ae30 100644
> > --- a/net/9p/trans_xen.c
> > +++ b/net/9p/trans_xen.c
> > @@ -208,6 +208,14 @@ static void p9_xen_response(struct work_struct *work)
> > continue;
> > }
> >
> > + if (h.size > req->rc.capacity) {
> > + dev_warn(&priv->dev->dev,
> > + "requested packet size too big: %d for tag %d with capacity %zd\n",
> > + h.size, h.tag, rreq->rc.capacity);
>
> "req" instead of "rreq"

ugh, sorry for that. I didn't realize I have NET_9P_XEN=n on this
machine ... /facepalm

I'm lazy so won't bother sending a v2:
https://github.com/martinetd/linux/commit/ebd09c8245aa15f15b273e9733e8ed8991db3682

I'll add your Tested-by tomorrow unless you don't want to :)


> I made this change and tried the two patches together. Unfortunately I
> get the following error as soon as I try to write a file:
>
> /bin/sh: can't create /mnt/file: Input/output error
>
>
> Next I reverted the second patch and only kept this patch. With that, it
> worked as usual. It looks like the second patch is the problem. I have
> not investigated further.

Thanks -- it's now obvious I shouldn't send patches without testing
before bedtime...
I could reproduce easily with virtio as well, this one was silly as well
(>= instead of >). . . With another problem when zc requests get
involved, as we don't actually allocate more than 4k for the rpc itself.

If I adjust it to also check with the zc 'inlen' as follow it appears to
work:
https://github.com/martinetd/linux/commit/162015a0dac40eccc9e8311a5eb031596ad35e82
But that inlen isn't actually precise, and trans_virtio (the only
transport implementing zc rpc) actually takes some liberty with the
actual sg size to better fit hardwre, so that doesn't really make
sense either and we probably should just trust trans_virtio at this
point?

This isn't obvious, so I'll just drop this patch for now.
Checking witih msize isn't any good but it can wait till we sort it out
as transports now all already check this one way or another; I'd like to
get the actual fixes out first.

(Christian, if you have time to look at it and take over I'd appreciate
it, but there's no hurry.)


Thanks again and sorry for the bad patches!
--
Dominique

2022-11-21 14:50:11

by Christian Schoenebeck

[permalink] [raw]
Subject: Re: [PATCH 1/2] 9p/xen: check logical size for buffer size

On Saturday, November 19, 2022 3:31:41 AM CET Dominique Martinet wrote:
[...]
> > I made this change and tried the two patches together. Unfortunately I
> > get the following error as soon as I try to write a file:
> >
> > /bin/sh: can't create /mnt/file: Input/output error
> >
> >
> > Next I reverted the second patch and only kept this patch. With that, it
> > worked as usual. It looks like the second patch is the problem. I have
> > not investigated further.
>
> Thanks -- it's now obvious I shouldn't send patches without testing
> before bedtime...
> I could reproduce easily with virtio as well, this one was silly as well
> (>= instead of >). . . With another problem when zc requests get
> involved, as we don't actually allocate more than 4k for the rpc itself.
>
> If I adjust it to also check with the zc 'inlen' as follow it appears to
> work:
> https://github.com/martinetd/linux/commit/162015a0dac40eccc9e8311a5eb031596ad35e82
> But that inlen isn't actually precise, and trans_virtio (the only
> transport implementing zc rpc) actually takes some liberty with the
> actual sg size to better fit hardwre, so that doesn't really make
> sense either and we probably should just trust trans_virtio at this
> point?
>
> This isn't obvious, so I'll just drop this patch for now.
> Checking witih msize isn't any good but it can wait till we sort it out
> as transports now all already check this one way or another; I'd like to
> get the actual fixes out first.
>
> (Christian, if you have time to look at it and take over I'd appreciate
> it, but there's no hurry.)

OK, I'll look at this.

Best regards,
Christian Schoenebeck



2022-11-21 17:37:48

by Christian Schoenebeck

[permalink] [raw]
Subject: Re: [PATCH 1/2] 9p/xen: check logical size for buffer size

On Friday, November 18, 2022 2:55:41 PM CET Dominique Martinet wrote:
> trans_xen did not check the data fits into the buffer before copying
> from the xen ring, but we probably should.
> Add a check that just skips the request and return an error to
> userspace if it did not fit
>
> Signed-off-by: Dominique Martinet <[email protected]>
> ---
>
> This comes more or less as a follow up of a fix for trans_fd:
> https://lkml.kernel.org/r/[email protected]
> Where msize should be replaced by capacity check, except trans_xen
> did not actually use to check the size fits at all.
>
> While we normally trust the hypervisor (they can probably do whatever
> they want with our memory), a bug in the 9p server is always possible so
> sanity checks never hurt, especially now buffers got drastically smaller
> with a recent patch.
>
> My setup for xen is unfortunately long dead so I cannot test this:
> Stefano, you've tested v9fs xen patches in the past, would you mind
> verifying this works as well?
>
> net/9p/trans_xen.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
> index b15c64128c3e..66ceb3b3ae30 100644
> --- a/net/9p/trans_xen.c
> +++ b/net/9p/trans_xen.c
> @@ -208,6 +208,14 @@ static void p9_xen_response(struct work_struct *work)
> continue;
> }
>
> + if (h.size > req->rc.capacity) {
> + dev_warn(&priv->dev->dev,
> + "requested packet size too big: %d for tag %d with capacity %zd\n",
> + h.size, h.tag, rreq->rc.capacity);
> + req->status = REQ_STATUS_ERROR;
> + goto recv_error;
> + }
> +

Looks good (except of s/rreq/req/ mentioned by Stefano already).

> memcpy(&req->rc, &h, sizeof(h));

Is that really OK?

1. `h` is of type xen_9pfs_header and declared as packed, whereas `rc` is of
type p9_fcall not declared as packed.

2. Probably a bit dangerous to assume the layout of xen_9pfs_header being in
sync with the starting layout of p9_fcall without any compile-time
assertion?

> req->rc.offset = 0;
>
> @@ -217,6 +225,7 @@ static void p9_xen_response(struct work_struct *work)
> masked_prod, &masked_cons,
> XEN_9PFS_RING_SIZE(ring));
>
> +recv_error:
> virt_mb();
> cons += h.size;
> ring->intf->in_cons = cons;
>




2022-11-22 00:00:04

by Stefano Stabellini

[permalink] [raw]
Subject: Re: [PATCH 1/2] 9p/xen: check logical size for buffer size

On Mon, 21 Nov 2022, Christian Schoenebeck wrote:
> On Friday, November 18, 2022 2:55:41 PM CET Dominique Martinet wrote:
> > trans_xen did not check the data fits into the buffer before copying
> > from the xen ring, but we probably should.
> > Add a check that just skips the request and return an error to
> > userspace if it did not fit
> >
> > Signed-off-by: Dominique Martinet <[email protected]>
> > ---
> >
> > This comes more or less as a follow up of a fix for trans_fd:
> > https://lkml.kernel.org/r/[email protected]
> > Where msize should be replaced by capacity check, except trans_xen
> > did not actually use to check the size fits at all.
> >
> > While we normally trust the hypervisor (they can probably do whatever
> > they want with our memory), a bug in the 9p server is always possible so
> > sanity checks never hurt, especially now buffers got drastically smaller
> > with a recent patch.
> >
> > My setup for xen is unfortunately long dead so I cannot test this:
> > Stefano, you've tested v9fs xen patches in the past, would you mind
> > verifying this works as well?
> >
> > net/9p/trans_xen.c | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
> > index b15c64128c3e..66ceb3b3ae30 100644
> > --- a/net/9p/trans_xen.c
> > +++ b/net/9p/trans_xen.c
> > @@ -208,6 +208,14 @@ static void p9_xen_response(struct work_struct *work)
> > continue;
> > }
> >
> > + if (h.size > req->rc.capacity) {
> > + dev_warn(&priv->dev->dev,
> > + "requested packet size too big: %d for tag %d with capacity %zd\n",
> > + h.size, h.tag, rreq->rc.capacity);
> > + req->status = REQ_STATUS_ERROR;
> > + goto recv_error;
> > + }
> > +
>
> Looks good (except of s/rreq/req/ mentioned by Stefano already).
>
> > memcpy(&req->rc, &h, sizeof(h));
>
> Is that really OK?
>
> 1. `h` is of type xen_9pfs_header and declared as packed, whereas `rc` is of
> type p9_fcall not declared as packed.
>
> 2. Probably a bit dangerous to assume the layout of xen_9pfs_header being in
> sync with the starting layout of p9_fcall without any compile-time
> assertion?

You are right. It would be better to replace the memcpy with:

req->rc.size = h.size;
req->rc.id = h.id;
req->rc.tag = h.tag;


2022-11-22 01:41:49

by Dominique Martinet

[permalink] [raw]
Subject: Re: [PATCH 1/2] 9p/xen: check logical size for buffer size

Christian Schoenebeck wrote on Mon, Nov 21, 2022 at 05:35:56PM +0100:
> Looks good (except of s/rreq/req/ mentioned by Stefano already).

Thanks for the review (I've taken this as a 'reviewed-by' under the
assumption of that fix, sorry for being a bit aggressive at collecting
these -- I'd rather overcredit work being done than the other way around)

I'll send this and the three other commits in my 9p-next branch to Linus
tomorrow around this time:
https://github.com/martinetd/linux/commits/9p-next


> > memcpy(&req->rc, &h, sizeof(h));
>
> Is that really OK?
>
> 1. `h` is of type xen_9pfs_header and declared as packed, whereas `rc` is of
> type p9_fcall not declared as packed.
>
> 2. Probably a bit dangerous to assume the layout of xen_9pfs_header being in
> sync with the starting layout of p9_fcall without any compile-time
> assertion?

I've done this in a follow up that will be sent to Linus later as per
Stefano's suggestion.

--
Dominique

2022-11-22 11:28:07

by Christian Schoenebeck

[permalink] [raw]
Subject: Re: [PATCH 1/2] 9p/xen: check logical size for buffer size

On Tuesday, November 22, 2022 1:39:39 AM CET Dominique Martinet wrote:
> Christian Schoenebeck wrote on Mon, Nov 21, 2022 at 05:35:56PM +0100:
> > Looks good (except of s/rreq/req/ mentioned by Stefano already).
>
> Thanks for the review (I've taken this as a 'reviewed-by' under the
> assumption of that fix, sorry for being a bit aggressive at collecting
> these -- I'd rather overcredit work being done than the other way around)

Yes, you can add my RB of course!

> I'll send this and the three other commits in my 9p-next branch to Linus
> tomorrow around this time:
> https://github.com/martinetd/linux/commits/9p-next
>
>
> > > memcpy(&req->rc, &h, sizeof(h));
> >
> > Is that really OK?
> >
> > 1. `h` is of type xen_9pfs_header and declared as packed, whereas `rc` is
of
> > type p9_fcall not declared as packed.
> >
> > 2. Probably a bit dangerous to assume the layout of xen_9pfs_header being
in
> > sync with the starting layout of p9_fcall without any compile-time
> > assertion?
>
> I've done this in a follow up that will be sent to Linus later as per
> Stefano's suggestion.

Great, one patch less to send, thanks! :)