get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/93452/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 93452,
    "url": "https://patches.dpdk.org/api/patches/93452/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210526210147.1287-4-dmitry.kozliuk@gmail.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210526210147.1287-4-dmitry.kozliuk@gmail.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210526210147.1287-4-dmitry.kozliuk@gmail.com",
    "date": "2021-05-26T21:01:46",
    "name": "[kmods,v2,3/4] windows/virt2phys: add limits against resource exhaustion",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b1d126273a271c23f46e092b9418c8308ff60ea9",
    "submitter": {
        "id": 1581,
        "url": "https://patches.dpdk.org/api/people/1581/?format=api",
        "name": "Dmitry Kozlyuk",
        "email": "dmitry.kozliuk@gmail.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210526210147.1287-4-dmitry.kozliuk@gmail.com/mbox/",
    "series": [
        {
            "id": 17127,
            "url": "https://patches.dpdk.org/api/series/17127/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=17127",
            "date": "2021-05-26T21:01:43",
            "name": "windows/virt2phys: fix paging issue",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/17127/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/93452/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/93452/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 7F695A0546;\n\tWed, 26 May 2021 23:02:18 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 638144110E;\n\tWed, 26 May 2021 23:02:03 +0200 (CEST)",
            "from mail-lf1-f52.google.com (mail-lf1-f52.google.com\n [209.85.167.52]) by mails.dpdk.org (Postfix) with ESMTP id 38B9D410E6\n for <dev@dpdk.org>; Wed, 26 May 2021 23:01:59 +0200 (CEST)",
            "by mail-lf1-f52.google.com with SMTP id j6so4597207lfr.11\n for <dev@dpdk.org>; Wed, 26 May 2021 14:01:59 -0700 (PDT)",
            "from localhost.localdomain (broadband-37-110-65-23.ip.moscow.rt.ru.\n [37.110.65.23])\n by smtp.gmail.com with ESMTPSA id u28sm13205lfk.172.2021.05.26.14.01.57\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Wed, 26 May 2021 14:01:57 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n h=from:to:cc:subject:date:message-id:in-reply-to:references\n :mime-version:content-transfer-encoding;\n bh=mBqvnwph9Yp2mLQXehDOCd70c64arm+VzlOlgzSx+3s=;\n b=DspMuVWeRTQ6ApYuoaTlp1qBUGehaKnoJoRUbvd4yf36wnizFkxilSZjtYdgRVbGL4\n A0RR3x6TgjPbvkOixUW90XKetXfC/6LBJepB3i9k52BxUhj7Gjdlo0G+59/oQ0/Ad7BW\n GfVRaEF9KWUgz02ow0Kcv55IxAxvshLUX2VPmQNGbfWETByPPkgPfP5R7vjztDCK2Ad4\n Y3XN4guQ4Tekynz4hCuQUueQnTy2qXsZDD53wmIxHELtrVCxv8q/27rLeiEMwe5P4alw\n cq6nNgAxkHDu1Ls7QFGaPXwFORycyLgfbvKI+cKLDOHdzB/0J1wUM7FKyjdmaaM8/6Vg\n p5Dg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20161025;\n h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n :references:mime-version:content-transfer-encoding;\n bh=mBqvnwph9Yp2mLQXehDOCd70c64arm+VzlOlgzSx+3s=;\n b=VZHu8gN6aAlK1hbUliylFPItKTNxOx742Ez8zrthnjtvkpeg0JHegt7UnVfGLOEOOp\n aazI4Mxnv7yM6fH44FNdCw8QsVIHPB1bZHyav+mL6CzvpFSR9mdqKXvW3VssH4/epc4w\n YZi0YJZQU4oG3GZUOwusHx89qSzEHAqNXxBPZbjrsvg2l1uzTEJV44Vn5C2Al26KUob8\n DZtD1XOsKGQmR81yATAPm4oENdt+wnZecWTIssgU5Oc88o4Y5Pa5+lBgHhZ1M5mkrdpG\n daSAtJkCopacm4ZoWg3ds7NhrTYzPsCbGABrsxKwlJZgOuh4cH/qUUepkJutg47SIwt4\n LG8g==",
        "X-Gm-Message-State": "AOAM533mBoXtd8nSgQX6ikjSMQE2SZLrGB1YZwLErmegdI7B7MB1C7mA\n VO+tpysEvzUPxHN10gJrnnnfEe86bSGhgw==",
        "X-Google-Smtp-Source": "\n ABdhPJwlyPBJvELGAx/ysP6Z0Gn0tbCyUiRPVAucF1Jcuqvd/qF8vEAU5ORKJQOnoyi9CYI41FxxUQ==",
        "X-Received": "by 2002:ac2:4281:: with SMTP id m1mr36595lfh.164.1622062918338;\n Wed, 26 May 2021 14:01:58 -0700 (PDT)",
        "From": "Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>",
        "To": "dev@dpdk.org",
        "Cc": "Dmitry Malloy <dmitrym@microsoft.com>,\n Narcisa Ana Maria Vasile <navasile@linux.microsoft.com>,\n Pallavi Kadam <pallavi.kadam@intel.com>,\n Tyler Retzlaff <roretzla@linux.microsoft.com>,\n Nick Connolly <nick.connolly@mayadata.io>,\n Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>",
        "Date": "Thu, 27 May 2021 00:01:46 +0300",
        "Message-Id": "<20210526210147.1287-4-dmitry.kozliuk@gmail.com>",
        "X-Mailer": "git-send-email 2.29.3",
        "In-Reply-To": "<20210526210147.1287-1-dmitry.kozliuk@gmail.com>",
        "References": "<20210501171837.13282-1-dmitry.kozliuk@gmail.com>\n <20210526210147.1287-1-dmitry.kozliuk@gmail.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [kmods PATCH v2 3/4] windows/virt2phys: add limits\n against resource exhaustion",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Tracked processes are enumerated in process creation/termination\ncallback, making it O(N = number of tracked processes). A malicious user\ncould cause system-wide slowdown of process termination by making just one\ncall to virt2phys from many processes. Limit the number of tracked\nprocesses by `ProcessCountLimit` items.\n\nAny process with access to virt2phys could exhaust RAM for all the\nsystem by locking it. It can also exhaust RAM needed for other processes\nwith access to virt2phys. Limit amount of memory locked by each tracked\nprocess with `ProcessMemoryLimitMB`.\n\nAll limits are read from registry at driver load.\nEach limit can be turned off by setting it to 0.\nDocument limits and their non-zero defaults for administrators.\n\nSigned-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>\n---\n windows/virt2phys/README.md         | 38 +++++++++++++++\n windows/virt2phys/virt2phys.c       | 73 ++++++++++++++++++++++++++++-\n windows/virt2phys/virt2phys_logic.c | 46 +++++++++++++-----\n windows/virt2phys/virt2phys_logic.h |  9 +++-\n 4 files changed, 152 insertions(+), 14 deletions(-)\n create mode 100644 windows/virt2phys/README.md",
    "diff": "diff --git a/windows/virt2phys/README.md b/windows/virt2phys/README.md\nnew file mode 100644\nindex 0000000..04012ff\n--- /dev/null\n+++ b/windows/virt2phys/README.md\n@@ -0,0 +1,38 @@\n+Virtual to Physical Address Translator\n+======================================\n+\n+Purpose and Operation\n+---------------------\n+\n+``virt2phys`` driver allows user-mode processes to obtain physical address\n+of a given virtual address in their address space.\n+Virtual addresses must belong to regions from process private working set.\n+These regions must be physically contiguous.\n+The driver ensures that memory regions with translated addresses\n+are not swapped out as long as the process has access to this memory.\n+\n+It is not safe to administratively unload the driver\n+while there are processes that have used virt2phys to translate addresses.\n+Doing so will permanently leak RAM occupied by all memory regions\n+that contain translated addresses.\n+Terminate all such processes before unloading the driver.\n+\n+Configuration\n+-------------\n+\n+``virt2phys`` is configured at loading time via registry key\n+``HKLM\\SYSTEM\\ControlSet001\\Services\\virt2phys\\Parameters``.\n+\n+* ``ProcessCountLimit`` (default 16)\n+\n+  Maximum number of processes that can have access to memory regions\n+  with translated addresses. When this limit is reached, no more processes\n+  can translate addresses using ``virt2phys``. Large number of tracked\n+  processes may slow down system operation. Set limit to 0 to disable it.\n+\n+* ``ProcessMemoryLimitMB`` (default 16384, i.e. 16 GB)\n+\n+  Maximum amount of memory in all regions that contain translated addresses,\n+  total per process. When this limit is reached, the process can not translate\n+  addresses from new regions. Large values can cause RAM exhaustion.\n+  Set limit to 0 to disable it.\n\\ No newline at end of file\ndiff --git a/windows/virt2phys/virt2phys.c b/windows/virt2phys/virt2phys.c\nindex bf0c300..44204c9 100644\n--- a/windows/virt2phys/virt2phys.c\n+++ b/windows/virt2phys/virt2phys.c\n@@ -14,15 +14,22 @@ EVT_WDF_DRIVER_UNLOAD virt2phys_driver_unload;\n EVT_WDF_DRIVER_DEVICE_ADD virt2phys_driver_EvtDeviceAdd;\n EVT_WDF_IO_IN_CALLER_CONTEXT virt2phys_device_EvtIoInCallerContext;\n \n+static NTSTATUS virt2phys_load_params(\n+\tWDFDRIVER driver, struct virt2phys_params *params);\n static VOID virt2phys_on_process_event(\n \tHANDLE parent_id, HANDLE process_id, BOOLEAN create);\n \n+static const ULONG PROCESS_COUNT_LIMIT_DEF = 1 << 4;\n+static const ULONG PROCESS_MEMORY_LIMIT_DEF = 16 * (1 << 10); /* MB */\n+\n _Use_decl_annotations_\n NTSTATUS\n DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)\n {\n \tWDF_DRIVER_CONFIG config;\n \tWDF_OBJECT_ATTRIBUTES attributes;\n+\tWDFDRIVER driver;\n+\tstruct virt2phys_params params;\n \tNTSTATUS status;\n \n \tPAGED_CODE();\n@@ -32,11 +39,15 @@ DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)\n \tconfig.EvtDriverUnload = virt2phys_driver_unload;\n \tstatus = WdfDriverCreate(\n \t\tdriver_object, registry_path,\n-\t\t&attributes, &config, WDF_NO_HANDLE);\n+\t\t&attributes, &config, &driver);\n+\tif (!NT_SUCCESS(status))\n+\t\treturn status;\n+\n+\tstatus = virt2phys_load_params(driver, &params);\n \tif (!NT_SUCCESS(status))\n \t\treturn status;\n \n-\tstatus = virt2phys_init();\n+\tstatus = virt2phys_init(&params);\n \tif (!NT_SUCCESS(status))\n \t\treturn status;\n \n@@ -58,6 +69,64 @@ DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)\n \treturn status;\n }\n \n+static NTSTATUS\n+virt2phys_read_param(WDFKEY key, PCUNICODE_STRING name, ULONG *value,\n+\tULONG def)\n+{\n+\tNTSTATUS status;\n+\n+\tstatus = WdfRegistryQueryULong(key, name, value);\n+\tif (status == STATUS_OBJECT_NAME_NOT_FOUND) {\n+\t\t*value = def;\n+\t\tstatus = STATUS_SUCCESS;\n+\t}\n+\treturn status;\n+}\n+\n+static NTSTATUS\n+virt2phys_read_mb(WDFKEY key, PCUNICODE_STRING name, ULONG64 *bytes,\n+\tULONG def_mb)\n+{\n+\tULONG mb;\n+\tNTSTATUS status;\n+\n+\tstatus = virt2phys_read_param(key, name, &mb, def_mb);\n+\tif (NT_SUCCESS(status))\n+\t\t*bytes = (ULONG64)mb * (1ULL << 20);\n+\treturn status;\n+}\n+\n+static NTSTATUS\n+virt2phys_load_params(WDFDRIVER driver, struct virt2phys_params *params)\n+{\n+\tstatic DECLARE_CONST_UNICODE_STRING(\n+\t\tprocess_count_limit, L\"ProcessCountLimit\");\n+\tstatic DECLARE_CONST_UNICODE_STRING(\n+\t\tprocess_memory_limit, L\"ProcessMemoryLimitMB\");\n+\n+\tWDFKEY key;\n+\tNTSTATUS status;\n+\n+\tstatus = WdfDriverOpenParametersRegistryKey(\n+\t\tdriver, KEY_READ, WDF_NO_OBJECT_ATTRIBUTES, &key);\n+\tif (!NT_SUCCESS(status))\n+\t\treturn status;\n+\n+\tstatus = virt2phys_read_param(key, &process_count_limit,\n+\t\t&params->process_count_limit, PROCESS_COUNT_LIMIT_DEF);\n+\tif (!NT_SUCCESS(status))\n+\t\tgoto cleanup;\n+\n+\tstatus = virt2phys_read_mb(key, &process_memory_limit,\n+\t\t&params->process_memory_limit, PROCESS_MEMORY_LIMIT_DEF);\n+\tif (!NT_SUCCESS(status))\n+\t\tgoto cleanup;\n+\n+cleanup:\n+\tWdfRegistryClose(key);\n+\treturn status;\n+}\n+\n _Use_decl_annotations_\n VOID\n virt2phys_driver_unload(WDFDRIVER driver)\ndiff --git a/windows/virt2phys/virt2phys_logic.c b/windows/virt2phys/virt2phys_logic.c\nindex a27802c..37b4dd4 100644\n--- a/windows/virt2phys/virt2phys_logic.c\n+++ b/windows/virt2phys/virt2phys_logic.c\n@@ -11,6 +11,7 @@ struct virt2phys_process {\n \tHANDLE id;\n \tLIST_ENTRY next;\n \tSINGLE_LIST_ENTRY blocks;\n+\tULONG64 memory;\n };\n \n struct virt2phys_block {\n@@ -18,7 +19,9 @@ struct virt2phys_block {\n \tSINGLE_LIST_ENTRY next;\n };\n \n+static struct virt2phys_params g_params;\n static LIST_ENTRY g_processes;\n+static LONG g_process_count;\n static PKSPIN_LOCK g_lock;\n \n struct virt2phys_block *\n@@ -112,7 +115,7 @@ virt2phys_process_find_block(struct virt2phys_process *process, PVOID virt)\n }\n \n NTSTATUS\n-virt2phys_init(void)\n+virt2phys_init(const struct virt2phys_params *params)\n {\n \tg_lock = ExAllocatePoolZero(NonPagedPool, sizeof(*g_lock), 'gp2v');\n \tif (g_lock == NULL)\n@@ -120,6 +123,7 @@ virt2phys_init(void)\n \n \tInitializeListHead(&g_processes);\n \n+\tg_params = *params;\n \treturn STATUS_SUCCESS;\n }\n \n@@ -165,8 +169,10 @@ virt2phys_process_cleanup(HANDLE process_id)\n \tprocess = virt2phys_process_detach(process_id);\n \tKeReleaseSpinLock(g_lock, irql);\n \n-\tif (process != NULL)\n+\tif (process != NULL) {\n \t\tvirt2phys_process_free(process, TRUE);\n+\t\tInterlockedDecrement(&g_process_count);\n+\t}\n }\n \n static struct virt2phys_block *\n@@ -195,21 +201,38 @@ virt2phys_exceeeds(LONG64 count, ULONG64 limit)\n \treturn limit > 0 && count > (LONG64)limit;\n }\n \n-static BOOLEAN\n+static NTSTATUS\n virt2phys_add_block(struct virt2phys_process *process,\n-\tstruct virt2phys_block *block)\n+\tstruct virt2phys_block *block, BOOLEAN *process_exists)\n {\n \tstruct virt2phys_process *existing;\n+\tsize_t size;\n \n \texisting = virt2phys_process_find(process->id);\n-\tif (existing == NULL)\n+\t*process_exists = existing != NULL;\n+\tif (existing == NULL) {\n+\t\t/*\n+\t\t * This check is done with the lock held so that's no race.\n+\t\t * Increment below must be atomic however,\n+\t\t * because decrement is done without holding the lock.\n+\t\t */\n+\t\tif (virt2phys_exceeeds(g_process_count + 1,\n+\t\t\t\tg_params.process_count_limit))\n+\t\t\treturn STATUS_QUOTA_EXCEEDED;\n+\n \t\tInsertHeadList(&g_processes, &process->next);\n-\telse\n+\t\tInterlockedIncrement(&g_process_count);\n+\t} else\n \t\tprocess = existing;\n \n-\tPushEntryList(&process->blocks, &block->next);\n+\tsize = MmGetMdlByteCount(block->mdl);\n+\tif (virt2phys_exceeeds(process->memory + size,\n+\t\t\tg_params.process_memory_limit))\n+\t\treturn STATUS_QUOTA_EXCEEDED;\n \n-\treturn existing != NULL;\n+\tPushEntryList(&process->blocks, &block->next);\n+\tprocess->memory += size;\n+\treturn STATUS_SUCCESS;\n }\n \n static NTSTATUS\n@@ -356,13 +379,14 @@ virt2phys_translate(PVOID virt, PHYSICAL_ADDRESS *phys)\n \t}\n \n \tKeAcquireSpinLock(g_lock, &irql);\n-\ttracked = virt2phys_add_block(process, block);\n+\tstatus = virt2phys_add_block(process, block, &tracked);\n \tKeReleaseSpinLock(g_lock, irql);\n \n \t/* Same process has been added concurrently, block attached to it. */\n \tif (tracked && created)\n \t\tvirt2phys_process_free(process, FALSE);\n \n-\t*phys = virt2phys_block_translate(block, virt);\n-\treturn STATUS_SUCCESS;\n+\tif (NT_SUCCESS(status))\n+\t\t*phys = virt2phys_block_translate(block, virt);\n+\treturn status;\n }\ndiff --git a/windows/virt2phys/virt2phys_logic.h b/windows/virt2phys/virt2phys_logic.h\nindex 1582206..c8255f9 100644\n--- a/windows/virt2phys/virt2phys_logic.h\n+++ b/windows/virt2phys/virt2phys_logic.h\n@@ -5,10 +5,17 @@\n #ifndef VIRT2PHYS_LOGIC_H\n #define VIRT2PHYS_LOGIC_H\n \n+struct virt2phys_params {\n+\t/** Maximum number of tracked processes (0 = unlimited). */\n+\tULONG process_count_limit;\n+\t/** Maximum amount of memory locked by a process (0 = unlimited). */\n+\tULONG64 process_memory_limit;\n+};\n+\n /**\n  * Initialize internal data structures.\n  */\n-NTSTATUS virt2phys_init(void);\n+NTSTATUS virt2phys_init(const struct virt2phys_params *params);\n \n /**\n  * Free memory allocated for internal data structures.\n",
    "prefixes": [
        "kmods",
        "v2",
        "3/4"
    ]
}