forked from linux-test-project/ltp
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
syscalls/mmap04: Validate mapping perms in /proc/self/maps
Validating the various combinations of prot+flags arguments in mmap() call and parsing the /proc/self/maps file to verifying resulting mapping has the permission bits as requested in mmap() call. Signed-off-by: Avinesh Kumar <[email protected]>
- Loading branch information
Showing
1 changed file
with
63 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,185 +1,89 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
/* | ||
* Copyright (c) International Business Machines Corp., 2001 | ||
* | ||
* 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, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
* 07/2001 Ported by Wayne Boyer | ||
* Copyright (c) 2023 SUSE LLC Avinesh Kumar <[email protected]> | ||
*/ | ||
|
||
/* | ||
* Test Description: | ||
* Call mmap() to map a file creating a mapped region with read/exec access | ||
* under the following conditions - | ||
* - The prot parameter is set to PROT_READ|PROT_EXEC | ||
* - The file descriptor is open for read | ||
* - The file being mapped has read and execute permission bit set. | ||
* - The minimum file permissions should be 0555. | ||
* | ||
* The call should succeed to map the file creating mapped memory with the | ||
* required attributes. | ||
/*\ | ||
* [Description] | ||
* | ||
* Expected Result: | ||
* mmap() should succeed returning the address of the mapped region, | ||
* and the mapped region should contain the contents of the mapped file. | ||
* | ||
* HISTORY | ||
* 07/2001 Ported by Wayne Boyer | ||
* Verify that, after a successful mmap() call, permission bits of the new | ||
* mapping in /proc/pid/maps file matches the prot and flags arguments in | ||
* mmap() call. | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <sys/types.h> | ||
#include <errno.h> | ||
#include <unistd.h> | ||
#include <fcntl.h> | ||
#include <string.h> | ||
#include <signal.h> | ||
#include <sys/stat.h> | ||
#include <sys/mman.h> | ||
|
||
#include "test.h" | ||
|
||
#define TEMPFILE "mmapfile" | ||
#include "tst_test.h" | ||
#include "tst_safe_stdio.h" | ||
|
||
char *TCID = "mmap04"; | ||
int TST_TOTAL = 1; | ||
|
||
static size_t page_sz; | ||
#define MMAPSIZE 1024 | ||
static char *addr; | ||
static char *dummy; | ||
static int fildes; | ||
|
||
static void setup(void); | ||
static void cleanup(void); | ||
|
||
int main(int ac, char **av) | ||
static struct tcase { | ||
int prot; | ||
int flags; | ||
char *exp_perms; | ||
} tcases[] = { | ||
{PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, "---p"}, | ||
{PROT_NONE, MAP_ANONYMOUS | MAP_SHARED, "---s"}, | ||
{PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, "r--p"}, | ||
{PROT_READ, MAP_ANONYMOUS | MAP_SHARED, "r--s"}, | ||
{PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, "-w-p"}, | ||
{PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, "-w-s"}, | ||
{PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, "rw-p"}, | ||
{PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, "rw-s"}, | ||
{PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, "r-xp"}, | ||
{PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED, "r-xs"}, | ||
{PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, "-wxp"}, | ||
{PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED, "-wxs"}, | ||
{PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, "rwxp"}, | ||
{PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED, "rwxs"} | ||
}; | ||
|
||
static void get_map_perms(char *addr_str, char *perms) | ||
{ | ||
int lc; | ||
FILE *file; | ||
char line[BUFSIZ]; | ||
|
||
tst_parse_opts(ac, av, NULL, NULL); | ||
file = SAFE_FOPEN("/proc/self/maps", "r"); | ||
|
||
setup(); | ||
|
||
for (lc = 0; TEST_LOOPING(lc); lc++) { | ||
|
||
tst_count = 0; | ||
|
||
/* | ||
* Call mmap to map the temporary file 'TEMPFILE' | ||
* with read and execute access. | ||
*/ | ||
errno = 0; | ||
addr = mmap(0, page_sz, PROT_READ | PROT_EXEC, | ||
MAP_FILE | MAP_SHARED, fildes, 0); | ||
|
||
/* Check for the return value of mmap() */ | ||
if (addr == MAP_FAILED) { | ||
tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE); | ||
continue; | ||
} | ||
|
||
/* | ||
* Read the file contents into the dummy | ||
* variable. | ||
*/ | ||
if (read(fildes, dummy, page_sz) < 0) { | ||
tst_brkm(TFAIL, cleanup, "reading %s failed", | ||
TEMPFILE); | ||
} | ||
|
||
/* | ||
* Check whether the mapped memory region | ||
* has the file contents. | ||
*/ | ||
if (memcmp(dummy, addr, page_sz)) { | ||
tst_resm(TFAIL, | ||
"mapped memory region contains invalid " | ||
"data"); | ||
} else { | ||
tst_resm(TPASS, | ||
"Functionality of mmap() successful"); | ||
} | ||
|
||
/* Clean up things in case we are looping. */ | ||
/* Unmap the mapped memory */ | ||
if (munmap(addr, page_sz) != 0) { | ||
tst_brkm(TFAIL, cleanup, "munmapping failed"); | ||
while (fgets(line, sizeof(line), file)) { | ||
if (strstr(line, addr_str) != NULL) { | ||
if (sscanf(line, "%*x-%*x %s", perms) != 1) | ||
tst_brk(TBROK, "failed to find permission string in %s", line); | ||
break; | ||
} | ||
} | ||
|
||
cleanup(); | ||
tst_exit(); | ||
SAFE_FCLOSE(file); | ||
file = NULL; | ||
} | ||
|
||
static void setup(void) | ||
static void run(unsigned int i) | ||
{ | ||
char *tst_buff; | ||
|
||
tst_sig(NOFORK, DEF_HANDLER, cleanup); | ||
|
||
TEST_PAUSE; | ||
|
||
page_sz = getpagesize(); | ||
|
||
if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { | ||
tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); | ||
} | ||
|
||
/* Fill the test buffer with the known data */ | ||
memset(tst_buff, 'A', page_sz); | ||
|
||
tst_tmpdir(); | ||
|
||
/* Creat a temporary file used for mapping */ | ||
if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { | ||
free(tst_buff); | ||
tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); | ||
} | ||
struct tcase *tc = &tcases[i]; | ||
char addr_str[20]; | ||
char perms[8]; | ||
|
||
/* Write test buffer contents into temporary file */ | ||
if (write(fildes, tst_buff, page_sz) < (ssize_t)page_sz) { | ||
free(tst_buff); | ||
tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); | ||
} | ||
addr = SAFE_MMAP(NULL, MMAPSIZE, tc->prot, tc->flags, -1, 0); | ||
|
||
/* Free the memory allocated for test buffer */ | ||
free(tst_buff); | ||
sprintf(addr_str, "%p", addr); | ||
if (sscanf(addr_str, "0x%s", addr_str) != 1) | ||
tst_brk(TBROK, "failed to find address string"); | ||
|
||
/* Make sure proper permissions set on file */ | ||
if (fchmod(fildes, 0555) < 0) { | ||
tst_brkm(TFAIL, cleanup, "fchmod of %s failed", TEMPFILE); | ||
} | ||
get_map_perms(addr_str, perms); | ||
|
||
/* Close the temporary file opened for write */ | ||
if (close(fildes) < 0) { | ||
tst_brkm(TFAIL, cleanup, "closing %s failed", TEMPFILE); | ||
} | ||
if (!strcmp(perms, tc->exp_perms)) | ||
tst_res(TPASS, "mapping permissions in /proc matched: %s", perms); | ||
else | ||
tst_res(TFAIL, "mapping permissions in /proc mismatched," | ||
" expected: %s, found: %s", | ||
tc->exp_perms, perms); | ||
|
||
/* Allocate and initialize dummy string of system page size bytes */ | ||
if ((dummy = calloc(page_sz, sizeof(char))) == NULL) { | ||
tst_brkm(TFAIL, cleanup, "calloc failed (dummy)"); | ||
} | ||
|
||
/* Open the temporary file again for reading */ | ||
if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { | ||
tst_brkm(TFAIL, cleanup, | ||
"opening %s read-only failed", TEMPFILE); | ||
} | ||
SAFE_MUNMAP(addr, MMAPSIZE); | ||
} | ||
|
||
static void cleanup(void) | ||
{ | ||
close(fildes); | ||
free(dummy); | ||
tst_rmdir(); | ||
} | ||
static struct tst_test test = { | ||
.test = run, | ||
.tcnt = ARRAY_SIZE(tcases), | ||
}; |