From: Greg Kurz <groug@kaod.org>
To: Li Qiang <liq3ea@gmail.com>
Cc: qemu-devel@nongnu.org, Li Qiang <liqiang6-s@360.cn>
Subject: Re: [Qemu-devel] [PATCH] 9pfs: fix integer overflow issue in xattr read/write
Date: Wed, 12 Oct 2016 15:33:05 +0200 [thread overview]
Message-ID: <20161012153305.216b972e@bahia> (raw)
In-Reply-To: <57fdbc36.486b240a.941a3.ac8a@mx.google.com>
Hi Li,
I agree with the idea behind this patch but I have the impression that some
more work is needed. See below.
On Tue, 11 Oct 2016 21:29:19 -0700
Li Qiang <liq3ea@gmail.com> wrote:
> From: Li Qiang <liqiang6-s@360.cn>
>
> In 9pfs xattr read/write function, it mix to use unsigned/signed
> ,32/64 bits integers. This will causes oob read/write issues. This
> patch fix this.
>
The root cause for OOB to happen is that the off argument is an unint64_t
coming from the guest: if it exceeds xattr_len more than INT_MAX+2, then
write_count will be equal to INT_MAX and pass the write_count < 0 check.
The use of proper types is needed to detect that.
What about this:
The v9fs_xattr_read() and v9fs_xattr_write() are passed a guest originated
offset: they must ensure this offset does not go beyond the size of the
extended attribute that was set in v9fs_xattrcreate(). Unfortunately, the
current code implement these checks with unsafe calculations on 32 and 64
bit values, which may allow a malicious guest to cause OOB access anyway.
Let's fix this by comparing the offset and the xattr size, which are both
uint64_t, before trying to compute the effective number of bytes to read
or write.
> Signed-off-by: Li Qiang <liqiang6-s@360.cn>
> ---
> hw/9pfs/9p.c | 29 +++++++++++++----------------
> 1 file changed, 13 insertions(+), 16 deletions(-)
>
> diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
> index e4040dc..8b50bfb 100644
> --- a/hw/9pfs/9p.c
> +++ b/hw/9pfs/9p.c
> @@ -1642,21 +1642,21 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
> {
> ssize_t err;
> size_t offset = 7;
> - int read_count;
> - int64_t xattr_len;
> + uint64_t read_count;
> + uint64_t xattr_len;
I don't think xattr_len is needed. See below.
> V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
> VirtQueueElement *elem = v->elems[pdu->idx];
>
> xattr_len = fidp->fs.xattr.len;
typedef struct V9fsXattr
{
int64_t copied_len;
int64_t len;
I believe len should be uint64_t since it comes from the size argument to
setxattr() in the guest:
int setxattr(const char *path, const char *name,
const void *value, size_t size, int flags);
and it is treated as u64 in the linux kernel client code:
int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
u64 attr_size, int flags)
I guess copied_len should also be turned to uint64_t as well since its main
use is to account for copied bytes. And introduce a xattrwalk_fid bool
instead of setting copied_len to -1.
I suggest you fix the types in some prelimary patches and then build
this patch on top.
> + if (xattr_len < off) {
> + read_count = 0;
> + goto over_read_count;
goto should only be used when doing rollback on error paths, which is not
the case here. Please use a regular if...else construct instead.
> + }
> read_count = xattr_len - off;
> if (read_count > max_count) {
> read_count = max_count;
> - } else if (read_count < 0) {
> - /*
> - * read beyond XATTR value
> - */
> - read_count = 0;
> }
> +over_read_count:
> err = pdu_marshal(pdu, offset, "d", read_count);
> if (err < 0) {
> return err;
> @@ -1982,22 +1982,19 @@ static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
> {
> int i, to_copy;
> ssize_t err = 0;
> - int write_count;
> - int64_t xattr_len;
> + uint64_t write_count;
> + uint64_t xattr_len;
Same remark: xattr_len not needed.
> size_t offset = 7;
>
>
> xattr_len = fidp->fs.xattr.len;
> + if (xattr_len < off) {
> + err = -ENOSPC;
> + goto out;
> + }
> write_count = xattr_len - off;
> if (write_count > count) {
> write_count = count;
> - } else if (write_count < 0) {
> - /*
> - * write beyond XATTR value len specified in
> - * xattrcreate
> - */
> - err = -ENOSPC;
> - goto out;
> }
> err = pdu_marshal(pdu, offset, "d", write_count);
> if (err < 0) {
Cheers.
--
Greg
prev parent reply other threads:[~2016-10-12 13:33 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-12 4:29 [Qemu-devel] [PATCH] 9pfs: fix integer overflow issue in xattr read/write Li Qiang
2016-10-12 13:33 ` Greg Kurz [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20161012153305.216b972e@bahia \
--to=groug@kaod.org \
--cc=liq3ea@gmail.com \
--cc=liqiang6-s@360.cn \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.