nvme: fix compat address handling in several ioctls
authorNick Bowler <nbowler@draconx.ca>
Sat, 28 Mar 2020 05:09:09 +0000 (01:09 -0400)
committerChristoph Hellwig <hch@lst.de>
Tue, 31 Mar 2020 14:19:11 +0000 (16:19 +0200)
commitc95b708d5fa65b4e51f088ee077d127fd5a57b70
tree3b02b9ea88c718050d563630d85dee8f9e5c1bff
parent458ef2a25e0cbdc216012aa2b9cf549d64133b08
nvme: fix compat address handling in several ioctls

On a 32-bit kernel, the upper bits of userspace addresses passed via
various ioctls are silently ignored by the nvme driver.

However on a 64-bit kernel running a compat task, these upper bits are
not ignored and are in fact required to be zero for the ioctls to work.

Unfortunately, this difference matters.  32-bit smartctl submits the
NVME_IOCTL_ADMIN_CMD ioctl with garbage in these upper bits because it
seems the pointer value it puts into the nvme_passthru_cmd structure is
sign extended.  This works fine on 32-bit kernels but fails on a 64-bit
one because (at least on my setup) the addresses smartctl uses are
consistently above 2G.  For example:

  # smartctl -x /dev/nvme0n1
  smartctl 7.1 2019-12-30 r5022 [x86_64-linux-5.5.11] (local build)
  Copyright (C) 2002-19, Bruce Allen, Christian Franke, www.smartmontools.org

  Read NVMe Identify Controller failed: NVME_IOCTL_ADMIN_CMD: Bad address

Since changing 32-bit kernels to actually check all of the submitted
address bits now would break existing userspace, this patch fixes the
compat problem by explicitly zeroing the upper bits in the compat case.
This enables 32-bit smartctl to work on a 64-bit kernel.

Signed-off-by: Nick Bowler <nbowler@draconx.ca>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/host/core.c