Received: by 2002:a25:8b12:0:0:0:0:0 with SMTP id i18csp2277768ybl; Sun, 18 Aug 2019 22:42:28 -0700 (PDT) X-Google-Smtp-Source: APXvYqwCUK/ndnnKV54lOKORtMjJh/Q0EPveBDd3PqcXq0SpaVwZYEhtjZAl5GLElvDwxe8SuEmm X-Received: by 2002:a62:4e09:: with SMTP id c9mr23271959pfb.130.1566193348265; Sun, 18 Aug 2019 22:42:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1566193348; cv=none; d=google.com; s=arc-20160816; b=wmmps3OfDy/lkLrmuxFZNeEliHrTsZD5v2ggm7sFGv8MToYAwSHOrp7wwCYD8S+1wJ GWzQCw3CXW8HwoXYqOzkeIoua4bJaQ66rjl9Xs7AWX3nOXPeYqFJ3TqPRf9mIYGym4qn XIu7Ji4Bng8a+UkxOynKqz+bIgncjBilRA25w2ef6UJ25N6+xR/Q+FkN+DiRfAg0/vxD 4IIUAIOtgRxww7O00ZZQS8N9IY7Upc+iyV34ej2FI6zS8wgo3ZKz00vD6Qpv8Zie0nbw 6WlwE1aCzxIrcrrjpAqJlzHYTVnypBqLnl61/PQNwWya4d8PUXakXs1R1l7OvqMfQ4c7 dGpg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject; bh=zWB8jLAgdARLGmuRkN0M0oCh371rK2RNpxBwB2y2KCQ=; b=av1ipspD67+FdoH3e8cXcj8yqmnFioDf2k2nA76TMzqDybs+p5Zw0dq1yUENaC5/1P Mk+e48ZOvdL1/6A8ssrBD711Nw2BeVx1rSpf9NMNQIX1GMn5a8tOjAqTV53Y9nMdkAvG Zf2TnS10pEZWBD37hnCpL61PV70f45YQqJQtqLvr4NXZtmyofFJg9M3x/hmb11lJlu07 DZn6axn9h8HrcaJKZ9r81neHVuih+kIuIhuHr3nBgELMXozczrM2E5OixfjT/VL8fPuW e+NlMKRlZvC3ejgliUbkdbDNMvL0f65DBIc8HTLK14yA8blentbdbzKrlxxw8EiA636f mvfw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v37si9174543pga.219.2019.08.18.22.42.13; Sun, 18 Aug 2019 22:42:28 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726578AbfHSFj4 (ORCPT + 99 others); Mon, 19 Aug 2019 01:39:56 -0400 Received: from mga18.intel.com ([134.134.136.126]:54028 "EHLO mga18.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725768AbfHSFj4 (ORCPT ); Mon, 19 Aug 2019 01:39:56 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 18 Aug 2019 22:39:55 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,403,1559545200"; d="scan'208";a="378083046" Received: from genxtest-ykzhao.sh.intel.com (HELO [10.239.143.71]) ([10.239.143.71]) by fmsmga006.fm.intel.com with ESMTP; 18 Aug 2019 22:39:53 -0700 Subject: Re: [RFC PATCH 08/15] drivers/acrn: add VM memory management for ACRN char device To: Dan Carpenter Cc: x86@kernel.org, linux-kernel@vger.kernel.org, devel@driverdev.osuosl.org, Li@osuosl.org, Fei , Jason Chen CJ , Liu Shuo References: <1565922356-4488-1-git-send-email-yakui.zhao@intel.com> <1565922356-4488-9-git-send-email-yakui.zhao@intel.com> <20190816124757.GW1974@kadam> From: "Zhao, Yakui" Message-ID: <8b909c22-3873-2b5d-4845-1fee1a5d81ce@intel.com> Date: Mon, 19 Aug 2019 13:32:54 +0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.6.0 MIME-Version: 1.0 In-Reply-To: <20190816124757.GW1974@kadam> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 2019年08月16日 20:58, Dan Carpenter wrote: > On Fri, Aug 16, 2019 at 10:25:49AM +0800, Zhao Yakui wrote: >> +int hugepage_map_guest(struct acrn_vm *vm, struct vm_memmap *memmap) >> +{ >> + struct page *page = NULL, *regions_buf_pg = NULL; >> + unsigned long len, guest_gpa, vma; >> + struct vm_memory_region *region_array; >> + struct set_regions *regions; >> + int max_size = PAGE_SIZE / sizeof(struct vm_memory_region); >> + int ret; >> + >> + if (!vm || !memmap) >> + return -EINVAL; >> + >> + len = memmap->len; >> + vma = memmap->vma_base; >> + guest_gpa = memmap->gpa; >> + >> + /* prepare set_memory_regions info */ >> + regions_buf_pg = alloc_page(GFP_KERNEL); >> + if (!regions_buf_pg) >> + return -ENOMEM; >> + >> + regions = kzalloc(sizeof(*regions), GFP_KERNEL); >> + if (!regions) { >> + __free_page(regions_buf_pg); >> + return -ENOMEM; > > It's better to do a goto err_free_regions_buf here. More comments > below. > >> + } >> + regions->mr_num = 0; >> + regions->vmid = vm->vmid; >> + regions->regions_gpa = page_to_phys(regions_buf_pg); >> + region_array = page_to_virt(regions_buf_pg); >> + >> + while (len > 0) { >> + unsigned long vm0_gpa, pagesize; >> + >> + ret = get_user_pages_fast(vma, 1, 1, &page); >> + if (unlikely(ret != 1) || (!page)) { >> + pr_err("failed to pin huge page!\n"); >> + ret = -ENOMEM; >> + goto err; > > goto err is a red flag. It's better if error labels do one specific > named thing like: > > err_regions: > kfree(regions); > err_free_regions_buf: > __free_page(regions_buf_pg); > > We should unwind in the opposite/mirror order from how things were > allocated. Then we can remove the if statements in the error handling. Thanks for the review. Will follow your suggestion to unwind the error handling. > > In this situation, say the user triggers an -EFAULT in > get_user_pages_fast() in the second iteration through the loop. That > means that "page" is the non-NULL page from the previous iteration. We > have already added it to add_guest_map(). But now we're freeing it > without removing it from the map so probably it leads to a use after > free. > > The best way to write the error handling in a loop like this is to > clean up the partial iteration that has succeed (nothing here), and then > unwind all the successful iterations at the bottom of the function. > "goto unwind_loop;" > In theory we should cleanup the previous success iteration if it encounters one error in the current iteration. But it will be quite complex to cleanup up the previous iteration. call the set_memory_regions for MR_DEL op. call the remove_guest_map for the added hash item call the put_page for returned page in get_user_pages_fast. In fact as this driver is mainly used for embedded IOT usage, it doesn't handle the complex cleanup when such error is encountered. Instead the clean up is handled in free_guest_vm. >> + } >> + >> + vm0_gpa = page_to_phys(page); >> + pagesize = PAGE_SIZE << compound_order(page); >> + >> + ret = add_guest_map(vm, vm0_gpa, guest_gpa, pagesize); >> + if (ret < 0) { >> + pr_err("failed to add memseg for huge page!\n"); >> + goto err; > > So then here, it would be: > > pr_err("failed to add memseg for huge page!\n"); > put_page(page); > goto unwind_loop; > > regards, > dan carpenter > >> + } >> + >> + /* fill each memory region into region_array */ >> + region_array[regions->mr_num].type = MR_ADD; >> + region_array[regions->mr_num].gpa = guest_gpa; >> + region_array[regions->mr_num].vm0_gpa = vm0_gpa; >> + region_array[regions->mr_num].size = pagesize; >> + region_array[regions->mr_num].prot = >> + (MEM_TYPE_WB & MEM_TYPE_MASK) | >> + (memmap->prot & MEM_ACCESS_RIGHT_MASK); >> + regions->mr_num++; >> + if (regions->mr_num == max_size) { >> + pr_debug("region buffer full, set & renew regions!\n"); >> + ret = set_memory_regions(regions); >> + if (ret < 0) { >> + pr_err("failed to set regions,ret=%d!\n", ret); >> + goto err; >> + } >> + regions->mr_num = 0; >> + } >> + >> + len -= pagesize; >> + vma += pagesize; >> + guest_gpa += pagesize; >> + } >> + >> + ret = set_memory_regions(regions); >> + if (ret < 0) { >> + pr_err("failed to set regions, ret=%d!\n", ret); >> + goto err; >> + } >> + >> + __free_page(regions_buf_pg); >> + kfree(regions); >> + >> + return 0; >> +err: >> + if (regions_buf_pg) >> + __free_page(regions_buf_pg); >> + if (page) >> + put_page(page); >> + kfree(regions); >> + return ret; >> +} >> + >