From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753249AbdA3Mll (ORCPT ); Mon, 30 Jan 2017 07:41:41 -0500 Received: from mail-ve1eur01on0090.outbound.protection.outlook.com ([104.47.1.90]:59136 "EHLO EUR01-VE1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753209AbdA3MlY (ORCPT ); Mon, 30 Jan 2017 07:41:24 -0500 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=dsafonov@virtuozzo.com; From: Dmitry Safonov To: CC: <0x7f454c46@gmail.com>, Dmitry Safonov , "Thomas Gleixner" , Ingo Molnar , "H. Peter Anvin" , Andy Lutomirski , Borislav Petkov , , , Shuah Khan , Subject: [PATCHv4 5/5] selftests/x86: add test to check compat mmap() return addr Date: Mon, 30 Jan 2017 15:04:32 +0300 Message-ID: <20170130120432.6716-6-dsafonov@virtuozzo.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170130120432.6716-1-dsafonov@virtuozzo.com> References: <20170130120432.6716-1-dsafonov@virtuozzo.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [195.214.232.6] X-ClientProxiedBy: VI1P194CA0011.EURP194.PROD.OUTLOOK.COM (10.175.178.21) To HE1PR0801MB1740.eurprd08.prod.outlook.com (10.168.150.7) X-MS-Office365-Filtering-Correlation-Id: ab50f39d-4aae-475f-99fc-08d449083641 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001);SRVR:HE1PR0801MB1740; X-Microsoft-Exchange-Diagnostics: 1;HE1PR0801MB1740;3:jGxyo9GjXXuR/HW5sKkUCBgQ2qiKAx6ipEIF33nNO9wUkswHFccuIrOfy6q9CccU2fA1B3dwpqO8mGMN4Ur94GJiSIgkHzw6WZvIo2qvBFGO65TZXTi9wiP6gGpQZiQ/1wVdE9Ic2WIEy4IPOmx8vGXgncItsuLQxV4PTvpcMdawjnAPrlW7xR5hELP8FsY/jMaqVPoxfjIuL311jrwCYBdf3F7Ju4Y817D1QI01aXYPljU4k5C4QeS7/4zab4oI0jLfZEgO2sHrLB3cpPeUIg==;25:J5GvtPQf8bof4IbZPZ1Eza1z4ljgucecKplmqcTWJG5GoF/ty9DXmZlpASXQQLRO6IHzEL5xSgbuO6d/LRm4YQvrZU2ThKpwEuSgbtDfkdzC/jnP8G1rWfyPmi49YqvlB1UJSKEWULdeHrUd/BvPtANIcMRt1Xz3uwMhIut3CqQMJBqW088tAhg5V3S6eEYJkC/fGzlDpKQWspJIyEH1yEBE8HuRJUbtiW+E5dNdronCNHT8tOwMneDvK06COGBsZ/mHTdFnRi8ppykE8pGlbBzturSrtXdKKxFtDhwUenfEj4z7d7oYk/qComjj+L6jeQR4ivK6SfXUVs8XjiNlZa+ZilvSfkKTCcI7CkRubPlKxI8DaxoqRg2J2j6Yb5iv9fTZdOdpEMC+n3vKqurCfP4K8b+R7eV74a2W4G5YNWGHyLYMnftiSRhIJPSABkNiE1mUmQhs1SOM3cmfI8QNqQ== X-Microsoft-Exchange-Diagnostics: 1;HE1PR0801MB1740;31:dl+KNI0PzpOD2yJ8gJbFwNdmuT5fz30LIopQIrCbgvh2WmdY1EJcM/EfVb88SgYtFgfTJs2cdgFWIV8jVJ/XDauSRfco9AbRxNbwlL3pSKVZ8ls1QADYUZqPKVlPriV7fo5RRVtEFODDPIDMAwmgyJtNU56sWOJ3fZUPWSnYnLFA6DiPVopxzyk7ySUJMHclilLsncI4uJFfFHoOiVCrcSUjayLxjMQJ75QXPpbqmg3QVI2fNd4uY7pYZLBXFiHe;20:Q7ISfNW3FiinwKmOSFthnhiQm3JBkGuSa0m80POa+WXbniRszlPX2EyA2nuBeNue/H3gnBYmHQqwhSA9y2XQ+JEOGZCMs0uJPXWbqkZIFCORYBPs34nl5jGaDtFgOUov70rKjJ9aZNdbTMx52c1vms9ohHudAsbwQ1Q4xQgAVNMZdx4CEr1rnG6RBGil1k+fzmACs2WDwKpIC2Zev/mek0AqglZt9aISJ9A20539BcnWbBpzl0ThbF24B4QGdjZk X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(9452136761055); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040375)(601004)(2401047)(5005006)(8121501046)(10201501046)(3002001)(6041248)(20161123564025)(20161123555025)(20161123562025)(20161123560025)(20161123558021)(6072148);SRVR:HE1PR0801MB1740;BCL:0;PCL:0;RULEID:;SRVR:HE1PR0801MB1740; X-Microsoft-Exchange-Diagnostics: 1;HE1PR0801MB1740;4:67fNI3SNoQFhtRyo5L31pSHBHud3tKpFLDIkZkNzpOmAL743RBDkdFVCTsBbFDgMKYr0V0NdOxlPSgW+MpX4gj4SgLDMwrfrNDhMSDEPnqG5T+0/HCMQ3fBeNNXpOE89e8iag3ZFq40tGAZkaGHLP2v8pT+pls1x6em35Oup8K+OG31QpfXLlpMQ05+PMhBnKMUrhBbV7Wb1nwpmQUCKVGLu88O6wg3JZgj1aj9PLhPwFf6gY5xloE6zyYcIMVSg3p54vjEfcJ4FwuJdlrJijrO02KffnwFC9080aEX1Eav14jGSTHaymq71Ft9OF19pDPEY0AJ0ME8/sQ1MChPnw1FcE1kPGzGlcvB4vrr4G1uvd9Ea9YF3Y/sUl0PYLLbMh1S8S9EOGgCJqYr5OUF64udC683I+ELVy1vy2w7CEDa7lVSYz9/LN9wkjS3QVU8UjWuCxxiNjVoktgVaBndGkT9ifldhN4fWPWlLVcHrxwTKer2krihlZtX5SiLLj31WZHHXfPRyZ1WmXf2xqzrG4xLoUvsKNMKq/j68jaMNNlXKh5UzuOKDvW9WbODoVhQKO4Rwz9cQ4A1HkRy1IvFtqDrmK6xt7aabF71HXpMlMmAE0WC6h91LNC+nnoeu5Fk0g0yoX0zq9DT+hiOkVdzWHg== X-Forefront-PRVS: 0203C93D51 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(6009001)(7916002)(39450400003)(199003)(189002)(7736002)(92566002)(189998001)(110136003)(53936002)(33646002)(4326007)(39060400001)(1076002)(53416004)(38730400001)(68736007)(97736004)(5003940100001)(6486002)(8676002)(305945005)(2906002)(6666003)(105586002)(50466002)(6506006)(6916009)(2950100002)(48376002)(106356001)(69596002)(86362001)(50986999)(47776003)(54906002)(6512007)(36756003)(76176999)(66066001)(2351001)(42186005)(81166006)(3846002)(6116002)(81156014)(25786008)(50226002)(101416001)(5660300001)(7416002)(2004002);DIR:OUT;SFP:1102;SCL:1;SRVR:HE1PR0801MB1740;H:dsafonov.sw.ru;FPR:;SPF:None;PTR:InfoNoRecords;A:1;MX:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;HE1PR0801MB1740;23:EyRQ6ksc61P0v6wXbjYyWJVkOZ2A6LYV7yGQjBA?= =?us-ascii?Q?xeCl4iEnP0MogXVndL74yp4rjYk/3QGXJNXTGy9lgujubrd/epY635htWZmI?= =?us-ascii?Q?3wmT8YuSZ1DT9RVnjZsSv6uixb9RiIIYolYliOS4mVBbh4O/d+aPun9RXsLH?= =?us-ascii?Q?sWM+5S8iNGZM2cWo6FNeyyEqrHc+TPlr5Ffy52DaYvhQN8y7YNT5rM43psk1?= =?us-ascii?Q?cccuRrDOVXHkiNhyhV8h6lHMIpgfiOhcLzeAdwZY1QkebeStGuPJsb50nIhn?= =?us-ascii?Q?hThVJ0nF/Q/C1Vjk58Xgl+jYShv+8bPSlA6tPOUFudbRxSbV/w9LqaEcPux0?= =?us-ascii?Q?CI11uxfUNR5wvjRoaE4npxFu7Lxc+tSzNpN061oOjjYTfXkoJooxGsdcE8l+?= =?us-ascii?Q?68xGSau4YYI3PkdJOzEwfTjE0NbH/ceZU2syGD8X95qjXN38atAWHt5HIEVY?= =?us-ascii?Q?KrvmNKcBvDaF86CGKZM5hJSfAWdwssMoqZhBqIql+8R0j4Jq4Mu550E44XBx?= =?us-ascii?Q?wwrqkA+B1CCs0/odEcjVsmUGXgCGPQmSZC3UYXgqSSzhP4RSnVtdb8f9xLj3?= =?us-ascii?Q?NlqtzHbixODElMqc3N9h7auCBDPZA3NO8XzHXdVFJjbufhtZjPRozZ+Az4ib?= =?us-ascii?Q?/u591aXS9dBc+s3lKwaEwU1QNUxXhBECEJtittj/9DEAuAd4g7RE6TTkDlI2?= =?us-ascii?Q?Zbm+grYwlZ4KEIgwNok8uyJv5RI0T63RJJr1rv8yLS2C1xQar1QO8nDA+i+A?= =?us-ascii?Q?xw9vsrdiPsHc2j4DqrHGBUBcTFyn1eFnOmML3ig2Iqx6MdUYQ9B+R3+cVxhD?= =?us-ascii?Q?Mu12Z0R9DDj6xkTPInNJJ4aseOUQgNg2sUWz6ZYy7lj5MHZda68qE6vYBmj1?= =?us-ascii?Q?0eK0n5fmK+z6A5t9Wwukm6JAg/kzTzlv0ZqF9JJClvek81xDJT9lkRFvMoQo?= =?us-ascii?Q?KBqKU1fKIsIb3uNrCkQ+oBtiwXMkt5EOzK0fW2R/sjnkn/8PSQgURdFdUrDz?= =?us-ascii?Q?1lcZwarXYe0coVydebXhuutgIykSdf2TsJ6cETSrX1VqXKFk1KOZ3BhD9Und?= =?us-ascii?Q?hKz+yhx+PrlC9S3KDdkL+plER7GJqe1U9yvS79eZZB7X512Y3Eo/CepZNMNC?= =?us-ascii?Q?8LoJd/QwpCWlPcPEhnjDLLSyWIz5kWZaX+uybk4bL60SIU2YinBMPoiDF2ip?= =?us-ascii?Q?CSXbJ9xICqLaEWWIB+SHn6gRoLXV47uPATPlT2OKFCKvPaGtk7hHSrWliYWQ?= =?us-ascii?Q?VtmUAJId/XvlN75+b9WoNpC4NgvaGhQjbjOm15qkN?= X-Microsoft-Exchange-Diagnostics: 1;HE1PR0801MB1740;6:Xub1XqCAIvZZdYRa4pgesGPmfwwUy8L5hbZeof4h4v5OcJo1KrviZnvOwYdyTaP5qGFmP76Vxs830VFI+tOYXsqK5m34OlznwYx4Jby+ssiEU3PqYctoXgoChJoMWElXgoDZty83OyslaQxHch+r00yegYrUqY7V/Qj5XHypeVQcvJAkSr9szAYMD6ATpY5fYVf92bPm3rsLfghYUpfQpkwNDc5WrFBeVPSGFJlZus9uWybpQVdFytKQntR/oPCgFjWCC/hPd9gfmHc63DQSJPWohM7r6XjO2FfocLNg65y5QTsv+HsaJPN3KMj5bVh/Lwv/XgFb4c4Wo1vaCO6PfXRtvlIWgAVP9UQ+e++OWFc7CIs4cdNDzUmSH8v+5a9McS4fPoXTb6m6UW1d3vIqziGQtOg5DzW3gAJra3uYAYc=;5:4jUerIjpFirfoKolRY/1sGFh/F6bCWD36v70ais4wgbRSUZhHq06SBLQb8ECUdc2RTenhWLgTHd+vFEEmU35LCk//aRMXQwUbQJGW6mbrGFu/qk2t84JUGLATdtPv/0FISj5Q+MPFYq+XXcrJdxE9vxhJNyo0g1zBNWcFhNt55U=;24:Onm81GPunoWXIEjclaTVjvBSKZ2wSlFT/8qatHS32vpik02gXXrMInCh2QajUC2WPD+qxC+RfEcmEe/qvMK9ZzhBiV8ksKnoT/Feh2pxT9I= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;HE1PR0801MB1740;7:uLrRXJTrV2BVtkN7oKxiXzWYZ417xBifjxiG9o6a88WmJHowx8SfXdl8YQh9I+BZreZsIvlZvSp2/n4fmdCBKn6sdOx+fCk1pwt7keU+z5/oEC0GGnNV48Kcdbm3Ic7c9WMDzHLbSLVq7MLNmvzkxvrXAqtqsKgEZ/ZbwJHAE7YJulWWwBciOva1PpDeSy0TOqjbyJB+0ZRlxhZoD6qTae+yetZObM0clbZPyP4ZkuiwGIdI9trwOl5LOO0W92Njqu6hkcJ/29ioGMfJLluesXOdbT1MRCJs+sBNFYPt9pAVYoBPZGcW/lQjWUJfJJizsK2N+yy2V7AnBGQomaSzFTGYdJSkMDpvrrXRBp4DFwajV/AgI6poP/YyM5CZbCOEgU8Mb2iTBUODav4GHVCgtPcSKRXXr0f1/8cFUtRl1ZMD0D4w04YrKZFvPURPzzmQNoYBlklEqSwJMh/B1ydz8g==;20:xSZtjiWelfACLRkMoDRVpd3thFrHvv03gvJp8QzfwoudQMxxsySCk+x6nHDWXd/JkQWUFcwEYrgcR4Xs+U+/fwCTBD3Z/gB0ACHqV4yQNFWGqm+BNfthGXiISYVBgwXao5/T8UNShWRe61ep9IpGQvJmSo/dxJMbKUjy3EI0cdw= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Jan 2017 12:04:57.1396 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: HE1PR0801MB1740 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org We can't just add segfault handler and use addr, returned by compat mmap() syscall, because the lower 4 bytes can be the same as already existed VMA. So, the test parses /proc/self/maps file, founds new VMAs those appeared after compatible sys_mmap() and checks if mmaped VMA is in that list. On failure it prints: [NOTE] Allocated mmap 0x6f36a000, sized 0x400000 [NOTE] New mapping appeared: 0x7f936f36a000 [FAIL] Found VMA [0x7f936f36a000, 0x7f936f76a000] in maps file, that was allocated with compat syscall Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: Dmitry Safonov --- tools/testing/selftests/x86/Makefile | 2 +- tools/testing/selftests/x86/test_compat_mmap.c | 208 +++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/test_compat_mmap.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 8c1cb423cfe6..9c3e746a6064 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -10,7 +10,7 @@ TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_sysc TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer -TARGETS_C_64BIT_ONLY := fsgsbase +TARGETS_C_64BIT_ONLY := fsgsbase test_compat_mmap TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) diff --git a/tools/testing/selftests/x86/test_compat_mmap.c b/tools/testing/selftests/x86/test_compat_mmap.c new file mode 100644 index 000000000000..245d9407653e --- /dev/null +++ b/tools/testing/selftests/x86/test_compat_mmap.c @@ -0,0 +1,208 @@ +/* + * Check that compat 32-bit mmap() returns address < 4Gb on 64-bit. + * + * Copyright (c) 2017 Dmitry Safonov (Virtuozzo) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include + +#include +#include +#include +#include +#include + +#define PAGE_SIZE 4096 +#define MMAP_SIZE (PAGE_SIZE*1024) +#define MAX_VMAS 50 +#define BUF_SIZE 1024 + +#ifndef __NR32_mmap2 +#define __NR32_mmap2 192 +#endif + +struct syscall_args32 { + uint32_t nr, arg0, arg1, arg2, arg3, arg4, arg5; +}; + +static void do_full_int80(struct syscall_args32 *args) +{ + asm volatile ("int $0x80" + : "+a" (args->nr), + "+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2), + "+S" (args->arg3), "+D" (args->arg4), + "+rbp" (args->arg5) + : : "r8", "r9", "r10", "r11"); +} + +void *mmap2(void *addr, size_t len, int prot, int flags, + int fildes, off_t off) +{ + struct syscall_args32 s; + + s.nr = __NR32_mmap2; + s.arg0 = (uint32_t)(uintptr_t)addr; + s.arg1 = (uint32_t)len; + s.arg2 = prot; + s.arg3 = flags; + s.arg4 = fildes; + s.arg5 = (uint32_t)off; + + do_full_int80(&s); + + return (void *)(uintptr_t)s.nr; +} + +struct vm_area { + unsigned long start; + unsigned long end; +}; + +static struct vm_area vmas_before_mmap[MAX_VMAS]; +static struct vm_area vmas_after_mmap[MAX_VMAS]; + +static char buf[BUF_SIZE]; + +int parse_maps(struct vm_area *vmas) +{ + FILE *maps; + int i; + + maps = fopen("/proc/self/maps", "r"); + if (maps == NULL) { + printf("[ERROR]\tFailed to open maps file: %m\n"); + return -1; + } + + for (i = 0; i < MAX_VMAS; i++) { + struct vm_area *v = &vmas[i]; + char *end; + + if (fgets(buf, BUF_SIZE, maps) == NULL) + break; + + v->start = strtoul(buf, &end, 16); + v->end = strtoul(end + 1, NULL, 16); + //printf("[NOTE]\tVMA: [%#lx, %#lx]\n", v->start, v->end); + } + + if (i == MAX_VMAS) { + printf("[ERROR]\tNumber of VMAs is bigger than reserved array's size\n"); + return -1; + } + + if (fclose(maps)) { + printf("[ERROR]\tFailed to close maps file: %m\n"); + return -1; + } + return 0; +} + +int compare_vmas(struct vm_area *vmax, struct vm_area *vmay) +{ + if (vmax->start > vmay->start) + return 1; + if (vmax->start < vmay->start) + return -1; + if (vmax->end > vmay->end) + return 1; + if (vmax->end < vmay->end) + return -1; + return 0; +} + +unsigned long vma_size(struct vm_area *v) +{ + return v->end - v->start; +} + +int find_new_vma_like(struct vm_area *vma) +{ + int i, j = 0, found_alike = -1; + + for (i = 0; i < MAX_VMAS && j < MAX_VMAS; i++, j++) { + int cmp = compare_vmas(&vmas_before_mmap[i], + &vmas_after_mmap[j]); + + if (cmp == 0) + continue; + if (cmp < 0) {/* Lost mapping */ + printf("[NOTE]\tLost mapping: %#lx\n", + vmas_before_mmap[i].start); + j--; + continue; + } + + printf("[NOTE]\tNew mapping appeared: %#lx\n", + vmas_after_mmap[j].start); + i--; + if (!compare_vmas(&vmas_after_mmap[j], vma)) + return 0; + + if (((vmas_after_mmap[j].start & 0xffffffff) == vma->start) && + (vma_size(&vmas_after_mmap[j]) == vma_size(vma))) + found_alike = j; + } + + /* Left new vmas in tail */ + for (; i < MAX_VMAS; i++) + if (!compare_vmas(&vmas_after_mmap[j], vma)) + return 0; + + if (found_alike != -1) { + printf("[FAIL]\tFound VMA [%#lx, %#lx] in maps file, that was allocated with compat syscall\n", + vmas_after_mmap[found_alike].start, + vmas_after_mmap[found_alike].end); + return -1; + } + + printf("[ERROR]\tCan't find [%#lx, %#lx] in maps file\n", + vma->start, vma->end); + return -1; +} + +int main(int argc, char **argv) +{ + void *map; + struct vm_area vma; + + if (parse_maps(vmas_before_mmap)) { + printf("[ERROR]\tFailed to parse maps file\n"); + return 1; + } + + map = mmap2(0, MMAP_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (((uintptr_t)map) % PAGE_SIZE) { + printf("[ERROR]\tmmap2 failed: %d\n", + (~(uint32_t)(uintptr_t)map) + 1); + return 1; + } else { + printf("[NOTE]\tAllocated mmap %p, sized %#x\n", map, MMAP_SIZE); + } + + if (parse_maps(vmas_after_mmap)) { + printf("[ERROR]\tFailed to parse maps file\n"); + return 1; + } + + munmap(map, MMAP_SIZE); + + vma.start = (unsigned long)(uintptr_t)map; + vma.end = vma.start + MMAP_SIZE; + if (find_new_vma_like(&vma)) + return 1; + + printf("[OK]\n"); + + return 0; +} -- 2.11.0 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-oi0-f71.google.com (mail-oi0-f71.google.com [209.85.218.71]) by kanga.kvack.org (Postfix) with ESMTP id D3BFA6B026C for ; Mon, 30 Jan 2017 07:05:02 -0500 (EST) Received: by mail-oi0-f71.google.com with SMTP id u143so369516567oif.1 for ; Mon, 30 Jan 2017 04:05:02 -0800 (PST) Received: from EUR03-DB5-obe.outbound.protection.outlook.com (mail-eopbgr40101.outbound.protection.outlook.com. [40.107.4.101]) by mx.google.com with ESMTPS id j4si5335254ote.30.2017.01.30.04.05.01 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 30 Jan 2017 04:05:01 -0800 (PST) From: Dmitry Safonov Subject: [PATCHv4 5/5] selftests/x86: add test to check compat mmap() return addr Date: Mon, 30 Jan 2017 15:04:32 +0300 Message-ID: <20170130120432.6716-6-dsafonov@virtuozzo.com> In-Reply-To: <20170130120432.6716-1-dsafonov@virtuozzo.com> References: <20170130120432.6716-1-dsafonov@virtuozzo.com> MIME-Version: 1.0 Content-Type: text/plain Sender: owner-linux-mm@kvack.org List-ID: To: linux-kernel@vger.kernel.org Cc: 0x7f454c46@gmail.com, Dmitry Safonov , Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , Andy Lutomirski , Borislav Petkov , x86@kernel.org, linux-mm@kvack.org, Shuah Khan , linux-kselftest@vger.kernel.org We can't just add segfault handler and use addr, returned by compat mmap() syscall, because the lower 4 bytes can be the same as already existed VMA. So, the test parses /proc/self/maps file, founds new VMAs those appeared after compatible sys_mmap() and checks if mmaped VMA is in that list. On failure it prints: [NOTE] Allocated mmap 0x6f36a000, sized 0x400000 [NOTE] New mapping appeared: 0x7f936f36a000 [FAIL] Found VMA [0x7f936f36a000, 0x7f936f76a000] in maps file, that was allocated with compat syscall Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: Dmitry Safonov --- tools/testing/selftests/x86/Makefile | 2 +- tools/testing/selftests/x86/test_compat_mmap.c | 208 +++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/test_compat_mmap.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 8c1cb423cfe6..9c3e746a6064 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -10,7 +10,7 @@ TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_sysc TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer -TARGETS_C_64BIT_ONLY := fsgsbase +TARGETS_C_64BIT_ONLY := fsgsbase test_compat_mmap TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) diff --git a/tools/testing/selftests/x86/test_compat_mmap.c b/tools/testing/selftests/x86/test_compat_mmap.c new file mode 100644 index 000000000000..245d9407653e --- /dev/null +++ b/tools/testing/selftests/x86/test_compat_mmap.c @@ -0,0 +1,208 @@ +/* + * Check that compat 32-bit mmap() returns address < 4Gb on 64-bit. + * + * Copyright (c) 2017 Dmitry Safonov (Virtuozzo) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include + +#include +#include +#include +#include +#include + +#define PAGE_SIZE 4096 +#define MMAP_SIZE (PAGE_SIZE*1024) +#define MAX_VMAS 50 +#define BUF_SIZE 1024 + +#ifndef __NR32_mmap2 +#define __NR32_mmap2 192 +#endif + +struct syscall_args32 { + uint32_t nr, arg0, arg1, arg2, arg3, arg4, arg5; +}; + +static void do_full_int80(struct syscall_args32 *args) +{ + asm volatile ("int $0x80" + : "+a" (args->nr), + "+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2), + "+S" (args->arg3), "+D" (args->arg4), + "+rbp" (args->arg5) + : : "r8", "r9", "r10", "r11"); +} + +void *mmap2(void *addr, size_t len, int prot, int flags, + int fildes, off_t off) +{ + struct syscall_args32 s; + + s.nr = __NR32_mmap2; + s.arg0 = (uint32_t)(uintptr_t)addr; + s.arg1 = (uint32_t)len; + s.arg2 = prot; + s.arg3 = flags; + s.arg4 = fildes; + s.arg5 = (uint32_t)off; + + do_full_int80(&s); + + return (void *)(uintptr_t)s.nr; +} + +struct vm_area { + unsigned long start; + unsigned long end; +}; + +static struct vm_area vmas_before_mmap[MAX_VMAS]; +static struct vm_area vmas_after_mmap[MAX_VMAS]; + +static char buf[BUF_SIZE]; + +int parse_maps(struct vm_area *vmas) +{ + FILE *maps; + int i; + + maps = fopen("/proc/self/maps", "r"); + if (maps == NULL) { + printf("[ERROR]\tFailed to open maps file: %m\n"); + return -1; + } + + for (i = 0; i < MAX_VMAS; i++) { + struct vm_area *v = &vmas[i]; + char *end; + + if (fgets(buf, BUF_SIZE, maps) == NULL) + break; + + v->start = strtoul(buf, &end, 16); + v->end = strtoul(end + 1, NULL, 16); + //printf("[NOTE]\tVMA: [%#lx, %#lx]\n", v->start, v->end); + } + + if (i == MAX_VMAS) { + printf("[ERROR]\tNumber of VMAs is bigger than reserved array's size\n"); + return -1; + } + + if (fclose(maps)) { + printf("[ERROR]\tFailed to close maps file: %m\n"); + return -1; + } + return 0; +} + +int compare_vmas(struct vm_area *vmax, struct vm_area *vmay) +{ + if (vmax->start > vmay->start) + return 1; + if (vmax->start < vmay->start) + return -1; + if (vmax->end > vmay->end) + return 1; + if (vmax->end < vmay->end) + return -1; + return 0; +} + +unsigned long vma_size(struct vm_area *v) +{ + return v->end - v->start; +} + +int find_new_vma_like(struct vm_area *vma) +{ + int i, j = 0, found_alike = -1; + + for (i = 0; i < MAX_VMAS && j < MAX_VMAS; i++, j++) { + int cmp = compare_vmas(&vmas_before_mmap[i], + &vmas_after_mmap[j]); + + if (cmp == 0) + continue; + if (cmp < 0) {/* Lost mapping */ + printf("[NOTE]\tLost mapping: %#lx\n", + vmas_before_mmap[i].start); + j--; + continue; + } + + printf("[NOTE]\tNew mapping appeared: %#lx\n", + vmas_after_mmap[j].start); + i--; + if (!compare_vmas(&vmas_after_mmap[j], vma)) + return 0; + + if (((vmas_after_mmap[j].start & 0xffffffff) == vma->start) && + (vma_size(&vmas_after_mmap[j]) == vma_size(vma))) + found_alike = j; + } + + /* Left new vmas in tail */ + for (; i < MAX_VMAS; i++) + if (!compare_vmas(&vmas_after_mmap[j], vma)) + return 0; + + if (found_alike != -1) { + printf("[FAIL]\tFound VMA [%#lx, %#lx] in maps file, that was allocated with compat syscall\n", + vmas_after_mmap[found_alike].start, + vmas_after_mmap[found_alike].end); + return -1; + } + + printf("[ERROR]\tCan't find [%#lx, %#lx] in maps file\n", + vma->start, vma->end); + return -1; +} + +int main(int argc, char **argv) +{ + void *map; + struct vm_area vma; + + if (parse_maps(vmas_before_mmap)) { + printf("[ERROR]\tFailed to parse maps file\n"); + return 1; + } + + map = mmap2(0, MMAP_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (((uintptr_t)map) % PAGE_SIZE) { + printf("[ERROR]\tmmap2 failed: %d\n", + (~(uint32_t)(uintptr_t)map) + 1); + return 1; + } else { + printf("[NOTE]\tAllocated mmap %p, sized %#x\n", map, MMAP_SIZE); + } + + if (parse_maps(vmas_after_mmap)) { + printf("[ERROR]\tFailed to parse maps file\n"); + return 1; + } + + munmap(map, MMAP_SIZE); + + vma.start = (unsigned long)(uintptr_t)map; + vma.end = vma.start + MMAP_SIZE; + if (find_new_vma_like(&vma)) + return 1; + + printf("[OK]\n"); + + return 0; +} -- 2.11.0 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: email@kvack.org