lkml.org 
[lkml]   [2019]   [Mar]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.14 051/123] efi: cper: Fix possible out-of-bounds access
    Date
    From: Ross Lagerwall <ross.lagerwall@citrix.com>

    [ Upstream commit 45b14a4ffcc1e0b5caa246638f942cbe7eaea7ad ]

    When checking a generic status block, we iterate over all the generic
    data blocks. The loop condition only checks that the start of the
    generic data block is valid (within estatus->data_length) but not the
    whole block. Because the size of data blocks (excluding error data) may
    vary depending on the revision and the revision is contained within the
    data block, ensure that enough of the current data block is valid before
    dereferencing any members otherwise an out-of-bounds access may occur if
    estatus->data_length is invalid.

    This relies on the fact that struct acpi_hest_generic_data_v300 is a
    superset of the earlier version. Also rework the other checks to avoid
    potential underflow.

    Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
    Acked-by: Borislav Petkov <bp@suse.de>
    Tested-by: Tyler Baicar <baicar.tyler@gmail.com>
    Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/firmware/efi/cper.c | 13 +++++++++----
    1 file changed, 9 insertions(+), 4 deletions(-)

    diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
    index d2fcafcea07e..ce23d5402bd6 100644
    --- a/drivers/firmware/efi/cper.c
    +++ b/drivers/firmware/efi/cper.c
    @@ -641,19 +641,24 @@ EXPORT_SYMBOL_GPL(cper_estatus_check_header);
    int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
    {
    struct acpi_hest_generic_data *gdata;
    - unsigned int data_len, gedata_len;
    + unsigned int data_len, record_size;
    int rc;

    rc = cper_estatus_check_header(estatus);
    if (rc)
    return rc;
    +
    data_len = estatus->data_length;

    apei_estatus_for_each_section(estatus, gdata) {
    - gedata_len = acpi_hest_get_error_length(gdata);
    - if (gedata_len > data_len - acpi_hest_get_size(gdata))
    + if (sizeof(struct acpi_hest_generic_data) > data_len)
    + return -EINVAL;
    +
    + record_size = acpi_hest_get_record_size(gdata);
    + if (record_size > data_len)
    return -EINVAL;
    - data_len -= acpi_hest_get_record_size(gdata);
    +
    + data_len -= record_size;
    }
    if (data_len)
    return -EINVAL;
    --
    2.19.1
    \
     
     \ /
      Last update: 2019-03-27 19:51    [W:4.133 / U:0.092 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site