I have two processes, a client and a server.
The server creates an anonymous file using the Linux memfd_create()
syscall. It then mmap()
s the fd, which works fine. It also prints the fd to stdout.
Now when I pass this fd to the client program, it also tries to mmap()
it but somehow fails this time.
server.c:
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/memfd.h>
const size_t SIZE = 1024;
int main() {
int fd = memfd_create("testmemfd", MFD_ALLOW_SEALING);
// replacing the MFD_ALLOW_SEALING flag with 0 doesn't seem to change anything
if (fd == -1) {
perror("memfd_create");
}
if (ftruncate(fd, SIZE) == -1) {
perror("ftruncate");
}
void * data = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
perror("mmap");
}
close(fd);
// removing close(fd) or the mmap() code doesn't seem to change anything
printf("%d\n", fd);
while (1) {
}
return 0;
}
client.c:
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/memfd.h>
const size_t SIZE = 1024;
int main() {
int fd = -1;
scanf("%d", &fd);
printf("%d\n", fd);
void * data = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
perror("mmap");
}
return 0;
}
(note that using the memfd_create()
syscall needs _GNU_SOURCE
to be defined when compiling)
Now I run them:
$ ./server
3
# in another terminal, since server process won't exit:
$ ./client
3
3
mmap: Bad file descriptor
$
Since the server process is still open, why is the fd invalid? why did the fd work fine with mmap
on the server but not on another process?
I also tried the code here: a-darwish/memfd-examples, which uses sockets to pass data from the server to the client.
It works fine, but when I change the server to output fd to stdout and the client to read it from stdin instead of the whole socket business, mmap complains of a bad file descriptor again.
Why would it be that mmap works with a fd received from socket but not with stdin?
Then I changed the memfd-examples code to use sockets again, which made it work again. So I added a printf to the server and client to print the fd they were sending/receiving. The code worked fine, despite this strangeness:
$ ./memfd-examples/server
[Mon Jun 8 18:43:27 2020] New client connection!
sending fd = 5
# and in another terminal
$ ./memfd-examples/client
got fd = 4
Message: Secure zero-copy message from server: Mon Jun 8 18:43:27 2020
so the code is working fine, with what seems to be the wrong fd entirely?
I then tried decrementing the received fd in my client program -- doesn't work ("No such device", as one would expect).
So, what am I doing wrong with mmap()
?