/* * Copyright (c) 2017 Richard Palethorpe * Copyright (c) 2017 Fujitsu Ltd. (Xiao Yang ) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * Test for CVE-2017-5669 which allows us to map the nil page using shmat. * * When the bug is present shmat(..., (void *)1, SHM_RND) will round address * 0x1 down to zero and give us the (nil/null) page. With the current bug fix * in place, shmat it will return EINVAL instead. We also check to see if the * returned address is outside the nil page in case an alternative fix has * been applied. * * In any case we manage to map some memory we also try to write to it. This * is just to see if we get an access error or some other unexpected behaviour. * * See commit 95e91b831f (ipc/shm: Fix shmat mmap nil-page protection) * * The commit above disallowed SHM_RND maps to zero (and rounded) entirely and * that broke userland for cases like Xorg. New behavior disallows REMAPs to * lower addresses (0<=PAGESIZE). * * See commit a73ab244f0da (Revert "ipc/shm: Fix shmat mmap nil-page protect...) * See commit 8f89c007b6de (ipc/shm: fix shmat() nil address after round-dow...) * See https://github.com/linux-test-project/ltp/issues/319 * * This test needs root permissions or else security_mmap_addr(), from * get_unmapped_area(), will cause permission errors when trying to mmap lower * addresses. */ #include #include #include #include #include #include #include "tst_test.h" #include "tst_safe_sysv_ipc.h" static int shm_id; static void *shm_addr; static void setup(void) { shm_id = SAFE_SHMGET(IPC_PRIVATE, getpagesize(), 0777); } static void cleanup(void) { if (shm_addr) SAFE_SHMDT(shm_addr); if (shm_id) SAFE_SHMCTL(shm_id, IPC_RMID, 0); } static void run(void) { tst_res(TINFO, "Attempting to attach shared memory to null page"); /* * shmat() for 0 (or < PAGESIZE with RND flag) has to fail with REMAPs * https://github.com/linux-test-project/ltp/issues/319 */ shm_addr = shmat(shm_id, ((void *)1), SHM_RND | SHM_REMAP); if (shm_addr == (void *)-1) { shm_addr = NULL; if (errno == EINVAL) { tst_res(TPASS, "shmat returned EINVAL"); return; } tst_brk(TBROK | TERRNO, "The bug was not triggered, but the shmat error is unexpected"); } tst_res(TINFO, "Mapped shared memory to %p", shm_addr); if (!((size_t)shm_addr & (~0U << 16))) tst_res(TFAIL, "We have mapped a VM address within the first 64Kb"); else tst_res(TPASS, "The kernel assigned a different VM address"); tst_res(TINFO, "Touching shared memory to see if anything strange happens"); ((char *)shm_addr)[0] = 'P'; SAFE_SHMDT(shm_addr); shm_addr = NULL; } static struct tst_test test = { .needs_root = 1, .setup = setup, .cleanup = cleanup, .test_all = run, };