From: "Arnd Bergmann" <arnd@arndb.de>
To: "Alexander Graf" <graf@amazon.com>, linux-kernel@vger.kernel.org
Cc: linux-crypto@vger.kernel.org,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Herbert Xu" <herbert@gondor.apana.org.au>,
"Olivia Mackall" <olivia@selenic.com>,
"Petre Eftime" <petre.eftime@gmail.com>,
"Erdem Meydanlli" <meydanli@amazon.nl>,
"Benjamin Herrenschmidt" <benh@kernel.crashing.org>,
"David Woodhouse" <dwmw@amazon.co.uk>,
"Michael S. Tsirkin" <mst@redhat.com>,
"Jason Wang" <jasowang@redhat.com>,
"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
"Christophe JAILLET" <christophe.jaillet@wanadoo.fr>
Subject: Re: [PATCH v6] misc: Add Nitro Secure Module driver
Date: Wed, 11 Oct 2023 13:31:11 +0200 [thread overview]
Message-ID: <fd43fb0d-5d52-423d-bb1d-bc10e64ea3ee@app.fastmail.com> (raw)
In-Reply-To: <20231010213420.93725-1-graf@amazon.com>
On Tue, Oct 10, 2023, at 23:34, Alexander Graf wrote:
> This patch adds a driver for NSM that exposes a /dev/nsm device node which
> user space can issue an ioctl on this device with raw NSM CBOR formatted
> commands to request attestation documents, influence PCR states, read
> entropy and enumerate status of the device. In addition, the driver
> implements a hwrng backend.
I haven't had a chance to actually read the v3 submission in enough
detail, but assuming we're going to go with the simple pass-through
interface here, I've looked for some mostly cosmetic improvements
that you may want to integrate.
> +/* Timeout for NSM virtqueue respose in milliseconds. */
> +#define NSM_DEFAULT_TIMEOUT_MSECS (120000) /* 2 minutes */
> +
> +struct nsm {
> + struct virtio_device *vdev;
> + struct virtqueue *vq;
> + struct mutex lock;
> + wait_queue_head_t wq;
> + bool device_notified;
Instead of a manual wait queue plus a bool, using a
'struct completion' simplifies this a little bit.
> +
> +/* Maximum length input data */
> +struct nsm_data_req {
> + __u32 len;
> + __u8 data[NSM_REQUEST_MAX_SIZE];
> +};
> +/* Maximum length output data */
> +struct nsm_data_resp {
> + __u32 len;
> + __u8 data[NSM_RESPONSE_MAX_SIZE];
> +};
You have endian-conversion for some of the data fields
but not the 'len field here, I guess these should be
__le32 instead of __u32, with the appropriate le32_to_cpu()
and cpu_to_le32() conversion when passing the native
u32 word from userspace.
It does seem odd that you have a little-endian length field
here, but big-endian length fields inside of the cbor
data.
> +#define CBOR_HEADER_SIZE_U8 (CBOR_HEADER_SIZE_SHORT + sizeof(u8))
> +#define CBOR_HEADER_SIZE_U16 (CBOR_HEADER_SIZE_SHORT + sizeof(u16))
> +#define CBOR_HEADER_SIZE_U32 (CBOR_HEADER_SIZE_SHORT + sizeof(u32))
> +#define CBOR_HEADER_SIZE_U64 (CBOR_HEADER_SIZE_SHORT + sizeof(u64))
Similarly, I guess these should be __be16/__be32/__be64?
> + } else if (cbor_short_size == CBOR_LONG_SIZE_U32) {
> + if (cbor_object_size < CBOR_HEADER_SIZE_U32)
> + return -EFAULT;
> + /* 4 bytes */
> + array_len = cbor_object[1] << 24 |
> + cbor_object[2] << 16 |
> + cbor_object[3] << 8 |
> + cbor_object[4];
> + array_offset = CBOR_HEADER_SIZE_U32;
> + } else if (cbor_short_size == CBOR_LONG_SIZE_U64) {
> + if (cbor_object_size < CBOR_HEADER_SIZE_U64)
> + return -EFAULT;
> + /* 8 bytes */
> + array_len = (u64) cbor_object[1] << 56 |
> + (u64) cbor_object[2] << 48 |
> + (u64) cbor_object[3] << 40 |
> + (u64) cbor_object[4] << 32 |
> + (u64) cbor_object[5] << 24 |
> + (u64) cbor_object[6] << 16 |
> + (u64) cbor_object[7] << 8 |
> + (u64) cbor_object[8];
These could use be{!6,32,64}_to_cpup() for clarity.
> +static int nsm_rng_read(struct hwrng *rng, void *data, size_t max,
> bool wait)
> +{
> + struct nsm *nsm = hwrng_to_nsm(rng);
> + struct device *dev = &nsm->vdev->dev;
> + struct nsm_msg *msg;
> + int rc = 0;
> +
> + /* NSM always needs to wait for a response */
> + if (!wait)
> + return 0;
> +
> + msg = kzalloc(sizeof(*msg), GFP_KERNEL);
> + if (!msg)
> + return -ENOMEM;
> +
> + rc = fill_req_get_random(nsm, &msg->req);
> + if (rc != 0)
> + goto out;
> +
> + rc = nsm_sendrecv_msg(nsm, msg);
> + if (rc != 0)
> + goto out;
> +
> + rc = parse_resp_get_random(nsm, &msg->resp, data, max);
> + if (rc < 0)
> + goto out;
It looks like the bulk of this function happens inside of
nsm_sendrecv_msg(), which uses a mutex for serialization.
In this case, I think you can replace the dynamic allocation
during read() with a preallocated buffer in the device that
always gets used here, after you extend the mutex out to the
entire fill_req_get_random()/nsm_sendrecv_msg()/parse_resp_get_random()
block.
> +static long nsm_dev_ioctl(struct file *file, unsigned int cmd,
> + unsigned long arg)
> +{
> + void __user *argp = u64_to_user_ptr((u64)arg);
> + struct nsm *nsm = file_to_nsm(file);
> + struct nsm_msg *msg;
> + struct nsm_raw raw;
> + int r = 0;
> +
> + if (cmd != NSM_IOCTL_RAW)
> + return -EINVAL;
> +
> + if (_IOC_SIZE(cmd) != sizeof(raw))
> + return -EINVAL;
> +
> + /* Allocate message buffers to device */
> + r = -ENOMEM;
> + msg = kzalloc(sizeof(*msg), GFP_KERNEL);
> + if (!msg)
> + goto out;
> +
> + /* Copy user argument struct to kernel argument struct */
> + r = -EFAULT;
> + if (copy_from_user(&raw, argp, _IOC_SIZE(cmd)))
> + goto out;
> +
> + /* Convert kernel argument struct to device request */
> + r = fill_req_raw(nsm, &msg->req, &raw);
> + if (r)
> + goto out;
> +
> + /* Send message to NSM and read reply */
> + r = nsm_sendrecv_msg(nsm, msg);
> + if (r)
> + goto out;
> +
> + /* Parse device response into kernel argument struct */
> + r = parse_resp_raw(nsm, &msg->resp, &raw);
> + if (r)
> + goto out;
And the same is probably true here.
> +static int nsm_dev_file_open(struct inode *node, struct file *file)
> +{
> + return 0;
> +}
> +
> +static int nsm_dev_file_close(struct inode *inode, struct file *file)
> +{
> + return 0;
> +}
These are not needed if they don't do anything.
Arnd
next prev parent reply other threads:[~2023-10-11 11:31 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-10 21:34 [PATCH v6] misc: Add Nitro Secure Module driver Alexander Graf
2023-10-11 11:31 ` Arnd Bergmann [this message]
2023-10-11 12:12 ` Arnd Bergmann
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=fd43fb0d-5d52-423d-bb1d-bc10e64ea3ee@app.fastmail.com \
--to=arnd@arndb.de \
--cc=benh@kernel.crashing.org \
--cc=christophe.jaillet@wanadoo.fr \
--cc=dwmw@amazon.co.uk \
--cc=graf@amazon.com \
--cc=gregkh@linuxfoundation.org \
--cc=herbert@gondor.apana.org.au \
--cc=jasowang@redhat.com \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=meydanli@amazon.nl \
--cc=mst@redhat.com \
--cc=olivia@selenic.com \
--cc=petre.eftime@gmail.com \
--cc=xuanzhuo@linux.alibaba.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox