Created
August 28, 2018 15:40
-
-
Save keith-bennett-gbg/680d3e82a732471becfd97d171f5b7ea to your computer and use it in GitHub Desktop.
cloexec-does-not-close-in-parent
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
extern "C" { | |
#include <sys/types.h> // fork(), open() | |
#include <sys/stat.h> // open() | |
#include <sys/wait.h> // waitpid() | |
#include <unistd.h> // fork(), fcntl(), read(), execve() | |
#include <fcntl.h> // fcntl(), open() | |
#include <signal.h> // signal() | |
} // extern "C" | |
#include <iostream>// std::cerr | |
#include <fstream> // std::fstream | |
#include <cstdlib> // EXIT_FAILURE, EXIT_SUCCESS | |
#include <cstring> // std::strerror, std::strcpy | |
#include <cerrno> // errno | |
void child_action(int signum) | |
{ | |
// do nothing. | |
} | |
int main(int argc, char **argv) | |
{ | |
if ( argc == 1 ) | |
{ | |
std::cerr << "./a.out child-file\n"; | |
return EXIT_FAILURE; | |
} | |
errno = 0; | |
int fd = open(argv[0], O_CLOEXEC | O_RDONLY); | |
if ( -1 == fd ) | |
{ | |
int err = errno; | |
std::cerr << "open(" << argv[0] << "): " << std::strerror(err) << std::endl; | |
return EXIT_FAILURE; | |
} | |
errno = 0; | |
sighandler_t prev_handler = signal(SIGCHLD, child_action); | |
if ( SIG_ERR == prev_handler ) | |
{ | |
int err = errno; | |
std::cerr << "signal(SIGCHLD): " << std::strerror(err) << std::endl; | |
return EXIT_FAILURE; | |
} | |
errno = 0; | |
pid_t pid = fork(); | |
if ( -1 == pid ) | |
{ | |
int err = errno; | |
std::cerr << "fork(): " << std::strerror(err) << std::endl; | |
return EXIT_FAILURE; | |
} | |
if ( 0 == pid ) | |
{ | |
// I am child. Check fd, write status to file named by argv[1], and exit. | |
std::fstream f(argv[1], std::ios_base::out | std::ios_base::trunc); | |
if ( false == f.good() ) | |
{ | |
return EXIT_FAILURE; | |
} | |
char buffer[16]; | |
// read from fd. | |
errno = 0; | |
int result = read(fd, buffer, sizeof(buffer)); | |
int err = errno; | |
f << fd << '\t' << result << '\t' << err << '\t' << std::strerror(err) << '\n' << std::flush; | |
if ( false == f.good() ) | |
{ | |
return EXIT_FAILURE; | |
} | |
// try a bad execve() | |
std::strcpy(buffer, "blah blah blah"); | |
char * argv_[2] = {buffer, nullptr}; | |
errno = 0; | |
// reusing argv_ for argp_. this will break most apps. oh well, I just need the app to die quick. | |
result = execve("no-such-executable", argv_, argv_); | |
err = errno; | |
f << "no-such-executable\t" << result << '\t' << err << '\t' << std::strerror(err) << '\n'; | |
// try reading fd some more. | |
errno = 0; | |
result = read(fd, buffer, sizeof(buffer)); | |
err = errno; | |
f << fd << '\t' << result << '\t' << err << '\t' << std::strerror(err) << '\n' << std::flush; | |
if ( false == f.good() ) | |
{ | |
return EXIT_FAILURE; | |
} | |
// child is done. | |
return EXIT_SUCCESS; | |
} | |
else | |
{ | |
// I am parent. Wait for child to exit, then reap. | |
int status = 0; | |
int result = waitpid(pid, &status, 0); | |
// Child has exited. Is our fd still open? | |
char buffer[16]; | |
errno = 0; | |
result = read(fd, buffer, sizeof(buffer)); | |
int err = errno; | |
std::cout << fd << '\t' << result << '\t' << err << '\t' << std::strerror(err) << '\n' << std::flush; | |
if ( -1 != result || EBADF != err ) | |
{ | |
std::cerr << "fd appears to still be open even after execve should have failed in child\n" << std::flush; | |
return EXIT_FAILURE; | |
} | |
} | |
return EXIT_SUCCESS; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment