My goal is to open the device in one process and then close it in another (not fork).
I don't want to use UNIX socket. I found that starting kernel 5.6 there are two new syscalls: syscall(SYS_pidfd_open, pid, flags)
and syscall(SYS_pidfd_getfd, pidfd, 0, 0)
.
I tried simple code to check this solution.
open_device.c:
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <errno.h>
#define pidfd_open(pid, flags) syscall(SYS_pidfd_open, pid, flags)
int main() {
// Open the device
int fd = open("/dev/null", O_RDWR);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
printf("File descriptor for /dev/null: %d\n", fd);
// Get the current process ID
pid_t pid = getpid();
// Obtain a pidfd for this process
int pidfd = pidfd_open(pid, 0);
if (pidfd == -1) {
perror("pidfd_open");
close(fd);
return EXIT_FAILURE;
}
printf("Generated pidfd: %d\n", pidfd);
// Write pidfd to a file
FILE *pidfd_file = fopen("pidfd.txt", "w");
if (pidfd_file == NULL) {
perror("fopen");
close(fd);
close(pidfd);
return EXIT_FAILURE;
}
fprintf(pidfd_file, "%d\n", pidfd);
fclose(pidfd_file);
// Keep the process alive for testing
while (1) {
sleep(10);
}
// Clean up
close(fd);
close(pidfd);
return 0;
}
close_device.c
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <errno.h>
#ifndef SYS_pidfd_getfd
#define SYS_pidfd_getfd 438 // Replace with the correct syscall number for your architecture
#endif
int main() {
// Read the pidfd from the file
FILE *pidfd_file = fopen("pidfd.txt", "r");
if (pidfd_file == NULL) {
perror("fopen");
return EXIT_FAILURE;
}
int pidfd;
if (fscanf(pidfd_file, "%d", &pidfd) != 1) {
perror("fscanf");
fclose(pidfd_file);
return EXIT_FAILURE;
}
fclose(pidfd_file);
printf("Read pidfd: %d\n", pidfd);
// Retrieve the file descriptor from the first process
int target_fd = syscall(SYS_pidfd_getfd, pidfd, 0, 0);
if (target_fd == -1) {
perror("pidfd_getfd");
close(pidfd);
return EXIT_FAILURE;
}
printf("Successfully retrieved fd: %d\n", target_fd);
// Perform the close operation
if (close(target_fd) == -1) {
perror("close");
close(pidfd);
return EXIT_FAILURE;
}
printf("Device successfully closed.\n");
close(pidfd);
return 0;
}
The problem is that I receive error Bad file descriptor
for pidfd_getfd
.
Where can be an issue?
You are using the wrong arguments for SYS_pidfd_getfd
. pidfd
should be a PID descriptor, int pidfd = pidfd_open(remote_pid, 0);
, where remote_pid
is the process ID of the process which you want to obtain a duplicate file descriptor from.
You could just write the PID of the opening process down to the same file and then in close_device.c
you read that and then call pidfd_open
:
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#ifndef SYS_pidfd_getfd
# define SYS_pidfd_getfd \
438 // Replace with the correct syscall number for your architecture
#endif
#define pidfd_open(pid, flags) syscall(SYS_pidfd_open, pid, flags)
int main(void) {
// Read the pidfd from the file
FILE* pidfd_file = fopen("pidfd.txt", "r");
if(pidfd_file == NULL) {
perror("fopen");
return EXIT_FAILURE;
}
pid_t remote_pid;
int remote_fd;
// read both pid and the descriptor from the file:
// Note: %d may not be appropriate for `pid_t`
if(fscanf(pidfd_file, "%d %d", &remote_pid, &remote_fd) != 2) {
perror("fscanf");
fclose(pidfd_file);
return EXIT_FAILURE;
}
fclose(pidfd_file);
printf("Read pid:%d remote_fd: %d\n", remote_pid, remote_fd);
// now get the pidfd for the remote process:
int pidfd = pidfd_open(remote_pid, 0);
if(pidfd == -1) {
perror("pidfd_open");
return EXIT_FAILURE;
}
// Now you can retrieve the file descriptor from the remote process
int target_fd = syscall(SYS_pidfd_getfd, pidfd, remote_fd, 0);
if(target_fd == -1) {
perror("pidfd_getfd");
close(pidfd);
return EXIT_FAILURE;
}
printf("Successfully retrieved fd: %d\n", target_fd);
// Perform the close operation
if(close(target_fd) == -1) {
perror("close");
return EXIT_FAILURE;
}
printf("Device successfully closed.\n");
}