Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the behaviour of an mmap()'ed pointer after closing the file descriptor without first calling munmap()?

Consider the following code fragment:

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>

int fd = open( "/path/to/existing/file/or/device", O_RDONLY);
int numberOfWords = 4096; // chosen to be smaller than file size
int* data = mmap( NULL, nomberOfWords * sizeof(int), PROT_READ, MAP_SHARED, fd, 0); 
if (data != MAP_FAILED) {

   printf( "%d\n", data[0]);

   // oops, forgot to munmap

   close(fd);

   printf( "%d\n", data[0]);        // <-- why doesn't this segfault

}

Background

I am working with a custom kernel driver that uses ioctl() to setup for DMA, and ultimately requires user space to use mmap() to access a particular buffer.

While developing unit tests I discovered accidentally that after closing the file descriptor without calling munmap first, it was still possible to access the buffer memory in user space with the mmap'ed pointer. Thinking there was some bug in the driver I wrote a small program similar to that shown here to exercise mmap() with a "normal" file.

What I was expecting to see is a segfault on the read after close, my thinking being, that the kernel would automatically munmap() the pages associated with the file descriptor when the use of the open file descriptor was closed, similar to how it happens when the process is terminated.

Instead, I was able to keep using the pointer. This was a bit surprising as I have been using mmap() for several years, I must have been smart (more likely lucky) enough to avoid bugs that would expose this situation. Nothing was obvious in the mmap man page.

Problem

Ideally our driver will need to cause a segfault in user space if this happens, because we don't want a buggy user space program writing to the memory of interest.

So, is this behaviour the same across different *nix? In the given example, would it take say deleting the file to cause a segfault? Or perhaps flushing the vm caches?

like image 779
6EQUJ5 Avatar asked Jun 26 '14 07:06

6EQUJ5


2 Answers

Ok, after writing most of the question I found this different question which is worded differently from how I was searching: do I need to keep a file open after calling mmap on it?

The answer references the POSIX manual and it turns out in the man page after all (under munmap, in passing :-| ) it is explained that closing the descriptor will not automatically unmap the mapping. So it looks like we need to modify our driver close code to invalidate associated memory mappings so that a segfault will occur in user space.

I decided to post the question in case someone else searches for a similar thing.

like image 180
6EQUJ5 Avatar answered Oct 29 '22 01:10

6EQUJ5


The man page for mmap states the following:

After the mmap() call has returned, the file descriptor, fd, can be closed immediately without invalidating the mapping.

This was added explicitly in August 2018, meaning in the man pages for the 5.x Linux kernels.

like image 25
Cimbali Avatar answered Oct 29 '22 03:10

Cimbali