From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (unknown [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id 50204802A5 for ; Fri, 9 Oct 2026 14:50:48 +0000 (UTC) Received: from mail.openvz.org (localhost [127.0.0.1]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 699EnWLM008821; Fri, 9 Oct 2026 17:49:33 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 699EnWLM008821 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="kSz3bCNS" Received: from mail-ua1-f71.google.com (mail-ua1-f71.google.com [209.85.222.71]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 699EnURd008817 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Fri, 9 Oct 2026 17:49:31 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 699EnURd008817 Received: by mail-ua1-f71.google.com with SMTP id a1e0cc1a2514c-988d5a1080eso4852278241.0 for ; Fri, 09 Oct 2026 07:49:30 -0700 (PDT) X-Gm-Message-State: AFq9FYLCvmW+SJ0/CAjZB9VkX3toSgHkbUcvyrOpwBAf5SgTEplNJKH+ R1CDxeb2z5woK+7uUgiINPOvI1QoDtxdNxbAkRY4F9UhlUFsEVouj9BnO8UqVqpY+WgPnjWFQYX qYhoCBYUhlSltnE4bnjIHIL2d71j2ujI2LR4ZjsPizlmfmtWhTBRfBw== X-Gm-Gg: AYBFou1A7py52M3DVoyfsB/LaAX89AKgjjFA6dLl+BWg/R3KsSHI+t3JVlu094A5jv/ aEkcJVQWRdtdBAbhKZ543aQdcL4Sf9H3GQivaUDmKRw3axIOP5bR1G4T47klM2vbwLlggoI3nFK qj0QyJ3EwCa3wQrogpyD7q9zA3hS8ge7D6CJtx/zhHhDkKNHpuLaBXVl8qceVRYYa8/R2+rNB3J C7ukk2sApYv6lojyxh1tlVqlVAv1O33FAHF6FqHY/JnT2M9q3fowXWh5gGtA231nvww/WHNZMi2 HTd4IxBCcm3BT0xQdTUTuy1tKcQJ1eoWQ8IF0Z3sBTV8dQAZw6eMRnCmvkJ7a4289k7vhVFPEES hnZAYROIGqp2lBcKSN5mCBy3cRiBxMTzCotVAtJvFKPG3V3X1aQfDbVFemkJ6Jr6EFVtQVGJwOO la5kaa4JfPU3jWCFCcOVcRt4aVHxnBoZE= X-Received: by 2002:a05:6300:6bd6:20b0:3e1:7677:e53 with SMTP id adf61e73a8af0-3e1767712aemr414699637.29.1791554431241; Fri, 09 Oct 2026 07:00:31 -0700 (PDT) X-Received: by 2002:a05:6300:6bd6:20b0:3e1:7677:e53 with SMTP id adf61e73a8af0-3e1767712aemr414321637.29.1791554423965; Fri, 09 Oct 2026 07:00:23 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1791554423; cv=pass; d=google.com; s=arc-20260327; b=WfQ1gmGRceAhCmvuFz5Z9o3qc1u0KpbB/wE6Ki2l/gb2swBbY0aWDY5i4OZags61jY suBFJcA4r8kHT4iVXjIfZOMpPbb54AOvQgoCVjRD1oWnQ3h3Uei4yL2ehxfLip54pH0a aaQsNAimt/2hpKsVwVPVvcr6PuSx5Z4btPzPbTs7FvR54wXz4gxygGHnpoxH/5NZgCZg hLdIbP7Kds2T+gf5Qa1ZZd23dpBTRGPs06VKxFFljajWvYngGb8w4M6mRyiJmyKKRmsM Z1gDrCOMhcaOUWQqCEsqNevoSJe4XodDvzimzORZ4usxIYF0IjJ6XqUOegWqwdNTIMak Fh0g== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=mime-version:cc:to:in-reply-to:references:message-id :content-transfer-encoding:subject:date:from:dkim-signature; bh=Q/w3VzgM1b+CEK7AUh2OdOyhhbTIidtXG6xmSTSub8o=; fh=QMK9nbJ5AYrM+hiPA/q5PkyEnWxrtaWE6qYGnw4J4RA=; b=CRFEdpbFqR0IEE7uXhZX7KSAKCVeXkP3TUq87Hu8HnHmnlGwEcTdpq1ncCljjJ04ga ks2MJBBknn1JVPzdlBNa3By7huBf5gXUr0ttqwpncqO/VdB1HV/s8SIrYx4DlPaks6PM QSxO8jd1zD3nio7Dnz/XIuF7g6i14k2a+007tzoWNxVzkmpMQldSubUpBEcVJhLBmtuF 91A82HTZhhiYHQq+A7IsafngBHxyrQBYs/6GM89LpKI9SZ2IAdxB7DdYmTjpTvLroxHZ O4vKGqefPzKNVz3IwhReJ/y/7VZpOFaBzgVmFfYmrhNMTCVc7EkAbNA43bJEGZzDdgqk kmEQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=selector2 header.b=kSz3bCNS; arc=pass (i=1 spf=pass spfdomain=virtuozzo.com dkim=pass dkdomain=virtuozzo.com dmarc=pass fromdomain=virtuozzo.com); spf=pass (google.com: domain of andrey.drobyshev@virtuozzo.com designates 2a01:111:f403:c201::1 as permitted sender) smtp.mailfrom=andrey.drobyshev@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: from AM0PR83CU005.outbound.protection.outlook.com (mail-westeuropeazlp170100001.outbound.protection.outlook.com. [2a01:111:f403:c201::1]) by mx.google.com with ESMTPS id 41be03b00d2f7-cd3da079de5si3637768a12.252.2026.10.09.07.00.23 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Oct 2026 07:00:23 -0700 (PDT) Received-SPF: pass (google.com: domain of andrey.drobyshev@virtuozzo.com designates 2a01:111:f403:c201::1 as permitted sender) client-ip=2a01:111:f403:c201::1; Authentication-Results: mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=selector2 header.b=kSz3bCNS; arc=pass (i=1 spf=pass spfdomain=virtuozzo.com dkim=pass dkdomain=virtuozzo.com dmarc=pass fromdomain=virtuozzo.com); spf=pass (google.com: domain of andrey.drobyshev@virtuozzo.com designates 2a01:111:f403:c201::1 as permitted sender) smtp.mailfrom=andrey.drobyshev@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ehIxlXdS/7NZNI28mKOLSTHY8slJ54j92udcObjl1JymFFfqI3MYmxB0J1ik5rEq480OPcfz+1o3YnXMuyqlHf7VyXNqu8Fa4LFQDXA/RTlJ8eplr9Ir/uiJlgsRwY60kP81jfITZtPTKBdIg/8mCdwxHvrWSAvy9qJX/ASAKmOCmGgDuTNObGjbcLKII5sdN5yAqwViVf2DSNY35btw+4X2ZaxAwMe+Yw0aw80AExI6vxUIQHvWPN3oBlgI+3bhzFzBWoK7wfpzp3f55R/PMQJN+lUUq/ybm3RVlWetvbNe+yK6z9JwS9b1FVzNVz9SRw5+heCYk+RPeoBoiDSBDw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Q/w3VzgM1b+CEK7AUh2OdOyhhbTIidtXG6xmSTSub8o=; b=qbol8kDldQDtFbipgO1+EuDXX2l1hHpwISnFoBRDI7PnxQf9xy2YTOQ5lJFAx8/VhuDWlMf/9jhL7/bC1nFO7/dw+FT5Z5TFdvXYa44d+CQPOSEBAsVSt+m1k0T+EE/hC/OiT9lIRAKOdg84OLGSuhnTxlQfomv4sOjBQtlaixleFNLwKVGpOI1PvnnelM+ONmaVkeMl9K43hulostU1Dni+QuVNTCMs3dQSTpcD673JbK8x8EKCW5JsaenTCWSENm4dLqbwp61hhuG7LnrH4cIsQ0wSc1ekGPWSPJOM8AccmomS2Oricv075qGbJlbWPMKcq+MiRRu7zS0VVG97Qg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=virtuozzo.com; dmarc=pass action=none header.from=virtuozzo.com; dkim=pass header.d=virtuozzo.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=virtuozzo.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Q/w3VzgM1b+CEK7AUh2OdOyhhbTIidtXG6xmSTSub8o=; b=kSz3bCNSy56FZT1AmFNsstOFR8GSGeBtLA1AD6Z9j3dQv7FPxCbOXIcg8O5b4Ipg1gqWM5x7qOgDF/8g55F1piusXnzmHHyw2Lm94s7q/xZdEvWHkJ0b1trQ3Mu/t5hc5v491ZYsszbFcx/P5rL6OW+iJMvtPJiabrrUeiAhR5cDijl4Jp4bBHUfr8LcyQc1jMpWh/fOqM3Is1wvSmMpygHFAjkKj6VkNZHGerwQZrlxtfabdUSDNI5WUakXpRI74AQx0rvFOgGsNUe4iVMHdJmMcUPU7+nl/sAEtNqJLovWvne0GR8IRvA1wUdasedpQia/AqTyngJ59w8gW2WeMA== Authentication-Results: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=virtuozzo.com; Received: from VI0PR08MB10656.eurprd08.prod.outlook.com (2603:10a6:800:20a::12) by PR3PR08MB5802.eurprd08.prod.outlook.com (2603:10a6:102:8a::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.496.15; Fri, 9 Oct 2026 14:00:17 +0000 Received: from VI0PR08MB10656.eurprd08.prod.outlook.com ([fe80::4e37:b189:ddcd:3dd8]) by VI0PR08MB10656.eurprd08.prod.outlook.com ([fe80::4e37:b189:ddcd:3dd8%7]) with mapi id 15.21.0496.010; Fri, 9 Oct 2026 14:00:17 +0000 From: Andrey Drobyshev Date: Fri, 09 Oct 2026 17:00:07 +0300 Message-Id: <20261009-vfio_v1-v1-4-1901cd6c3c74@virtuozzo.com> References: <20261009-vfio_v1-v1-0-1901cd6c3c74@virtuozzo.com> In-Reply-To: <20261009-vfio_v1-v1-0-1901cd6c3c74@virtuozzo.com> To: Konstantin Khorenko X-Mailer: b4 0.16.0 X-ClientProxiedBy: VI6PEPF0000022A.AUTP296.PROD.OUTLOOK.COM (2603:10a6:808:1::8e6) To VI0PR08MB10656.eurprd08.prod.outlook.com (2603:10a6:800:20a::12) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI0PR08MB10656:EE_|PR3PR08MB5802:EE_ X-MS-Office365-Filtering-Correlation-Id: 51a1a308-dce2-4435-379f-08df260da57a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|52116014|366016|1800799024|376014|23010399003|6133799003|22082099003|18002099003|10067099003|38350700014|56012099006; X-Microsoft-Antispam-Message-Info: UnyyrVnJisl2USGqFUJygJ7ks23Qq59+sX7pQyU+4XP3+tNPnK3+M3SgRKLczIkjvLXJ05U3nQ3TxLrYGl9DOmDpeRc6eb33Ds81sxrKdxSJIMeKV3q92X72gpVEWyYUD/c5CkoyecdHDonE4QOB4ttq417+D4JIJ33BR5yvPpSCpvIQgFHafhG58AOp7KBGU6eyDJ+z0uBfKh6L6fX141KRueQDmxYlozTmvhe41wKijWNCgkUH0PoEtj/v4UWmhrOfGZ18tDWQMynZUVWgvTqMcrqq2AK71lsIx5CaRJIAcIYi6da8+m1msfurSknmpmyaZOQqLbquIt9PVFF22h4Bu0gDN7BQOjRrPWq5dA30JyUO4dPAx3kuyzM8bBr4+VCIuo87HPdEYfnGTOAQW9FwrGgPfQ3flQ1Aas9Oan8mOlKWuxOtKe3POXEch6iv0EL49JDPjEgf0JjOmGobh+aAwVFSdW8YaV5gc97tYLuIwqvENHNv551aajGDbvgWA4iSK8Lt4sExexC7PrbGeBbXly42kBxV9O3DJX/FO4tqSYlZLIlt8ZxmjC1etP0NUyjClyzFDHeqYNL+htAUgi+OqNaEoKroenHUH5iAd4N1y1W7h9SmU+cwAAIIjOvNJHsPY1/5H9Ben7yqjFmdhHec1F81qUTq/KLtlXfuzVDKPBRzfAGRVgBv4VxnCxhzINK7+u/E5C6/oaICAp7VzaZAaroOvN7iHkENXzCPffk= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:VI0PR08MB10656.eurprd08.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(52116014)(366016)(1800799024)(376014)(23010399003)(6133799003)(22082099003)(18002099003)(10067099003)(38350700014)(56012099006); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?M0FSY0dWLzlUMUhWWlRxK3lYWmpyUkRvaVFUTXVnQ1NMQkZjenR6ZVVsUkZY?= =?utf-8?B?cWlhajc5YndYT2pUMldZV1ZpUkZNZDREQXJnOTd2M1pmdEN3WUlkSjFMZFg3?= =?utf-8?B?ampMUytrOHVML3NDaHRvVnc1eVI0Y1Boa0kzcWhyMDlCRzhMY0FHVmhEL2k0?= =?utf-8?B?TTJZcmNBblNoVkowRHF6Nm9STXB5K3lob0NBMkxBSFBWZ0lEQTZzRGdaNHd4?= =?utf-8?B?UE14VDhjVzNvZDdRWWdmT09FNHRZcGVmMWhIdVZ3ZXN5aDY5Zy9Ya0Y1Ylh0?= =?utf-8?B?RE1GMWVaY0ZNRnVYdWVjN1BxTEs4WjJhQXBWZHowVFluQ0ZOWUYwRUQ1MlhS?= =?utf-8?B?SXExL2JKYm5jSTdDc0RRWDRXYjF2RXJaMTNZTHRDa01OelI1UXVMTmhobnl5?= =?utf-8?B?cjNCcXNKMC9ZbEV3S1lpa1Z1Q3hUNGEvbmhRU3RzVGNKS05salIrVGliVm1O?= =?utf-8?B?dU5aU2d3eGtVamcxRmhGYlJnSFAyMlZZeURITk9ma1psSE05ZUFOUjlNWC9W?= =?utf-8?B?MURLNVFYcGhQbHNza0NzbFhFa3prR3IrUmFiNWN3REx5Vk1aMEU4YVBPc2Vp?= =?utf-8?B?Q3YwYm1XUzhZOW5yWGU0OVJFbzhPcUtGQ1Y0VmRZd3hVdEVOWE5ValM3bnB0?= =?utf-8?B?WXVPRjZ1anVWeFhVNWx3a1F6eGlWUmltb0h0dUZkczE5WFlDcGlvWVBLQkFX?= =?utf-8?B?SUNBVjdPdndQMFUrY0syNHRnY2NlT0syR3d0ZG5JZjgrS1dCTU1CU0g4NE8v?= =?utf-8?B?QklyWExzb3VTTFVVc3cxNmxESmU0dlZQWCtPWDNwM2xpa25Vck9DeWR3dktW?= =?utf-8?B?d3dIaGtzWFI4UDYzbXlTZlU5ajlIY0tIbTlIdk5TVXVRNzh2T3FnT05ldE5P?= =?utf-8?B?OEZDeWhGRTJGR1RsUDRnQXQzVnpLMjliQmswL056bTB4Y1h4eENRN1pDTk9C?= =?utf-8?B?K0lJNHh0K1JzemZWMDR5VHNua2txMUsyL3NqOEFMaUtsWXp5TzlBVlBxRXVN?= =?utf-8?B?bFFHRGk0TzMrVnphSitxWnkxcjhxRUYvdkZ4SGhTc2NYdXg2MGN1bElTeDkz?= =?utf-8?B?bHNkS3AzTEJRTEx0Q2QxSldFQVMwN2g4eGVFRy9pY1dCdk54TmVaVUd4WjRI?= =?utf-8?B?YUp2VmJ3bnp0Y290SmFNcWZpNml5bnRIaTRYMCtpbVNWeEtzaTlVeTUyTVFJ?= =?utf-8?B?VzVxOXMrV1FTaGIweFdyc0taZnM3Zmo2UnRJS21mTCtiL01MSmtDZWhzY0Rs?= =?utf-8?B?cEpVaG1WUDVNeXFsd2l5VFV3cUw4NXFWcGkxN0ZCYitsNk5XM0tWSC9lTFlN?= =?utf-8?B?TFJxekN1L0c1L2t3NU1lMWxaSEZtbkNrWkJ5aUxWRFdFL2ZXelZzOWlDMXFr?= =?utf-8?B?Ulo5QmFtdE5iKzhocFI3MmNEZmlOYXJtVGZIejZjZklHQ0lPSnBOVWtuL3VC?= =?utf-8?B?Y21pSmk4VDA1c2tma1Z6MnIxUWFjdFkrcjVOc2llOW92MWhiUkQzaG9ROGp6?= =?utf-8?B?MmF6cFVNVGlEN1R3TUQ5d25EcmVYUUFYdWdBdHoxUmE1MGpJZlhnRURMOC9a?= =?utf-8?B?bk50dGhseDhaaUU1MzhLSi9pVVVnSGVIOG9MVm1iQjVOdDhYQTFnOFpoZmxH?= =?utf-8?B?NU41eWs4bFdrQmhkSGU3ZHNmR1Y2UCtKd01uZ3pMcTdyZkR6VTJTbUFYVHRK?= =?utf-8?B?SjJNcU5zOWkxM0tYcUFqOG9wWEVaMy81SVM2S1QwZFd0aG44SUppZHdaOEhp?= =?utf-8?B?S3hGcVdZZFV0ekRYeEtTWXZmN041bkNlNmRIMjMzWWtsT0FwaGE3MUpVTDB0?= =?utf-8?B?cnRQR3NlQXIzakdQZlBhTWl1eERUWXMyTXo3RFBGcEZyUUdWSStkenJXc1U0?= =?utf-8?B?ck1Qb0xxcnRJbGhWQkhVb3lEV3Y3MXNicWliT0JrRTdpeGM2UnpwYU96VElZ?= =?utf-8?B?U0NOTTFUbnJFcFNMVzVqZndyOWE2dEV1WGs2Q3pvTzNyRHU0ZExoQzBXRWtJ?= =?utf-8?B?TGFET0FLczFzdUgyN25wQTFrQmk5Z0JWQndkUWtQL3N4Qzdhb09TLzEyMDFS?= =?utf-8?B?dFpDQlFhMkxxazBFNENySHhSU2hzYWorZThuTldRN1FzNmErUmxCL3M1MTZo?= =?utf-8?B?NzU3L2NyRHdNTU84cDEwcFZVRkgwZzdoNzFBNW5qRXdtTzVIOGR6cGowVjZs?= =?utf-8?B?M2lRaDVZMWdGMUVOYkJ2V2U2VmZzUW9PQUYvN1hXMnlRQkdHYjFZa3V4QXJN?= =?utf-8?B?YzZEOE8vR3gxZ0Zpcm1SdFZQalBOUTMwdzVpQXFQL25RSUpuTXNDKzc0RWQr?= =?utf-8?B?Ykx2dUlaZHRPVno4UHpMcDhlVTFxZ0pOSmkvOHNCamk1MlUzenBZWTRUemo1?= =?utf-8?Q?kpBoX8YunAKypSzI=3D?= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-Network-Message-Id: 51a1a308-dce2-4435-379f-08df260da57a X-MS-Exchange-CrossTenant-AuthSource: VI0PR08MB10656.eurprd08.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Oct 2026 14:00:16.4750 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 0bc7f26d-0264-416e-a6fc-8352af79c58f X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: wTMxbaJ9Xr78buK+yAHUgEaHKJFZ9h58GrfhQy71URWILU7zS2HcqDaItfFz6Hk55mHKj40+xoShCL3Z9Rw4zSh9U7+MrzbP2HoCE04cac4= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PR3PR08MB5802 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH RFC PATCH hci-8.1 4/4] selftests/mm: test memory preservation across exec X-BeenThere: devel@openvz.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: OpenVZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: devel-bounces@openvz.org Errors-To: devel-bounces@openvz.org Add an ELF-opted-in MADV_DOEXEC test and wire it into the mm test runner. Compare CPU writes against retained long-term GUP pins across repeated exec and a later fork, including base pages, THP, mlock, protected mappings and fast GUP. Check existing COW mappings separately. Exercise recoverable rejection and retry with an external CLONE_VM task, own and non-leader threads, concurrent shared-mm clone creation, proc inspection during repeated exec, and vhost owner reset before exec. Add an optional task-local allocation-failure sweep. https://virtuozzo.atlassian.net/browse/VSTOR-103860 Signed-off-by: Andrey Drobyshev --- tools/testing/selftests/mm/Makefile | 1 + tools/testing/selftests/mm/doexec.c | 774 ++++++++++++++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 1 + 3 files changed, 776 insertions(+) diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index c837b0549c89..7f9efb0e0a38 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -74,6 +74,7 @@ endif TEST_GEN_FILES = cow TEST_GEN_FILES += compaction_test +TEST_GEN_FILES += doexec TEST_GEN_FILES += gup_longterm TEST_GEN_FILES += gup_test TEST_GEN_FILES += hmm-tests diff --git a/tools/testing/selftests/mm/doexec.c b/tools/testing/selftests/mm/doexec.c new file mode 100644 index 000000000000..6ec09e868679 --- /dev/null +++ b/tools/testing/selftests/mm/doexec.c @@ -0,0 +1,774 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Verify that exec preserves the memory backing long-term DMA pins. */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../../../mm/gup_test.h" +#include "../kselftest.h" + +#ifndef MADV_DOEXEC +#define MADV_DOEXEC 201 +#endif +#ifndef MADV_COLLAPSE +#define MADV_COLLAPSE 25 +#endif + +/* The downstream ELF loader requires this opt-in in a PT_NOTE segment. */ +asm(".pushsection .note.doexec,\"a\",@note\n" + ".balign 4\n" + ".long 17, 0, 0x07c1feed\n" + ".asciz \"preserved-mem-ok\"\n" + ".balign 4\n" + ".popsection\n"); + +enum test_kind { + BASE, + HUGE, + LOCKED, + PROTECTED, + READ_PIN, + FAST_PIN, + NR_TESTS, +}; + +static const char * const names[] = { + "base pages", + "PMD huge pages", + "mlocked pages", + "read-only mapping", + "read-only pins", + "fast GUP pins", +}; + +static int wait_child(pid_t pid) +{ + int status; + pid_t ret; + + do { + ret = waitpid(pid, &status, 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0 || !WIFEXITED(status)) + return KSFT_FAIL; + return WEXITSTATUS(status); +} + +static int check_pin(int fd, char *ram, size_t size, unsigned char value) +{ + char *copy = malloc(size); + uint64_t addr = (uintptr_t)copy; + size_t i; + int ret = KSFT_FAIL; + + if (!copy) + return ret; + if (ioctl(fd, PIN_LONGTERM_TEST_READ, &addr)) { + ksft_print_msg("read pin: %s\n", strerror(errno)); + goto out; + } + for (i = 0; i < size; i++) { + if ((unsigned char)ram[i] != value || + (unsigned char)copy[i] != value) { + ksft_print_msg("CPU/pin mismatch at byte %zu\n", i); + goto out; + } + } + ret = KSFT_PASS; +out: + free(copy); + return ret; +} + +static int check_bytes(char *ram, size_t size, unsigned char value) +{ + size_t i; + + for (i = 0; i < size; i++) + if ((unsigned char)ram[i] != value) + return KSFT_FAIL; + return KSFT_PASS; +} + +static int after_cow_exec(char *ram, size_t size, pid_t sibling, int pipe_fd) +{ + char ready = 1; + int ret = check_bytes(ram, size, 0x31); + + memset(ram, 0x42, size); + if (write(pipe_fd, &ready, 1) != 1) + ret = KSFT_FAIL; + close(pipe_fd); + if (wait_child(sibling)) + ret = KSFT_FAIL; + return ret; +} + +/* Pages shared with a separate mm must retain their pre-existing COW state. */ +static int before_cow_exec(void) +{ + size_t size = 16 * sysconf(_SC_PAGESIZE); + char addr_arg[32], size_arg[32], pid_arg[32], fd_arg[32], ready; + int pipe_fd[2]; + char *ram; + pid_t pid; + + ram = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ram == MAP_FAILED) + return KSFT_FAIL; + memset(ram, 0x31, size); + if (madvise(ram, size, MADV_DOEXEC)) + return errno == EINVAL ? KSFT_SKIP : KSFT_FAIL; + if (pipe(pipe_fd)) + return KSFT_FAIL; + pid = fork(); + if (pid < 0) + return KSFT_FAIL; + if (!pid) { + close(pipe_fd[1]); + if (read(pipe_fd[0], &ready, 1) != 1) + _exit(KSFT_FAIL); + _exit(check_bytes(ram, size, 0x31)); + } + close(pipe_fd[0]); + snprintf(addr_arg, sizeof(addr_arg), "%llu", + (unsigned long long)(uintptr_t)ram); + snprintf(size_arg, sizeof(size_arg), "%zu", size); + snprintf(pid_arg, sizeof(pid_arg), "%d", pid); + snprintf(fd_arg, sizeof(fd_arg), "%d", pipe_fd[1]); + execl("/proc/self/exe", "doexec", "--cow", addr_arg, size_arg, + pid_arg, fd_arg, NULL); + close(pipe_fd[1]); + wait_child(pid); + return KSFT_FAIL; +} + +static void exec_stage(int fd, char *ram, size_t size, int kind, int stage) +{ + char fd_arg[32], addr_arg[32], size_arg[32], kind_arg[32], stage_arg[32]; + + snprintf(fd_arg, sizeof(fd_arg), "%d", fd); + snprintf(addr_arg, sizeof(addr_arg), "%llu", + (unsigned long long)(uintptr_t)ram); + snprintf(size_arg, sizeof(size_arg), "%zu", size); + snprintf(kind_arg, sizeof(kind_arg), "%d", kind); + snprintf(stage_arg, sizeof(stage_arg), "%d", stage); + execl("/proc/self/exe", "doexec", "--exec", fd_arg, addr_arg, size_arg, + kind_arg, stage_arg, NULL); + ksft_print_msg("exec: %s\n", strerror(errno)); + _exit(KSFT_FAIL); +} + +static int after_exec(int fd, char *ram, size_t size, int kind, int stage) +{ + unsigned char before = stage == 1 ? 0x31 : 0x42; + unsigned char after = stage == 1 ? 0x42 : 0x53; + pid_t pid; + + if (check_pin(fd, ram, size, before)) + return KSFT_FAIL; + if (kind == PROTECTED && mprotect(ram, size, PROT_READ | PROT_WRITE)) + return KSFT_FAIL; + memset(ram, after, size); + if (check_pin(fd, ram, size, after)) + return KSFT_FAIL; + if (stage == 1) { + /* VM_EXEC_KEEP is consumed, so mark again for the second exec. */ + if (madvise(ram, size, MADV_DOEXEC)) + return KSFT_FAIL; + if (kind == PROTECTED && mprotect(ram, size, PROT_READ)) + return KSFT_FAIL; + exec_stage(fd, ram, size, kind, 2); + } + + /* Fork must copy into the child and retain the parent's pinned pages. */ + pid = fork(); + if (pid < 0) + return KSFT_FAIL; + if (!pid) { + memset(ram, 0x64, size); + _exit(KSFT_PASS); + } + if (wait_child(pid) || check_pin(fd, ram, size, after)) + return KSFT_FAIL; + memset(ram, 0x75, size); + if (check_pin(fd, ram, size, 0x75)) + return KSFT_FAIL; + return ioctl(fd, PIN_LONGTERM_TEST_STOP) ? KSFT_FAIL : KSFT_PASS; +} + +static size_t huge_page_size(void) +{ + FILE *file = fopen("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", "r"); + size_t size = 0; + + if (file) { + if (fscanf(file, "%zu", &size) != 1) + size = 0; + fclose(file); + } + return size; +} + +static int before_exec(int kind) +{ + size_t size = 16 * sysconf(_SC_PAGESIZE); + struct pin_longterm_test pin; + char *ram, *mapping; + uintptr_t aligned; + int fd; + + if (kind == HUGE) { + size = huge_page_size(); + if (!size) + return KSFT_SKIP; + } + fd = open("/sys/kernel/debug/gup_test", O_RDWR); + if (fd < 0) + return KSFT_SKIP; + mapping = mmap(NULL, 2 * size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (mapping == MAP_FAILED) + return KSFT_FAIL; + aligned = ((uintptr_t)mapping + size - 1) & ~(size - 1); + ram = (char *)aligned; + if (ram != mapping) + munmap(mapping, ram - mapping); + if (ram + size != mapping + 2 * size) + munmap(ram + size, mapping + 2 * size - (ram + size)); + if (madvise(ram, size, kind == HUGE ? MADV_HUGEPAGE : MADV_NOHUGEPAGE)) + return KSFT_FAIL; + memset(ram, 0x31, size); + if (kind == HUGE && madvise(ram, size, MADV_COLLAPSE)) + return KSFT_SKIP; + if (kind == LOCKED && mlock(ram, size)) + return KSFT_SKIP; + if (madvise(ram, size, MADV_DOEXEC)) { + ksft_print_msg("MADV_DOEXEC: %s\n", strerror(errno)); + return errno == EINVAL ? KSFT_SKIP : KSFT_FAIL; + } + pin = (struct pin_longterm_test) { + .addr = (uintptr_t)ram, + .size = size, + .flags = kind == READ_PIN ? 0 : PIN_LONGTERM_TEST_FLAG_USE_WRITE, + }; + if (kind == FAST_PIN) + pin.flags |= PIN_LONGTERM_TEST_FLAG_USE_FAST; + if (ioctl(fd, PIN_LONGTERM_TEST_START, &pin)) { + ksft_print_msg("pin: %s\n", strerror(errno)); + return errno == ENOTTY ? KSFT_SKIP : KSFT_FAIL; + } + if (kind == PROTECTED && mprotect(ram, size, PROT_READ)) + return KSFT_FAIL; + exec_stage(fd, ram, size, kind, 1); + return KSFT_FAIL; +} + +static int check_exec(char *ram, size_t size, size_t stride, bool reject) +{ + char addr_arg[32], size_arg[32], stride_arg[32]; + + snprintf(addr_arg, sizeof(addr_arg), "%llu", + (unsigned long long)(uintptr_t)ram); + snprintf(size_arg, sizeof(size_arg), "%zu", size); + snprintf(stride_arg, sizeof(stride_arg), "%zu", stride); + execl("/proc/self/exe", "doexec", reject ? "--reject" : "--check", addr_arg, size_arg, + stride_arg, NULL); + return errno; +} + +static char *preserved_ram(size_t size) +{ + char *ram = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (ram == MAP_FAILED) + return NULL; + memset(ram, 0x31, size); + if (madvise(ram, size, MADV_DOEXEC)) { + munmap(ram, size); + return NULL; + } + return ram; +} + +static int blocked_task(void *arg) +{ + int fd = *(int *)arg; + char ready; + + return read(fd, &ready, 1) == 1 ? KSFT_PASS : KSFT_FAIL; +} + +static void *blocked_thread(void *arg) +{ + blocked_task(arg); + return NULL; +} + +/* Own threads may be killed by exec; a separate CLONE_VM task may not. */ +static int shared_mm_exec(bool own_thread) +{ + size_t size = sysconf(_SC_PAGESIZE); + char *ram = preserved_ram(size), *stack; + int pipe_fd[2], ret; + pthread_t thread; + pid_t pid; + + if (!ram) + return errno == EINVAL ? KSFT_SKIP : KSFT_FAIL; + if (pipe(pipe_fd)) + return KSFT_FAIL; + if (own_thread) { + if (pthread_create(&thread, NULL, blocked_thread, &pipe_fd[0])) + return KSFT_FAIL; + check_exec(ram, size, 1, false); + write(pipe_fd[1], "x", 1); + pthread_join(thread, NULL); + return KSFT_FAIL; + } + stack = mmap(NULL, 65536, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (stack == MAP_FAILED) + return KSFT_FAIL; + pid = clone(blocked_task, stack + 65536, CLONE_VM | SIGCHLD, &pipe_fd[0]); + if (pid < 0) + return KSFT_FAIL; + ret = check_exec(ram, size, 1, true); + /* Exec must return EBUSY with the old mapping intact. */ + if (ret != EBUSY || check_bytes(ram, size, 0x31)) + ret = KSFT_FAIL; + else + ret = KSFT_PASS; + write(pipe_fd[1], "x", 1); + if (wait_child(pid)) + ret = KSFT_FAIL; + if (ret) + return ret; + /* Releasing the outside user must allow a retry. */ + check_exec(ram, size, 1, false); + return KSFT_FAIL; +} + +/* The caller must release its backend owner before preserving exec. */ +static int vhost_owner_exec(void) +{ + size_t size = sysconf(_SC_PAGESIZE); + char *ram; + int fd = open("/dev/vhost-net", O_RDWR); + + if (fd < 0) + return KSFT_SKIP; + ram = preserved_ram(size); + if (!ram) + return errno == EINVAL ? KSFT_SKIP : KSFT_FAIL; + if (ioctl(fd, VHOST_SET_OWNER)) + return KSFT_SKIP; + if (ioctl(fd, VHOST_RESET_OWNER)) + return KSFT_FAIL; + close(fd); + check_exec(ram, size, 1, false); + return KSFT_FAIL; +} + +static void *exec_thread(void *arg) +{ + check_exec(arg, sysconf(_SC_PAGESIZE), 1, false); + return NULL; +} + +static int nonleader_exec(void) +{ + char *ram = preserved_ram(sysconf(_SC_PAGESIZE)); + pthread_t thread; + + if (!ram) + return errno == EINVAL ? KSFT_SKIP : KSFT_FAIL; + if (pthread_create(&thread, NULL, exec_thread, ram)) + return KSFT_FAIL; + pthread_join(thread, NULL); + return KSFT_FAIL; +} + +static int proc_exec(char *ram, size_t size, int stage) +{ + char addr_arg[32], size_arg[32], stage_arg[32]; + + if (check_bytes(ram, size, 0x31)) + return KSFT_FAIL; + if (stage == 32) + return KSFT_PASS; + if (madvise(ram, size, MADV_DOEXEC)) + return KSFT_FAIL; + snprintf(addr_arg, sizeof(addr_arg), "%llu", + (unsigned long long)(uintptr_t)ram); + snprintf(size_arg, sizeof(size_arg), "%zu", size); + snprintf(stage_arg, sizeof(stage_arg), "%d", stage + 1); + execl("/proc/self/exe", "doexec", "--proc", addr_arg, size_arg, + stage_arg, NULL); + return KSFT_FAIL; +} + +/* Read both pre-opened and freshly opened proc files during repeated exec. */ +static int proc_readers_exec(void) +{ + static const char * const files[] = { "maps", "smaps_rollup", "pagemap" }; + int ready[2], go[2], fds[3] = { -1, -1, -1 }, status, ret = KSFT_FAIL; + char paths[3][80], buffer[4096]; + unsigned int round = 0; + pid_t pid, waited; + int i; + + if (pipe(ready) || pipe(go)) + return KSFT_FAIL; + pid = fork(); + if (pid < 0) + return KSFT_FAIL; + if (!pid) { + size_t size = 16 * sysconf(_SC_PAGESIZE); + char *ram = preserved_ram(size); + + close(ready[0]); + close(go[1]); + if (!ram) + _exit(errno == EINVAL ? KSFT_SKIP : KSFT_FAIL); + if (write(ready[1], "x", 1) != 1 || read(go[0], buffer, 1) != 1) + _exit(KSFT_FAIL); + close(ready[1]); + close(go[0]); + _exit(proc_exec(ram, size, 0)); + } + close(ready[1]); + close(go[0]); + if (read(ready[0], buffer, 1) != 1) { + close(ready[0]); + close(go[1]); + return wait_child(pid); + } + close(ready[0]); + for (i = 0; i < 3; i++) { + snprintf(paths[i], sizeof(paths[i]), "/proc/%d/%s", pid, files[i]); + fds[i] = open(paths[i], O_RDONLY); + if (fds[i] < 0) { + ret = KSFT_SKIP; + goto stop; + } + } + if (write(go[1], "x", 1) != 1) + goto stop; + close(go[1]); + go[1] = -1; + for (;;) { + waited = waitpid(pid, &status, WNOHANG); + if (waited == pid) { + ret = WIFEXITED(status) ? WEXITSTATUS(status) : KSFT_FAIL; + break; + } + if (waited < 0 && errno != EINTR) + break; + for (i = 0; i < 3; i++) { + lseek(fds[i], 0, SEEK_SET); + if (read(fds[i], buffer, sizeof(buffer)) < 0 && + errno != EINTR && errno != ESRCH) + goto stop; + } + /* Keep two old handles while refreshing the third. */ + i = round++ % 3; + close(fds[i]); + fds[i] = open(paths[i], O_RDONLY); + if (fds[i] < 0) { + ret = wait_child(pid); + break; + } + } + for (i = 0; i < 3; i++) + if (fds[i] >= 0) + close(fds[i]); + return ret; +stop: + if (go[1] >= 0) + close(go[1]); + kill(pid, SIGKILL); + wait_child(pid); + for (i = 0; i < 3; i++) + if (fds[i] >= 0) + close(fds[i]); + return ret; +} + +struct clone_race { + char *ram; + int report; + atomic_bool stop; + atomic_uint rounds; +}; + +static int clone_race_child(void *arg) +{ + struct clone_race *race = arg; + unsigned int i; + + for (i = 0; i < 8; i++) { + if (__atomic_load_n(race->ram, __ATOMIC_RELAXED) != 0x31) { + write(race->report, "x", 1); + return KSFT_FAIL; + } + usleep(1000); + } + return KSFT_PASS; +} + +static void *clone_race_thread(void *arg) +{ + struct clone_race *race = arg; + char *stack = mmap(NULL, 65536, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + pid_t pid; + + if (stack == MAP_FAILED) { + write(race->report, "x", 1); + atomic_store(&race->rounds, 4); + return NULL; + } + while (!atomic_load(&race->stop)) { + pid = clone(clone_race_child, stack + 65536, + CLONE_VM | SIGCHLD, race); + if (pid >= 0) { + if (wait_child(pid)) + write(race->report, "x", 1); + } else if (errno != EBUSY && errno != EINTR) { + write(race->report, "x", 1); + } + atomic_fetch_add(&race->rounds, 1); + usleep(1000); + } + munmap(stack, 65536); + return NULL; +} + +/* A supervisor collects errors from any shared-mm child surviving exec. */ +static int clone_exec_race(void) +{ + int report[2], ret; + struct pollfd pfd; + char failed; + pid_t pid; + + if (pipe(report)) + return KSFT_FAIL; + pid = fork(); + if (pid < 0) + return KSFT_FAIL; + if (!pid) { + size_t size = sysconf(_SC_PAGESIZE); + struct clone_race race = { .report = report[1] }; + pthread_t thread; + unsigned int attempt; + + close(report[0]); + race.ram = preserved_ram(size); + if (!race.ram) + _exit(errno == EINVAL ? KSFT_SKIP : KSFT_FAIL); + if (pthread_create(&thread, NULL, clone_race_thread, &race)) + _exit(KSFT_FAIL); + while (atomic_load(&race.rounds) < 4) + usleep(1000); + for (attempt = 0; attempt < 500; attempt++) { + if (check_exec(race.ram, size, 1, false) != EBUSY) + break; + if (check_bytes(race.ram, size, 0x31)) + break; + usleep(1000); + } + atomic_store(&race.stop, true); + pthread_join(thread, NULL); + _exit(KSFT_FAIL); + } + close(report[1]); + ret = wait_child(pid); + pfd = (struct pollfd) { .fd = report[0], .events = POLLIN | POLLHUP }; + if (poll(&pfd, 1, 3000) <= 0 || read(report[0], &failed, 1) != 0) + ret = KSFT_FAIL; + close(report[0]); + return ret; +} + +/* Opt-in sweep of allocation failures, using only the child's fail-nth. */ +static int allocation_failures(void) +{ + const size_t size = 256ul << 20, stride = 2ul << 20; + struct rlimit no_core = { 0, 0 }; + unsigned int early = 0, fatal = 0, success = 0, loader = 0; + unsigned int nth; + pid_t pid; + int status; + pid_t waited; + + if (!getenv("DOEXEC_FAULT_INJECTION") || access("/proc/self/fail-nth", W_OK)) + return KSFT_SKIP; + for (nth = 1; nth <= 256; nth++) { + pid = fork(); + if (pid < 0) + return KSFT_FAIL; + if (!pid) { + char *ram, number[32]; + size_t i; + int fd, len, err; + + setrlimit(RLIMIT_CORE, &no_core); + ram = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ram == MAP_FAILED || madvise(ram, size, MADV_NOHUGEPAGE)) + _exit(KSFT_FAIL); + for (i = 0; i < size; i += stride) + ram[i] = 0x31; + if (madvise(ram, size, MADV_DOEXEC)) + _exit(errno == EINVAL ? KSFT_SKIP : KSFT_FAIL); + fd = open("/proc/self/fail-nth", O_WRONLY | O_CLOEXEC); + len = snprintf(number, sizeof(number), "%u", nth); + if (fd < 0 || write(fd, number, len) != len) + _exit(KSFT_FAIL); + err = check_exec(ram, size, stride, false); + /* Disarm before checking mappings or exiting. */ + pwrite(fd, "0", 1, 0); + for (i = 0; i < size; i += stride) + if (ram[i] != 0x31) + _exit(KSFT_FAIL); + _exit(err == ENOMEM || err == EFAULT || err == EAGAIN ? 10 : KSFT_FAIL); + } + do { + waited = waitpid(pid, &status, 0); + } while (waited < 0 && errno == EINTR); + if (waited < 0) + return KSFT_FAIL; + if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) + fatal++; + else if (WIFEXITED(status) && WEXITSTATUS(status) == 10) + early++; + else if (WIFEXITED(status) && WEXITSTATUS(status) == KSFT_PASS) + success++; + /* A dynamic loader may exit when a post-exec allocation fails. */ + else if (WIFEXITED(status) && WEXITSTATUS(status) == 127) + loader++; + else if (WIFEXITED(status) && WEXITSTATUS(status) == KSFT_SKIP) + return KSFT_SKIP; + else + return KSFT_FAIL; + } + ksft_print_msg("faults: %u recoverable, %u SIGSEGV, %u success, %u loader exits\n", + early, fatal, success, loader); + /* A sweep that injected no recoverable/fatal errors provides no coverage. */ + return early && fatal ? KSFT_PASS : KSFT_SKIP; +} + +int main(int argc, char **argv) +{ + pid_t pid; + int kind, ret; + + if (argc == 7 && !strcmp(argv[1], "--exec")) + return after_exec(atoi(argv[2]), + (char *)(uintptr_t)strtoull(argv[3], NULL, 10), + strtoull(argv[4], NULL, 10), atoi(argv[5]), atoi(argv[6])); + if (argc == 6 && !strcmp(argv[1], "--cow")) + return after_cow_exec((char *)(uintptr_t)strtoull(argv[2], NULL, 10), + strtoull(argv[3], NULL, 10), atoi(argv[4]), atoi(argv[5])); + if (argc == 5 && !strcmp(argv[1], "--reject")) + return KSFT_FAIL; + if (argc == 5 && !strcmp(argv[1], "--proc")) + return proc_exec((char *)(uintptr_t)strtoull(argv[2], NULL, 10), + strtoull(argv[3], NULL, 10), atoi(argv[4])); + if (argc == 5 && !strcmp(argv[1], "--check")) { + char *ram = (char *)(uintptr_t)strtoull(argv[2], NULL, 10); + size_t size = strtoull(argv[3], NULL, 10); + size_t stride = strtoull(argv[4], NULL, 10), i; + int fd = open("/proc/self/fail-nth", O_WRONLY); + + if (fd >= 0) { + write(fd, "0", 1); + close(fd); + } + for (i = 0; i < size; i += stride) + if (ram[i] != 0x31) + return KSFT_FAIL; + return KSFT_PASS; + } + ksft_print_header(); + ksft_set_plan(NR_TESTS + 8); + for (kind = 0; kind < NR_TESTS; kind++) { + fflush(stdout); + pid = fork(); + if (!pid) + _exit(before_exec(kind)); + ret = pid < 0 ? KSFT_FAIL : wait_child(pid); + if (ret == KSFT_SKIP) + ksft_test_result_skip("%s: DOEXEC, GUP test or mapping unavailable\n", + names[kind]); + else + ksft_test_result(ret == KSFT_PASS, "%s: repeated exec and fork\n", + names[kind]); + } + fflush(stdout); + pid = fork(); + if (!pid) + _exit(before_cow_exec()); + ret = pid < 0 ? KSFT_FAIL : wait_child(pid); + if (ret == KSFT_SKIP) + ksft_test_result_skip("pre-existing COW: DOEXEC unavailable\n"); + else + ksft_test_result(ret == KSFT_PASS, "pre-existing COW preserved\n"); + for (kind = 0; kind < 7; kind++) { + static const char * const extra_names[] = { + "CLONE_VM: recoverable EBUSY and retry", + "own threads: preserving exec allowed", + "vhost owner: reset before preserving exec", + "allocation failure sweep (opt-in)", + "non-leader thread: preserving exec allowed", + "proc readers: repeated preserving exec allowed", + "concurrent CLONE_VM: shared memory is not stolen", + }; + + fflush(stdout); + pid = fork(); + if (!pid) { + switch (kind) { + case 0: + case 1: + _exit(shared_mm_exec(kind)); + case 2: + _exit(vhost_owner_exec()); + case 3: + _exit(allocation_failures()); + case 4: + _exit(nonleader_exec()); + case 5: + _exit(proc_readers_exec()); + case 6: + _exit(clone_exec_race()); + } + } + ret = pid < 0 ? KSFT_FAIL : wait_child(pid); + if (ret == KSFT_SKIP) + ksft_test_result_skip("%s: unavailable or disabled\n", extra_names[kind]); + else + ksft_test_result(ret == KSFT_PASS, "%s\n", extra_names[kind]); + } + ksft_finished(); +} diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh index 6ac8ba7e2447..9643b39762b8 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -296,6 +296,7 @@ fi # Dump pages 0, 19, and 4096, using pin_user_pages: CATEGORY="gup_test" run_test ./gup_test -ct -F 0x1 0 19 0x1000 CATEGORY="gup_test" run_test ./gup_longterm +CATEGORY="gup_test" run_test ./doexec CATEGORY="userfaultfd" run_test ./uffd-unit-tests uffd_stress_bin=./uffd-stress -- 2.47.1 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel