All of lore.kernel.org
 help / color / mirror / Atom feed
From: Meng Xu <meng.xu@gatech.edu>
To: dan.j.williams@intel.com, linux-nvdimm@lists.01.org,
	linux-kernel@vger.kernel.org
Cc: taesoo@gatech.edu, meng.xu@gatech.edu,
	Meng Xu <mengxu.gatech@gmail.com>,
	sanidhya@gatech.edu
Subject: [PATCH] nvdimm: fix potential double-fetch bug
Date: Wed, 23 Aug 2017 17:07:46 -0400	[thread overview]
Message-ID: <1503522466-35486-1-git-send-email-meng.xu@gatech.edu> (raw)

From: Meng Xu <mengxu.gatech@gmail.com>

While examining the kernel source code, I found a dangerous operation that
could turn into a double-fetch situation (a race condition bug) where
the same userspace memory region are fetched twice into kernel with sanity
checks after the first fetch while missing checks after the second fetch.

In the case of _IOC_NR(ioctl_cmd) == ND_CMD_CALL:

1. The first fetch happens in line 935 copy_from_user(&pkg, p, sizeof(pkg)

2. subsequently `pkg.nd_reserved2` is asserted to be all zeroes
(line 984 to 986).

3. The second fetch happens in line 1022 copy_from_user(buf, p, buf_len)

4. Given that `p` can be fully controlled in userspace, an attacker can
race condition to override the header part of `p`, say,
`((struct nd_cmd_pkg *)p)->nd_reserved2` to arbitrary value
(say nine 0xFFFFFFFF for `nd_reserved2`) after the first fetch but before the
second fetch. The changed value will be copied to `buf`.

5. There is no checks on the second fetches until the use of it in
line 1034: nd_cmd_clear_to_send(nvdimm_bus, nvdimm, cmd, buf) and
line 1038: nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, &cmd_rc)
which means that the assumed relation, `p->nd_reserved2` are all zeroes might
not hold after the second fetch. And once the control goes to these functions
we lose the context to assert the assumed relation.

6. Based on my manual analysis, `p->nd_reserved2` is not used in function
`nd_cmd_clear_to_send` and potential implementations of `nd_desc->ndctl`
so there is no working exploit against it right now. However, this could
easily turns to an exploitable one if careless developers start to use
`p->nd_reserved2` later and assume that they are all zeroes.

Proposed patch:

The patch explicitly overrides `buf->nd_reserved2` after the second fetch with
the value `pkg.nd_reserved2` from the first fetch. In this way, it is assured
that the relation, `buf->nd_reserved2` are all zeroes, holds after the second
fetch.

Signed-off-by: Meng Xu <mengxu.gatech@gmail.com>
---
 drivers/nvdimm/bus.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 937fafa..20c4d0f 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -1024,6 +1024,12 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
 		goto out;
 	}
 
+	if (cmd == ND_CMD_CALL) {
+		struct nd_cmd_pkg *hdr = (struct nd_cmd_pkg *)buf;
+		memcpy(hdr->nd_reserved2, pkg.nd_reserved2,
+				sizeof(pkg.nd_reserved2));
+	}
+
 	nvdimm_bus_lock(&nvdimm_bus->dev);
 	rc = nd_cmd_clear_to_send(nvdimm_bus, nvdimm, func, buf);
 	if (rc)
-- 
2.7.4

_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

WARNING: multiple messages have this Message-ID (diff)
From: Meng Xu <meng.xu@gatech.edu>
To: dan.j.williams@intel.com, linux-nvdimm@lists.01.org,
	linux-kernel@vger.kernel.org
Cc: meng.xu@gatech.edu, sanidhya@gatech.edu, taesoo@gatech.edu,
	Meng Xu <mengxu.gatech@gmail.com>
Subject: [PATCH] nvdimm: fix potential double-fetch bug
Date: Wed, 23 Aug 2017 17:07:46 -0400	[thread overview]
Message-ID: <1503522466-35486-1-git-send-email-meng.xu@gatech.edu> (raw)

From: Meng Xu <mengxu.gatech@gmail.com>

While examining the kernel source code, I found a dangerous operation that
could turn into a double-fetch situation (a race condition bug) where
the same userspace memory region are fetched twice into kernel with sanity
checks after the first fetch while missing checks after the second fetch.

In the case of _IOC_NR(ioctl_cmd) == ND_CMD_CALL:

1. The first fetch happens in line 935 copy_from_user(&pkg, p, sizeof(pkg)

2. subsequently `pkg.nd_reserved2` is asserted to be all zeroes
(line 984 to 986).

3. The second fetch happens in line 1022 copy_from_user(buf, p, buf_len)

4. Given that `p` can be fully controlled in userspace, an attacker can
race condition to override the header part of `p`, say,
`((struct nd_cmd_pkg *)p)->nd_reserved2` to arbitrary value
(say nine 0xFFFFFFFF for `nd_reserved2`) after the first fetch but before the
second fetch. The changed value will be copied to `buf`.

5. There is no checks on the second fetches until the use of it in
line 1034: nd_cmd_clear_to_send(nvdimm_bus, nvdimm, cmd, buf) and
line 1038: nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, &cmd_rc)
which means that the assumed relation, `p->nd_reserved2` are all zeroes might
not hold after the second fetch. And once the control goes to these functions
we lose the context to assert the assumed relation.

6. Based on my manual analysis, `p->nd_reserved2` is not used in function
`nd_cmd_clear_to_send` and potential implementations of `nd_desc->ndctl`
so there is no working exploit against it right now. However, this could
easily turns to an exploitable one if careless developers start to use
`p->nd_reserved2` later and assume that they are all zeroes.

Proposed patch:

The patch explicitly overrides `buf->nd_reserved2` after the second fetch with
the value `pkg.nd_reserved2` from the first fetch. In this way, it is assured
that the relation, `buf->nd_reserved2` are all zeroes, holds after the second
fetch.

Signed-off-by: Meng Xu <mengxu.gatech@gmail.com>
---
 drivers/nvdimm/bus.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 937fafa..20c4d0f 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -1024,6 +1024,12 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
 		goto out;
 	}
 
+	if (cmd == ND_CMD_CALL) {
+		struct nd_cmd_pkg *hdr = (struct nd_cmd_pkg *)buf;
+		memcpy(hdr->nd_reserved2, pkg.nd_reserved2,
+				sizeof(pkg.nd_reserved2));
+	}
+
 	nvdimm_bus_lock(&nvdimm_bus->dev);
 	rc = nd_cmd_clear_to_send(nvdimm_bus, nvdimm, func, buf);
 	if (rc)
-- 
2.7.4

             reply	other threads:[~2017-08-23 21:05 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-23 21:07 Meng Xu [this message]
2017-08-23 21:07 ` [PATCH] nvdimm: fix potential double-fetch bug Meng Xu
2017-08-31 22:42 ` Dan Williams
2017-08-31 22:42   ` Dan Williams
2017-09-04 15:39   ` Meng Xu
2017-09-04 15:39     ` Meng Xu
2017-09-12 22:03   ` Jerry Hoemann
2017-09-12 22:03     ` Jerry Hoemann
2017-09-12 22:49     ` Meng Xu
2017-09-12 22:49       ` Meng Xu
2017-09-20  2:35       ` Meng Xu
2017-09-20  2:35         ` Meng Xu

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=1503522466-35486-1-git-send-email-meng.xu@gatech.edu \
    --to=meng.xu@gatech.edu \
    --cc=dan.j.williams@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nvdimm@lists.01.org \
    --cc=mengxu.gatech@gmail.com \
    --cc=sanidhya@gatech.edu \
    --cc=taesoo@gatech.edu \
    /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.