Skip to content

Instantly share code, notes, and snippets.

@berdario
Created June 1, 2025 00:40
Show Gist options
  • Save berdario/740bdeefea62c373d97931e2d4c51be5 to your computer and use it in GitHub Desktop.
Save berdario/740bdeefea62c373d97931e2d4c51be5 to your computer and use it in GitHub Desktop.
openat & fchmod issue within child processes and smb
#define _GNU_SOURCE // Required for clone()
#include <sched.h> // For clone()
#include <stdio.h> // For printf, perror, fopen, fclose, remove
#include <stdlib.h> // For malloc, free, EXIT_SUCCESS, EXIT_FAILURE
#include <unistd.h> // For getpid, close, syscall
#include <sys/wait.h> // For waitpid()
#include <sys/syscall.h> // For SYS_getpid
#include <fcntl.h> // For openat(), AT_FDCWD, O_RDWR
#include <sys/stat.h> // For fchmod(), S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH
#include <signal.h> // For sigaction, SIGCHLD, SIG_DFL, SIG_IGN
#define STACK_SIZE (1024 * 1024) // 1MB stack for the child process
static int child_func(void *arg) {
printf("Child: Process started, PID (via syscall(SYS_getpid)) = %ld\n", (long)syscall(SYS_getpid));
printf("Child: UID = %d, GID = %d\n", getuid(), getgid());
int fd;
printf("Child: Attempting to open 'foo' using openat()...\n");
fd = openat(AT_FDCWD, "foo", O_RDWR | O_CREAT);
if (fd == -1) {
perror("Child: openat failed for 'foo'");
return 1;
}
printf("Child: 'foo' opened successfully via openat(), file descriptor = %d\n", fd);
printf("Child: Attempting to change permissions of 'foo' to 0644 using fchmod()...\n");
if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
perror("Child: fchmod failed for 'foo'");
close(fd);
return 1;
}
printf("Child: Permissions of 'foo' changed successfully to 0644.\n");
if (close(fd) == -1) {
perror("Child: close failed for 'foo'");
return 1;
}
printf("Child: 'foo' closed.\n");
printf("Child: Exiting successfully.\n");
return 0;
}
int main() {
void *child_stack;
pid_t child_pid;
printf("Parent: Process started, PID = %ld\n", (long)getpid());
child_stack = malloc(STACK_SIZE);
if (child_stack == NULL) {
perror("Parent: Failed to allocate stack for child process");
remove("foo");
return EXIT_FAILURE;
}
void *stack_top = child_stack + STACK_SIZE;
printf("Parent: Attempting to clone a new process...\n");
child_pid = clone(child_func, stack_top, CLONE_VM | SIGCHLD, NULL);
if (child_pid == -1) {
perror("Parent: clone failed");
free(child_stack);
remove("foo");
return EXIT_FAILURE;
}
printf("Parent: clone() successful. Child process PID = %ld\n", (long)child_pid);
printf("Parent: Waiting for child process to terminate...\n");
int status;
if (waitpid(child_pid, &status, 0) == -1) {
perror("Parent: waitpid failed");
} else {
if (WIFEXITED(status)) {
printf("Parent: Child process exited with status %d.\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Parent: Child process killed by signal %d.\n", WTERMSIG(status));
} else {
printf("Parent: Child process ended with unknown status.\n");
}
}
// Let's do it again, if fchmod failed, the file had still been created, which can change the behavior of the 2nd child being cloned.
printf("Parent: Attempting to clone a new process...\n");
child_pid = clone(child_func, stack_top, CLONE_VM | SIGCHLD, NULL);
if (child_pid == -1) {
perror("Parent: clone failed");
free(child_stack);
remove("foo");
return EXIT_FAILURE;
}
printf("Parent: clone() successful. Child process PID = %ld\n", (long)child_pid);
printf("Parent: Waiting for child process to terminate...\n");
if (waitpid(child_pid, &status, 0) == -1) {
perror("Parent: waitpid failed");
} else {
if (WIFEXITED(status)) {
printf("Parent: Child process exited with status %d.\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Parent: Child process killed by signal %d.\n", WTERMSIG(status));
} else {
printf("Parent: Child process ended with unknown status.\n");
}
}
free(child_stack);
printf("Parent: Child stack memory freed.\n");
if (remove("foo") == 0) {
printf("Parent: 'foo' file removed successfully.\n");
} else {
perror("Parent: Failed to remove 'foo' file");
}
printf("Parent: Exiting.\n");
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment