From 5bacecc3c56131c31f18b23d366f2184328fd9cf Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 16 Feb 2023 22:44:58 +0200 Subject: drm/displayid: add displayid_get_header() and check bounds better Add a helper to get a pointer to struct displayid_header. To be pedantic, add buffer overflow checks to not touch the base if that itself would overflow. Cc: Iaroslav Boliukin Cc: Dmitry Osipenko Signed-off-by: Jani Nikula Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/4a03b3a5132642d3cdb6d4c2641422955a917292.1676580180.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_displayid.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/drm_displayid.c') diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 38ea8203df45..7d03159dc146 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -7,13 +7,28 @@ #include #include +static const struct displayid_header * +displayid_get_header(const u8 *displayid, int length, int index) +{ + const struct displayid_header *base; + + if (sizeof(*base) > length - index) + return ERR_PTR(-EINVAL); + + base = (const struct displayid_header *)&displayid[index]; + + return base; +} + static int validate_displayid(const u8 *displayid, int length, int idx) { int i, dispid_length; u8 csum = 0; const struct displayid_header *base; - base = (const struct displayid_header *)&displayid[idx]; + base = displayid_get_header(displayid, length, idx); + if (IS_ERR(base)) + return PTR_ERR(base); DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", base->rev, base->bytes, base->prod_id, base->ext_count); -- cgit From 5631f6a0436ac30eecfb2e6fdcd0a517f90add8a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 16 Feb 2023 22:44:59 +0200 Subject: drm/displayid: return struct displayid_header from validate_displayid() Avoid figuring out the header pointer multiple times. Cc: Iaroslav Boliukin Cc: Dmitry Osipenko Signed-off-by: Jani Nikula Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/e840c744d165608a41db5a5e2bd4b0205783c697.1676580180.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_displayid.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/drm_displayid.c') diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 7d03159dc146..0de9b5530393 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -20,7 +20,8 @@ displayid_get_header(const u8 *displayid, int length, int index) return base; } -static int validate_displayid(const u8 *displayid, int length, int idx) +static const struct displayid_header * +validate_displayid(const u8 *displayid, int length, int idx) { int i, dispid_length; u8 csum = 0; @@ -28,7 +29,7 @@ static int validate_displayid(const u8 *displayid, int length, int idx) base = displayid_get_header(displayid, length, idx); if (IS_ERR(base)) - return PTR_ERR(base); + return base; DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", base->rev, base->bytes, base->prod_id, base->ext_count); @@ -36,16 +37,16 @@ static int validate_displayid(const u8 *displayid, int length, int idx) /* +1 for DispID checksum */ dispid_length = sizeof(*base) + base->bytes + 1; if (dispid_length > length - idx) - return -EINVAL; + return ERR_PTR(-EINVAL); for (i = 0; i < dispid_length; i++) csum += displayid[idx + i]; if (csum) { DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum); - return -EINVAL; + return ERR_PTR(-EINVAL); } - return 0; + return base; } static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid, @@ -54,7 +55,6 @@ static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid, { const u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index); const struct displayid_header *base; - int ret; if (!displayid) return NULL; @@ -63,11 +63,10 @@ static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid, *length = EDID_LENGTH - 1; *idx = 1; - ret = validate_displayid(displayid, *length, *idx); - if (ret) + base = validate_displayid(displayid, *length, *idx); + if (IS_ERR(base)) return NULL; - base = (const struct displayid_header *)&displayid[*idx]; *length = *idx + sizeof(*base) + base->bytes; return displayid; -- cgit From b568e6bb49d49ef05fa3aa4bb294ae960e1d778a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 16 Feb 2023 22:45:00 +0200 Subject: drm/displayid: provide access to DisplayID version and primary use case The DisplayID structure version and primary use case are stored in the DisplayID Base Section. We should be checking them in a number of places when parsing the DisplayID blocks. Currently, we completely ignore the primary use case, and just look at the block tags without cross-checking against structure version. Store the version and primary use case in the DisplayID iterator, and provide accessors to them. In general, the information is needed when iterating the blocks, and this is a convenient place to both store and retrieve the information during parsing. Promote using accessors rather than users poking at the iterator directly. Cc: Iaroslav Boliukin Cc: Dmitry Osipenko Signed-off-by: Jani Nikula Tested-by: Dmitry Osipenko Reviewed-by: Dmitry Osipenko Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/ad8a35c109f97ffe115e6b18e4a132b592f11089.1676580180.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_displayid.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/gpu/drm/drm_displayid.c') diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 0de9b5530393..9edc111be7ee 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -123,6 +123,9 @@ __displayid_iter_next(struct displayid_iter *iter) } for (;;) { + /* The first section we encounter is the base section */ + bool base_section = !iter->section; + iter->section = drm_find_displayid_extension(iter->drm_edid, &iter->length, &iter->idx, @@ -132,6 +135,18 @@ __displayid_iter_next(struct displayid_iter *iter) return NULL; } + /* Save the structure version and primary use case. */ + if (base_section) { + const struct displayid_header *base; + + base = displayid_get_header(iter->section, iter->length, + iter->idx); + if (!IS_ERR(base)) { + iter->version = base->rev; + iter->primary_use = base->prod_id; + } + } + iter->idx += sizeof(struct displayid_header); block = displayid_iter_block(iter); @@ -144,3 +159,18 @@ void displayid_iter_end(struct displayid_iter *iter) { memset(iter, 0, sizeof(*iter)); } + +/* DisplayID Structure Version/Revision from the Base Section. */ +u8 displayid_version(const struct displayid_iter *iter) +{ + return iter->version; +} + +/* + * DisplayID Primary Use Case (2.0+) or Product Type Identifier (1.0-1.3) from + * the Base Section. + */ +u8 displayid_primary_use(const struct displayid_iter *iter) +{ + return iter->primary_use; +} -- cgit