Received: by 2002:a05:6a10:2785:0:0:0:0 with SMTP id ia5csp432875pxb; Fri, 8 Jan 2021 08:35:31 -0800 (PST) X-Google-Smtp-Source: ABdhPJxUxpPRZK6mXFNJ5PDF1GybQdhtr39+gPDKH+zFn4rk/EB1U6710f++HNzdklLqoo2xQg8F X-Received: by 2002:aa7:d784:: with SMTP id s4mr5743094edq.215.1610123730966; Fri, 08 Jan 2021 08:35:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1610123730; cv=none; d=google.com; s=arc-20160816; b=YOBZLxlt7IXBjAASojotUFWPQeGcpKiGwuzQS1dJQ00GUzOlRX9etBfUzCp3du59TC mF6/5cFpLfHd7oi98JgrblioLfBsE8+uF42xL9anCf4azkeEyRApmq/UZhup6n/8x4un ZrarmShPUkn3Ebz/IBsItX43REqSV6zYWXRuqycC4iT+aJG1Mc/s1rTIeTtN5u88ZlUZ 7H7C11xiR032b+9qqGFANxfAd989akagArFy4kBtlvbnyXZ7CzeswshkDAnv8heUYi+b tSPIQOXHA+ujcGn8uQT2OhTfMo5Wnvui2CmlR7OtEzOxUavXyRBle3B71zTCOQmeLvzA 4cEA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=hm2iTN4Ch7eQ7rVA/cjFV3xEn4oZYCZuK1hpWr0tCPQ=; b=W+Q7ZY+awuxAKwla4z8qPIAp3UNM403XDmVK2HwG7r30srURuA9BwTwKouu11p+b9j 6MxOK0QnU9c+b/G1iFz0i8M8Rz2YcpRIjErc4g5ZC9JETZ4tLxSpJVE85ZJWfb8Xn2tX fvYlfKYeMq9d+SqfhoW2Y1HjM6qMPPNyLtI/2jWN2iQEy+gyLT22iIdD5dRGNUY4Pfe3 wLQ3pfZSzeeiE5xxQ87q7a06mEuDubx0CrHRtnW57cpTYHKRd1VjeeB77/FGUM+oCYWd OkDIGkm/wior2y5+en7zH4/myYPZoSMNAqrpPsc7c9n7vFJ+cFnKF0LPQOtIQ4LwrxfH t1WA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=FAN5kq6l; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id h7si3925010edf.503.2021.01.08.08.35.06; Fri, 08 Jan 2021 08:35:30 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=FAN5kq6l; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728243AbhAHQct (ORCPT + 99 others); Fri, 8 Jan 2021 11:32:49 -0500 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:30598 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728130AbhAHQcs (ORCPT ); Fri, 8 Jan 2021 11:32:48 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1610123481; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=hm2iTN4Ch7eQ7rVA/cjFV3xEn4oZYCZuK1hpWr0tCPQ=; b=FAN5kq6lJydHWgaAwdL9vxIjUzoszVDq8wUxa83BfLe7pE4IEZe06ybipM++4ulkbv31CO jCxM8P09kCXmoGGJKgMQHiMBJtm9ASWhbv4LPi72O2Ng9actETxkaPQok7Z6oJfSNkc56z DNNQ1C6zWV57NQJeEo7hhF4idLmCtjw= Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-99-R3gmTh3qPu-k_--8lJBa5g-1; Fri, 08 Jan 2021 11:31:19 -0500 X-MC-Unique: R3gmTh3qPu-k_--8lJBa5g-1 Received: by mail-qk1-f197.google.com with SMTP id l138so9695493qke.4 for ; Fri, 08 Jan 2021 08:31:19 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=hm2iTN4Ch7eQ7rVA/cjFV3xEn4oZYCZuK1hpWr0tCPQ=; b=ND6kwCSKEzape46cf3eYtNJZvKmJaQKV8EwJEuLmQSg1p8oeu/7KKT99DRwwgkwbrC lZNiHv3FwZ5W40cCNCqiWsaZs/VNxf+Gc76QJJTfJzghM00n77GOaTZWcvutFLPRloW0 VNrqxj7GW8nrgT8DKMyG3qMuX6T8f998WQQsCodwQON1kPqWVcJ955B0lxn3LF3ITkNT jRR2tRHhBuwFJeHB6SdDBbTWbyuve4y832LNMM+oXecEU3yyTk9TGIgY5ApnjCvvKp2e QlCYyiUgPUH7Da0MQ0ahilQrHOaHRoYaY+hvLuaR9LYlmXDxFcJ5Ckj2aQlCTCMx7hxU 1HlA== X-Gm-Message-State: AOAM530RTS2iN8hpUqnLdZSn3coplXRr+frMt2YhGvhZWzjKjbg0pwbg +uEK8kz9h9pXsFhgLRc472rOiFf6PSxbtzKS6APnLDHO4VyUU4cEBLFOTFKy5Gj0NeHKXL3hP5F zvrTL1IhqjB782xXVgF6Pj9Jr X-Received: by 2002:ac8:51d8:: with SMTP id d24mr4135461qtn.73.1610123478675; Fri, 08 Jan 2021 08:31:18 -0800 (PST) X-Received: by 2002:ac8:51d8:: with SMTP id d24mr4135443qtn.73.1610123478342; Fri, 08 Jan 2021 08:31:18 -0800 (PST) Received: from dev.jcline.org ([2605:a601:a63a:4d01:c440:5c61:43ba:350c]) by smtp.gmail.com with ESMTPSA id 14sm4989879qkv.25.2021.01.08.08.31.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 08:31:17 -0800 (PST) From: Jeremy Cline To: Felix Kuehling , Alex Deucher , =?UTF-8?q?Christian=20K=C3=B6nig?= Cc: David Airlie , Daniel Vetter , Kent Russell , amd-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Jeremy Cline Subject: [PATCH] drm/amdkfd: Fix out-of-bounds read in kdf_create_vcrat_image_cpu() Date: Fri, 8 Jan 2021 11:31:04 -0500 Message-Id: <20210108163104.411442-1-jcline@redhat.com> X-Mailer: git-send-email 2.28.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org KASAN reported a slab-out-of-bounds read of size 1 in kdf_create_vcrat_image_cpu(). This occurs when, for example, when on an x86_64 with a single NUMA node because kfd_fill_iolink_info_for_cpu() is a no-op, but afterwards the sub_type_hdr->length, which is out-of-bounds, is read and multiplied by entries. Fortunately, entries is 0 in this case so the overall crat_table->length is still correct. This refactors the helper functions to accept the crat_table directly and calculate the table entry pointer based on the current table length. This allows us to avoid an out-of-bounds read and hopefully makes the pointer arithmetic clearer. It should have no functional change beyond removing the out-of-bounds read. Fixes: b7b6c38529c9 ("drm/amdkfd: Calculate CPU VCRAT size dynamically (v2)") Signed-off-by: Jeremy Cline --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 86 +++++++++++++-------------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 8cac497c2c45..e50db2c0f4ee 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -829,21 +829,24 @@ int kfd_create_crat_image_acpi(void **crat_image, size_t *size) /* kfd_fill_cu_for_cpu - Fill in Compute info for the given CPU NUMA node * * @numa_node_id: CPU NUMA node id - * @avail_size: Available size in the memory - * @sub_type_hdr: Memory into which compute info will be filled in + * @avail_size: Available space in bytes at the end of the @crat_table. + * @crat_table: The CRAT table to append the Compute info to; + * on success the table length and total_entries count is updated. * * Return 0 if successful else return -ve value */ static int kfd_fill_cu_for_cpu(int numa_node_id, int *avail_size, - int proximity_domain, - struct crat_subtype_computeunit *sub_type_hdr) + struct crat_header *crat_table) { const struct cpumask *cpumask; + struct crat_subtype_computeunit *sub_type_hdr; *avail_size -= sizeof(struct crat_subtype_computeunit); if (*avail_size < 0) return -ENOMEM; + sub_type_hdr = (typeof(sub_type_hdr))((char *)crat_table + + crat_table->length); memset(sub_type_hdr, 0, sizeof(struct crat_subtype_computeunit)); /* Fill in subtype header data */ @@ -855,36 +858,42 @@ static int kfd_fill_cu_for_cpu(int numa_node_id, int *avail_size, /* Fill in CU data */ sub_type_hdr->flags |= CRAT_CU_FLAGS_CPU_PRESENT; - sub_type_hdr->proximity_domain = proximity_domain; + sub_type_hdr->proximity_domain = crat_table->num_domains; sub_type_hdr->processor_id_low = kfd_numa_node_to_apic_id(numa_node_id); if (sub_type_hdr->processor_id_low == -1) return -EINVAL; sub_type_hdr->num_cpu_cores = cpumask_weight(cpumask); + crat_table->length += sub_type_hdr->length; + crat_table->total_entries++; + return 0; } /* kfd_fill_mem_info_for_cpu - Fill in Memory info for the given CPU NUMA node * * @numa_node_id: CPU NUMA node id - * @avail_size: Available size in the memory - * @sub_type_hdr: Memory into which compute info will be filled in + * @avail_size: Available space in bytes at the end of the @crat_table. + * @crat_table: The CRAT table to append the Memory info to; + * on success the table length and total_entries count is updated. * * Return 0 if successful else return -ve value */ static int kfd_fill_mem_info_for_cpu(int numa_node_id, int *avail_size, - int proximity_domain, - struct crat_subtype_memory *sub_type_hdr) + struct crat_header *crat_table) { uint64_t mem_in_bytes = 0; pg_data_t *pgdat; int zone_type; + struct crat_subtype_memory *sub_type_hdr; *avail_size -= sizeof(struct crat_subtype_memory); if (*avail_size < 0) return -ENOMEM; + sub_type_hdr = (typeof(sub_type_hdr))((char *)crat_table + + crat_table->length); memset(sub_type_hdr, 0, sizeof(struct crat_subtype_memory)); /* Fill in subtype header data */ @@ -905,27 +914,37 @@ static int kfd_fill_mem_info_for_cpu(int numa_node_id, int *avail_size, sub_type_hdr->length_low = lower_32_bits(mem_in_bytes); sub_type_hdr->length_high = upper_32_bits(mem_in_bytes); - sub_type_hdr->proximity_domain = proximity_domain; + sub_type_hdr->proximity_domain = crat_table->num_domains; + + crat_table->length += sub_type_hdr->length; + crat_table->total_entries++; return 0; } #ifdef CONFIG_X86_64 +/* kfd_fill_iolink_info_for_cpu() - Add IO link info to a Virtual CRAT + * + * @numa_node_id: The NUMA node ID for the CPU; as from for_each_online_node() + * @avail_size: Available space in bytes at the end of the @crat_table. + * @crat_table: The CRAT table to append the IO link info to; on success the + * table length and total_entries count is updated. + * + * Return: 0 if successful else return -ve value + */ static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size, - uint32_t *num_entries, - struct crat_subtype_iolink *sub_type_hdr) + struct crat_header *crat_table) { int nid; struct cpuinfo_x86 *c = &cpu_data(0); uint8_t link_type; + struct crat_subtype_iolink *sub_type_hdr; if (c->x86_vendor == X86_VENDOR_AMD) link_type = CRAT_IOLINK_TYPE_HYPERTRANSPORT; else link_type = CRAT_IOLINK_TYPE_QPI_1_1; - *num_entries = 0; - /* Create IO links from this node to other CPU nodes */ for_each_online_node(nid) { if (nid == numa_node_id) /* node itself */ @@ -935,6 +954,8 @@ static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size, if (*avail_size < 0) return -ENOMEM; + sub_type_hdr = (typeof(sub_type_hdr))((char *)crat_table + + crat_table->length); memset(sub_type_hdr, 0, sizeof(struct crat_subtype_iolink)); /* Fill in subtype header data */ @@ -947,8 +968,8 @@ static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size, sub_type_hdr->proximity_domain_to = nid; sub_type_hdr->io_interface_type = link_type; - (*num_entries)++; - sub_type_hdr++; + crat_table->length += sub_type_hdr->length; + crat_table->total_entries++; } return 0; @@ -966,12 +987,8 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size) struct crat_header *crat_table = (struct crat_header *)pcrat_image; struct acpi_table_header *acpi_table; acpi_status status; - struct crat_subtype_generic *sub_type_hdr; int avail_size = *size; int numa_node_id; -#ifdef CONFIG_X86_64 - uint32_t entries = 0; -#endif int ret = 0; if (!pcrat_image) @@ -1003,48 +1020,25 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size) crat_table->total_entries = 0; crat_table->num_domains = 0; - sub_type_hdr = (struct crat_subtype_generic *)(crat_table+1); - for_each_online_node(numa_node_id) { if (kfd_numa_node_to_apic_id(numa_node_id) == -1) continue; /* Fill in Subtype: Compute Unit */ - ret = kfd_fill_cu_for_cpu(numa_node_id, &avail_size, - crat_table->num_domains, - (struct crat_subtype_computeunit *)sub_type_hdr); + ret = kfd_fill_cu_for_cpu(numa_node_id, &avail_size, crat_table); if (ret < 0) return ret; - crat_table->length += sub_type_hdr->length; - crat_table->total_entries++; - - sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr + - sub_type_hdr->length); /* Fill in Subtype: Memory */ - ret = kfd_fill_mem_info_for_cpu(numa_node_id, &avail_size, - crat_table->num_domains, - (struct crat_subtype_memory *)sub_type_hdr); + ret = kfd_fill_mem_info_for_cpu(numa_node_id, &avail_size, crat_table); if (ret < 0) return ret; - crat_table->length += sub_type_hdr->length; - crat_table->total_entries++; - - sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr + - sub_type_hdr->length); /* Fill in Subtype: IO Link */ #ifdef CONFIG_X86_64 - ret = kfd_fill_iolink_info_for_cpu(numa_node_id, &avail_size, - &entries, - (struct crat_subtype_iolink *)sub_type_hdr); + ret = kfd_fill_iolink_info_for_cpu(numa_node_id, &avail_size, crat_table); if (ret < 0) return ret; - crat_table->length += (sub_type_hdr->length * entries); - crat_table->total_entries += entries; - - sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr + - sub_type_hdr->length * entries); #else pr_info("IO link not available for non x86 platforms\n"); #endif -- 2.28.0