HDMI specification defines the SPD InfoFrame Vendor Name and Product
Description as fixed-size fields, 8 and 16 bytes respectively, padded
with zeros and left without any trailing NUL when a name spans the whole
field.

Give those lengths a name and mark the fields as non-strings, so that
the copies can be handed over to strtomem_pad(), which implements
precisely the required semantics.  This also bounds the reads from the
source strings, whereas the open-coded strlen() could run past the end
of the buffer in the hdmi_spd_infoframe_unpack() path, where the names
come straight from the wire and are not NUL-terminated.

While at it, replace the related magic numbers in the pack and unpack
helpers with the new defines.

Signed-off-by: Cristian Ciocaltea <[email protected]>
---
 drivers/video/hdmi.c | 23 +++++++++++++----------
 include/linux/hdmi.h |  7 +++++--
 2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 45b42f14a750..e729c26d61c4 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -217,23 +217,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
  * @vendor: vendor string
  * @product: product string
  *
+ * Both strings are copied into the fixed-size infoframe fields,
+ * truncated if too long and padded with zeros otherwise.
+ *
  * Returns 0 on success or a negative error code on failure.
  */
 int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
                            const char *vendor, const char *product)
 {
-       size_t len;
-
        memset(frame, 0, sizeof(*frame));
 
        frame->type = HDMI_INFOFRAME_TYPE_SPD;
        frame->version = 1;
        frame->length = HDMI_SPD_INFOFRAME_SIZE;
 
-       len = strlen(vendor);
-       memcpy(frame->vendor, vendor, min(len, sizeof(frame->vendor)));
-       len = strlen(product);
-       memcpy(frame->product, product, min(len, sizeof(frame->product)));
+       strtomem_pad(frame->vendor, vendor, 0);
+       strtomem_pad(frame->product, product, 0);
 
        return 0;
 }
@@ -305,9 +304,11 @@ ssize_t hdmi_spd_infoframe_pack_only(const struct 
hdmi_spd_infoframe *frame,
        ptr += HDMI_INFOFRAME_HEADER_SIZE;
 
        memcpy(ptr, frame->vendor, sizeof(frame->vendor));
-       memcpy(ptr + 8, frame->product, sizeof(frame->product));
+       memcpy(ptr + HDMI_SPD_INFOFRAME_VENDOR_LEN, frame->product,
+              sizeof(frame->product));
 
-       ptr[24] = frame->sdi;
+       ptr[HDMI_SPD_INFOFRAME_VENDOR_LEN + HDMI_SPD_INFOFRAME_PRODUCT_LEN] =
+               frame->sdi;
 
        hdmi_infoframe_set_checksum(buffer, length);
 
@@ -1643,11 +1644,13 @@ static int hdmi_spd_infoframe_unpack(struct 
hdmi_spd_infoframe *frame,
 
        ptr += HDMI_INFOFRAME_HEADER_SIZE;
 
-       ret = hdmi_spd_infoframe_init(frame, ptr, ptr + 8);
+       ret = hdmi_spd_infoframe_init(frame, ptr,
+                                     ptr + HDMI_SPD_INFOFRAME_VENDOR_LEN);
        if (ret)
                return ret;
 
-       frame->sdi = ptr[24];
+       frame->sdi = ptr[HDMI_SPD_INFOFRAME_VENDOR_LEN +
+                        HDMI_SPD_INFOFRAME_PRODUCT_LEN];
 
        return 0;
 }
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index b80a5ee63bb2..d73ad7b3fa94 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -267,12 +267,15 @@ enum hdmi_spd_sdi {
        HDMI_SPD_SDI_PMP,
 };
 
+#define HDMI_SPD_INFOFRAME_VENDOR_LEN   8
+#define HDMI_SPD_INFOFRAME_PRODUCT_LEN 16
+
 struct hdmi_spd_infoframe {
        enum hdmi_infoframe_type type;
        unsigned char version;
        unsigned char length;
-       char vendor[8];
-       char product[16];
+       unsigned char vendor[HDMI_SPD_INFOFRAME_VENDOR_LEN] __nonstring;
+       unsigned char product[HDMI_SPD_INFOFRAME_PRODUCT_LEN] __nonstring;
        enum hdmi_spd_sdi sdi;
 };
 

-- 
2.55.0

Reply via email to