forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: ZmnSCPxj jxPCSnmZ <[email protected]> Signed-off-by: Rusty Russell <[email protected]>
- Loading branch information
Showing
14 changed files
with
665 additions
and
27 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
CCAN imported from http://ccodearchive.net. | ||
|
||
CCAN version: init-2507-g05ec8351 | ||
CCAN version: init-2519-gcc888f28 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../licenses/CC0 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#include "config.h" | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
/** | ||
* closefrom - close all fds starting from specified fd. | ||
* | ||
* This code is an example of what to do in a child process to | ||
* ensure that none of the (possibly sensitive) file descriptors | ||
* in the parent remain in the child process. | ||
* | ||
* License: CC0 (Public domain) | ||
* Author: ZmnSCPxj jxPCSnmZ <[email protected]> | ||
* | ||
* Example: | ||
* #include <ccan/closefrom/closefrom.h> | ||
* #include <ccan/err/err.h> | ||
* #include <stdio.h> | ||
* #include <sys/resource.h> | ||
* #include <sys/time.h> | ||
* #include <sys/types.h> | ||
* #include <sys/wait.h> | ||
* #include <unistd.h> | ||
* | ||
* int main(int argc, char **argv) | ||
* { | ||
* pid_t child; | ||
* | ||
* // If being emulated, then we might end up | ||
* // looping over a large _SC_OPEN_MAX | ||
* // (Some systems have it as INT_MAX!) | ||
* // If so, closefrom_limit will lower this limit | ||
* // to a value you specify, or if given 0 will | ||
* // limit to 4096. | ||
* // Call this as early as possible. | ||
* closefrom_limit(0); | ||
* | ||
* // If we limited, we can query this so we can | ||
* // print it in debug logs or something. | ||
* if (closefrom_may_be_slow()) | ||
* printf("we limited ourselves to 4096 fds.\n"); | ||
* | ||
* child = fork(); | ||
* if (child < 0) | ||
* err(1, "Forking"); | ||
* if (child == 0) { | ||
* closefrom(STDERR_FILENO + 1); | ||
* // Insert your *whatever* code here. | ||
* _exit(0); | ||
* } | ||
* | ||
* waitpid(child, NULL, 0); | ||
* | ||
* return 0; | ||
* } | ||
* | ||
*/ | ||
int main(int argc, char *argv[]) | ||
{ | ||
/* Expect exactly one argument */ | ||
if (argc != 2) | ||
return 1; | ||
|
||
if (strcmp(argv[1], "depends") == 0) { | ||
return 0; | ||
} | ||
|
||
return 1; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
/* CC0 license (public domain) - see LICENSE file for details */ | ||
#include <ccan/closefrom/closefrom.h> | ||
#include <dirent.h> | ||
#include <errno.h> | ||
#include <limits.h> | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <sys/time.h> | ||
#include <sys/resource.h> | ||
#include <sys/types.h> | ||
#include <unistd.h> | ||
|
||
/* See also: | ||
* https://stackoverflow.com/a/918469 | ||
* | ||
* The implementation below is not exhaustive of all the suggested above. | ||
*/ | ||
|
||
#if !HAVE_CLOSEFROM | ||
|
||
/* IBM AIX. | ||
* https://www.ibm.com/docs/en/aix/7.2?topic=f-fcntl-dup-dup2-subroutine | ||
*/ | ||
#if HAVE_F_CLOSEM | ||
|
||
#include <fcntl.h> | ||
|
||
void closefrom(int fromfd) | ||
{ | ||
(void) fcntl(fromfd, F_CLOSEM, 0); | ||
} | ||
|
||
bool closefrom_may_be_slow(void) | ||
{ | ||
return false; | ||
} | ||
|
||
#else /* !HAVE_F_CLOSEM */ | ||
|
||
#if HAVE_NR_CLOSE_RANGE | ||
#include <sys/syscall.h> | ||
#endif | ||
|
||
#define PROC_PID_FD_LEN \ | ||
( 6 /* /proc/ */ \ | ||
+ 20 /* 64-bit $PID */ \ | ||
+ 3 /* /fd */ \ | ||
+ 1 /* NUL */ \ | ||
) | ||
|
||
static bool can_get_maxfd(void) | ||
{ | ||
#if HAVE_F_MAXFD | ||
int res = fcntl(0, F_MAXFD); | ||
if (res < 0) | ||
return false; | ||
else | ||
return true; | ||
#else | ||
return false; | ||
#endif | ||
} | ||
|
||
/* Linux >= 5.9 */ | ||
static bool can_close_range(void) | ||
{ | ||
#if HAVE_NR_CLOSE_RANGE | ||
int res = syscall(__NR_close_range, INT_MAX, INT_MAX, 0); | ||
if (res < 0) | ||
return false; | ||
return true; | ||
#else | ||
return false; | ||
#endif | ||
} | ||
|
||
/* On Linux, Solaris, AIX, Cygwin, and NetBSD. */ | ||
static bool can_open_proc_pid_fd(void) | ||
{ | ||
char dnam[PROC_PID_FD_LEN]; | ||
DIR *dir; | ||
|
||
sprintf(dnam, "/proc/%ld/fd", (long) getpid()); | ||
dir = opendir(dnam); | ||
if (!dir) | ||
return false; | ||
closedir(dir); | ||
return true; | ||
} | ||
|
||
/* On FreeBSD and MacOS. */ | ||
static bool can_open_dev_fd(void) | ||
{ | ||
DIR *dir; | ||
dir = opendir("/dev/fd"); | ||
if (!dir) | ||
return false; | ||
closedir(dir); | ||
return true; | ||
} | ||
|
||
bool closefrom_may_be_slow(void) | ||
{ | ||
if (can_get_maxfd()) | ||
return false; | ||
else if (can_close_range()) | ||
return false; | ||
else if (can_open_proc_pid_fd()) | ||
return false; | ||
else if (can_open_dev_fd()) | ||
return false; | ||
else | ||
return true; | ||
} | ||
|
||
/* It is possible that we run out of available file descriptors. | ||
* However, if we are going to close anyway, we could just try | ||
* closing file descriptors until we reach maxfd. | ||
*/ | ||
static | ||
DIR *try_opendir(const char *dnam, int *fromfd, int maxfd) | ||
{ | ||
DIR *dir; | ||
|
||
do { | ||
dir = opendir(dnam); | ||
if (!dir && (errno == ENFILE || errno == EMFILE)) { | ||
if (*fromfd < maxfd) | ||
close((*fromfd)++); | ||
else | ||
break; | ||
} | ||
} while (!dir && (errno == ENFILE || errno == EMFILE)); | ||
|
||
return dir; | ||
} | ||
|
||
void closefrom(int fromfd) | ||
{ | ||
int saved_errno = errno; | ||
|
||
int res; | ||
int maxfd; | ||
|
||
char dnam[PROC_PID_FD_LEN]; | ||
DIR *dir; | ||
struct dirent *entry; | ||
|
||
(void) res; | ||
|
||
if (fromfd < 0) | ||
goto quit; | ||
|
||
#if HAVE_NR_CLOSE_RANGE | ||
res = syscall(__NR_close_range, fromfd, INT_MAX, 0); | ||
if (res == 0) | ||
goto quit; | ||
#endif | ||
|
||
maxfd = sysconf(_SC_OPEN_MAX); | ||
|
||
sprintf(dnam, "/proc/%ld/fd", (long) getpid()); | ||
dir = try_opendir(dnam, &fromfd, maxfd); | ||
if (!dir) | ||
dir = try_opendir("/dev/fd", &fromfd, maxfd); | ||
|
||
if (dir) { | ||
while ((entry = readdir(dir))) { | ||
long fd; | ||
char *endp; | ||
|
||
fd = strtol(entry->d_name, &endp, 10); | ||
if (entry->d_name != endp && *endp == '\0' && | ||
fd >= 0 && fd < INT_MAX && fd >= fromfd && | ||
fd != dirfd(dir) ) | ||
close(fd); | ||
} | ||
closedir(dir); | ||
goto quit; | ||
} | ||
|
||
#if HAVE_F_MAXFD | ||
res = fcntl(0, F_MAXFD); | ||
if (res >= 0) | ||
maxfd = res + 1; | ||
#endif | ||
|
||
/* Fallback. */ | ||
for (; fromfd < maxfd; ++fromfd) | ||
close(fromfd); | ||
|
||
quit: | ||
errno = saved_errno; | ||
} | ||
|
||
#endif /* !HAVE_F_CLOSEM */ | ||
|
||
void closefrom_limit(unsigned int arg_limit) | ||
{ | ||
rlim_t limit = (rlim_t) arg_limit; | ||
|
||
struct rlimit nofile; | ||
|
||
if (!closefrom_may_be_slow()) | ||
return; | ||
|
||
if (limit == 0) | ||
limit = 4096; | ||
|
||
getrlimit(RLIMIT_NOFILE, &nofile); | ||
|
||
/* Respect the max limit. | ||
* If we are not running as root then we cannot raise | ||
* it, but we *can* lower the max limit. | ||
*/ | ||
if (nofile.rlim_max != RLIM_INFINITY && limit > nofile.rlim_max) | ||
limit = nofile.rlim_max; | ||
|
||
nofile.rlim_cur = limit; | ||
nofile.rlim_max = limit; | ||
|
||
setrlimit(RLIMIT_NOFILE, &nofile); | ||
} | ||
|
||
#endif /* !HAVE_CLOSEFROM */ |
Oops, something went wrong.