From 5a84abb09e91e972583ae0e1ef21110fcb7caccb Mon Sep 17 00:00:00 2001 From: ZmnSCPxj jxPCSnmZ Date: Tue, 19 Oct 2021 09:51:43 +0800 Subject: [PATCH] ccan: update to include closefrom Signed-off-by: ZmnSCPxj jxPCSnmZ Signed-off-by: Rusty Russell --- Makefile | 4 + ccan/README | 2 +- ccan/ccan/closefrom/LICENSE | 1 + ccan/ccan/closefrom/_info | 69 ++++++++ ccan/ccan/closefrom/closefrom.c | 225 +++++++++++++++++++++++++ ccan/ccan/closefrom/closefrom.h | 81 +++++++++ ccan/ccan/closefrom/test/run.c | 192 +++++++++++++++++++++ ccan/ccan/crc32c/crc32c.c | 27 +-- ccan/ccan/io/poll.c | 16 +- ccan/ccan/json_escape/json_escape.c | 3 +- ccan/ccan/pipecmd/_info | 1 + ccan/ccan/pipecmd/pipecmd.c | 27 ++- ccan/ccan/str/base32/base32.c | 3 +- ccan/tools/configurator/configurator.c | 41 ++++- 14 files changed, 665 insertions(+), 27 deletions(-) create mode 120000 ccan/ccan/closefrom/LICENSE create mode 100644 ccan/ccan/closefrom/_info create mode 100644 ccan/ccan/closefrom/closefrom.c create mode 100644 ccan/ccan/closefrom/closefrom.h create mode 100644 ccan/ccan/closefrom/test/run.c diff --git a/Makefile b/Makefile index 5903b1bae..efd3feba0 100644 --- a/Makefile +++ b/Makefile @@ -96,6 +96,7 @@ CCAN_OBJS := \ ccan-bitmap.o \ ccan-bitops.o \ ccan-breakpoint.o \ + ccan-closefrom.o \ ccan-crc32c.o \ ccan-crypto-hmac.o \ ccan-crypto-hkdf.o \ @@ -154,6 +155,7 @@ CCAN_HEADERS := \ $(CCANDIR)/ccan/cast/cast.h \ $(CCANDIR)/ccan/cdump/cdump.h \ $(CCANDIR)/ccan/check_type/check_type.h \ + $(CCANDIR)/ccan/closefrom/closefrom.h \ $(CCANDIR)/ccan/compiler/compiler.h \ $(CCANDIR)/ccan/container_of/container_of.h \ $(CCANDIR)/ccan/cppmagic/cppmagic.h \ @@ -857,3 +859,5 @@ ccan-json_escape.o: $(CCANDIR)/ccan/json_escape/json_escape.c @$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<) ccan-json_out.o: $(CCANDIR)/ccan/json_out/json_out.c @$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<) +ccan-closefrom.o: $(CCANDIR)/ccan/closefrom/closefrom.c + @$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<) diff --git a/ccan/README b/ccan/README index 2c869c33c..79a99f513 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from http://ccodearchive.net. -CCAN version: init-2507-g05ec8351 +CCAN version: init-2519-gcc888f28 diff --git a/ccan/ccan/closefrom/LICENSE b/ccan/ccan/closefrom/LICENSE new file mode 120000 index 000000000..b7951dabd --- /dev/null +++ b/ccan/ccan/closefrom/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/closefrom/_info b/ccan/ccan/closefrom/_info new file mode 100644 index 000000000..4dc1d7fae --- /dev/null +++ b/ccan/ccan/closefrom/_info @@ -0,0 +1,69 @@ +#include "config.h" +#include +#include + +/** + * 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 + * + * Example: + * #include + * #include + * #include + * #include + * #include + * #include + * #include + * #include + * + * 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; +} diff --git a/ccan/ccan/closefrom/closefrom.c b/ccan/ccan/closefrom/closefrom.c new file mode 100644 index 000000000..177b05eee --- /dev/null +++ b/ccan/ccan/closefrom/closefrom.c @@ -0,0 +1,225 @@ +/* CC0 license (public domain) - see LICENSE file for details */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + +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 +#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 */ diff --git a/ccan/ccan/closefrom/closefrom.h b/ccan/ccan/closefrom/closefrom.h new file mode 100644 index 000000000..790a5ba32 --- /dev/null +++ b/ccan/ccan/closefrom/closefrom.h @@ -0,0 +1,81 @@ +/* CC0 license (public domain) - see LICENSE file for details */ +#ifndef CCAN_CLOSEFROM_H +#define CCAN_CLOSEFROM_H +#include "config.h" +#include + +#if HAVE_CLOSEFROM +/* BSD. */ +#include +/* Solaris. */ +#include + +static inline +bool closefrom_may_be_slow(void) +{ + return 0; +} + +static inline +void closefrom_limit(unsigned int limit) +{ +} + +#else /* !HAVE_CLOSEFROM */ + +/** + * closefrom - Close all open file descriptors, starting + * at fromfd onwards. + * @fromfd: the first fd to close; it and all higher file descriptors + * will be closed. + * + * This is not multithread-safe: other threads in the same process + * may or may not open new file descriptors in parallel to this call. + * However, the expected use-case is that this will be called in a + * child process just after fork(), meaning the child process is still + * single-threaded. + */ +void closefrom_(int fromfd); +/* In case the standard library has it, but declared in some + * *other* header we do not know of yet, we use closefrom_ in + * the actual name the linker sees. + */ +#define closefrom closefrom_ + +/** + * closefrom_may_be_slow - check if the closefrom() function could + * potentially take a long time. + * + * The return value is true if closefrom() is emulated by + * looping from fromfd to sysconf(_SC_OPEN_MAX), which can be + * very large (possibly even INT_MAX on some systems). + * If so, you might want to use setrlimit to limit _SC_OPEN_MAX. + * If this returns false, then closefrom is efficient and you do not + * need to limit the number of file descriptors. + * + * You can use closefrom_limit to perform the limiting based on + * closefrom_may_be_slow. + * This API is exposed in case you want to output to debug logs or + * something similar. + */ +bool closefrom_may_be_slow(void); + +/** + * closefrom_limit - If closefrom_may_be_slow(), lower the limit on + * the number of file descriptors we keep open, to prevent closefrom + * from being *too* slow. + * @limit: 0 to use a reasonable default of 4096, or non-zero for the + * limit you prefer. + * + * This function does nothing if closefrom_may_be_slow() return false. + * + * This function only *lowers* the limit from the hard limit set by + * root before running this program. + * If the limit is higher than the hard limit, then the hard limit is + * respected. + */ +void closefrom_limit(unsigned int limit); + +#endif /* !HAVE_CLOSEFROM */ + +#endif /* CCAN_CLOSEFROM_H */ diff --git a/ccan/ccan/closefrom/test/run.c b/ccan/ccan/closefrom/test/run.c new file mode 100644 index 000000000..10e401584 --- /dev/null +++ b/ccan/ccan/closefrom/test/run.c @@ -0,0 +1,192 @@ +#include +/* Include the C files directly. */ +#include +#include +#include +#include +#include +#include + +/* Open a pipe, do closefrom, check pipe no longer works. */ +static +int pipe_close(void) +{ + int fds[2]; + ssize_t wres; + + char buf = '\0'; + + if (pipe(fds) < 0) + return 0; + + /* Writing to the write end should succeed, the + * pipe is working. */ + do { + wres = write(fds[1], &buf, 1); + } while ((wres < 0) && (errno == EINTR)); + if (wres < 0) + return 0; + + closefrom(STDERR_FILENO + 1); + + /* Writing to the write end should fail because + * everything should be closed. */ + do { + wres = write(fds[1], &buf, 1); + } while ((wres < 0) && (errno == EINTR)); + + return (wres < 0) && (errno == EBADF); +} + +/* Open a pipe, fork, do closefrom in child, read pipe from parent, + * parent should see EOF. + */ +static +int fork_close(void) +{ + int fds[2]; + pid_t child; + + char buf; + ssize_t rres; + + if (pipe(fds) < 0) + return 0; + + child = fork(); + if (child < 0) + return 0; + + if (child == 0) { + /* Child. */ + closefrom(STDERR_FILENO + 1); + _exit(0); + } else { + /* Parent. */ + + /* Close write end of pipe. */ + close(fds[1]); + + do { + rres = read(fds[0], &buf, 1); + } while ((rres < 0) && (errno == EINTR)); + + /* Should have seen EOF. */ + if (rres != 0) + return 0; + + /* Clean up. */ + waitpid(child, NULL, 0); + closefrom(STDERR_FILENO + 1); + } + + return 1; +} +/* Open a pipe, fork, in child set the write end to fd #3, + * in parent set the read end to fd #3, send a byte from + * child to parent, check. + */ +static +int fork_communicate(void) +{ + int fds[2]; + pid_t child; + + char wbuf = 42; + char rbuf; + ssize_t rres; + ssize_t wres; + + int status; + + if (pipe(fds) < 0) + return 0; + + child = fork(); + if (child < 0) + return 0; + + if (child == 0) { + /* Child. */ + + /* Move write end to fd #3. */ + if (fds[1] != 3) { + if (dup2(fds[1], 3) < 0) + _exit(127); + close(fds[1]); + fds[1] = 3; + } + + closefrom(4); + + do { + wres = write(fds[1], &wbuf, 1); + } while ((wres < 0) && (errno == EINTR)); + if (wres < 0) + _exit(127); + + _exit(0); + } else { + /* Parent. */ + + /* Move read end to fd #3. */ + if (fds[0] != 3) { + if (dup2(fds[0], 3) < 0) + return 0; + close(fds[0]); + fds[0] = 3; + } + + closefrom(4); + + /* Wait for child to finish. */ + waitpid(child, &status, 0); + if (!WIFEXITED(status)) + return 0; + if (WEXITSTATUS(status) != 0) + return 0; + + /* Read 1 byte. */ + do { + rres = read(fds[0], &rbuf, 1); + } while ((rres < 0) && (errno == EINTR)); + if (rres < 0) + return 0; + if (rres != 1) + return 0; + /* Should get same byte as what was sent. */ + if (rbuf != wbuf) + return 0; + + /* Next attempt to read should EOF. */ + do { + rres = read(fds[0], &rbuf, 1); + } while ((rres < 0) && (errno == EINTR)); + if (rres < 0) + return 0; + /* Should EOF. */ + if (rres != 0) + return 0; + + } + + /* Clean up. */ + close(fds[0]); + return 1; +} + +int main(void) +{ + /* Limit closefrom. */ + closefrom_limit(0); + + /* This is how many tests you plan to run */ + plan_tests(3); + + ok1(pipe_close()); + ok1(fork_close()); + ok1(fork_communicate()); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/crc32c/crc32c.c b/ccan/ccan/crc32c/crc32c.c index 9eaec79b0..0203a22bf 100644 --- a/ccan/ccan/crc32c/crc32c.c +++ b/ccan/ccan/crc32c/crc32c.c @@ -72,7 +72,8 @@ static inline uint32_t gf2_matrix_times(uint32_t *mat, uint32_t vec) { /* Multiply a matrix by itself over GF(2). Both mat and square must have 32 rows. */ static inline void gf2_matrix_square(uint32_t *square, uint32_t *mat) { - for (unsigned n = 0; n < 32; n++) + unsigned n; + for (n = 0; n < 32; n++) square[n] = gf2_matrix_times(mat, mat[n]); } @@ -87,7 +88,8 @@ static void crc32c_zeros_op(uint32_t *even, size_t len) { /* put operator for one zero bit in odd */ odd[0] = POLY; /* CRC-32C polynomial */ uint32_t row = 1; - for (unsigned n = 1; n < 32; n++) { + unsigned n; + for (n = 1; n < 32; n++) { odd[n] = row; row <<= 1; } @@ -111,7 +113,7 @@ static void crc32c_zeros_op(uint32_t *even, size_t len) { } while (len); /* answer ended up in odd -- copy to even */ - for (unsigned n = 0; n < 32; n++) + for (n = 0; n < 32; n++) even[n] = odd[n]; } @@ -121,7 +123,8 @@ static void crc32c_zeros(uint32_t zeros[][256], size_t len) { uint32_t op[32]; crc32c_zeros_op(op, len); - for (unsigned n = 0; n < 256; n++) { + unsigned n; + for (n = 0; n < 256; n++) { zeros[0][n] = gf2_matrix_times(op, n); zeros[1][n] = gf2_matrix_times(op, n << 8); zeros[2][n] = gf2_matrix_times(op, n << 16); @@ -265,7 +268,8 @@ uint32_t crc32c(uint32_t crc, void const *buf, size_t len) { static bool crc32c_once_little; static uint32_t crc32c_table_little[8][256]; static void crc32c_init_sw_little(void) { - for (unsigned n = 0; n < 256; n++) { + unsigned n; + for (n = 0; n < 256; n++) { uint32_t crc = n; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; @@ -277,9 +281,10 @@ static void crc32c_init_sw_little(void) { crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc32c_table_little[0][n] = crc; } - for (unsigned n = 0; n < 256; n++) { + for (n = 0; n < 256; n++) { uint32_t crc = crc32c_table_little[0][n]; - for (unsigned k = 1; k < 8; k++) { + unsigned k; + for (k = 1; k < 8; k++) { crc = crc32c_table_little[0][crc & 0xff] ^ (crc >> 8); crc32c_table_little[k][n] = crc; } @@ -340,7 +345,8 @@ static bool crc32c_once_big; static uint32_t crc32c_table_big_byte[256]; static uint64_t crc32c_table_big[8][256]; static void crc32c_init_sw_big(void) { - for (unsigned n = 0; n < 256; n++) { + unsigned n; + for (n = 0; n < 256; n++) { uint32_t crc = n; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; @@ -352,10 +358,11 @@ static void crc32c_init_sw_big(void) { crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc32c_table_big_byte[n] = crc; } - for (unsigned n = 0; n < 256; n++) { + for (n = 0; n < 256; n++) { uint32_t crc = crc32c_table_big_byte[n]; crc32c_table_big[0][n] = swap(crc); - for (unsigned k = 1; k < 8; k++) { + unsigned k; + for (k = 1; k < 8; k++) { crc = crc32c_table_big_byte[crc & 0xff] ^ (crc >> 8); crc32c_table_big[k][n] = swap(crc); } diff --git a/ccan/ccan/io/poll.c b/ccan/ccan/io/poll.c index 17f938458..4cc9f4b7d 100644 --- a/ccan/ccan/io/poll.c +++ b/ccan/ccan/io/poll.c @@ -121,7 +121,9 @@ bool add_listener(struct io_listener *l) static int find_always(const struct io_plan *plan) { - for (size_t i = 0; i < num_always; i++) + size_t i = 0; + + for (i = 0; i < num_always; i++) if (always[i] == plan) return i; return -1; @@ -287,8 +289,10 @@ static bool *exclusive(struct io_plan *plan) /* For simplicity, we do one always at a time */ static bool handle_always(void) { + int i; + /* Backwards is simple easier to remove entries */ - for (int i = num_always - 1; i >= 0; i--) { + for (i = num_always - 1; i >= 0; i--) { struct io_plan *plan = always[i]; if (num_exclusive && !*exclusive(plan)) @@ -323,10 +327,12 @@ bool backend_set_exclusive(struct io_plan *plan, bool excl) * else that we manipulate events. */ static void exclude_pollfds(void) { + size_t i; + if (num_exclusive == 0) return; - for (size_t i = 0; i < num_fds; i++) { + for (i = 0; i < num_fds; i++) { struct pollfd *pfd = &pollfds[fds[i]->backend_info]; if (!fds[i]->exclusive[IO_IN]) @@ -343,10 +349,12 @@ static void exclude_pollfds(void) static void restore_pollfds(void) { + size_t i; + if (num_exclusive == 0) return; - for (size_t i = 0; i < num_fds; i++) { + for (i = 0; i < num_fds; i++) { struct pollfd *pfd = &pollfds[fds[i]->backend_info]; if (fds[i]->listener) { diff --git a/ccan/ccan/json_escape/json_escape.c b/ccan/ccan/json_escape/json_escape.c index ed4bfab94..daa14abe8 100644 --- a/ccan/ccan/json_escape/json_escape.c +++ b/ccan/ccan/json_escape/json_escape.c @@ -21,7 +21,8 @@ bool json_escape_eq(const struct json_escape *a, const struct json_escape *b) bool json_escape_needed(const char *str, size_t len) { - for (size_t i = 0; i < len; i++) { + size_t i; + for (i = 0; i < len; i++) { if ((unsigned)str[i] < ' ' || str[i] == 127 || str[i] == '"' diff --git a/ccan/ccan/pipecmd/_info b/ccan/ccan/pipecmd/_info index 8c49511a2..824f22e3d 100644 --- a/ccan/ccan/pipecmd/_info +++ b/ccan/ccan/pipecmd/_info @@ -51,6 +51,7 @@ int main(int argc, char *argv[]) return 1; if (strcmp(argv[1], "depends") == 0) { + printf("ccan/closefrom\n"); printf("ccan/noerr\n"); return 0; } diff --git a/ccan/ccan/pipecmd/pipecmd.c b/ccan/ccan/pipecmd/pipecmd.c index afeaf5a0a..0090275b0 100644 --- a/ccan/ccan/pipecmd/pipecmd.c +++ b/ccan/ccan/pipecmd/pipecmd.c @@ -1,4 +1,5 @@ /* CC0 license (public domain) - see LICENSE file for details */ +#include #include #include #include @@ -115,7 +116,8 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, goto fail; if (childpid == 0) { - for (int i = 0; i < num_child_close; i++) + int i; + for (i = 0; i < num_child_close; i++) close(child_close[i]); // Child runs command. @@ -138,11 +140,21 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, close(errfromchild[1]); } + /* Map execfail[1] to fd 3. */ + if (execfail[1] != 3) { + if (dup2(execfail[1], 3) == -1) + goto child_errno_fail; + /* CLOEXEC is not shared by dup2, so copy the flags + * from execfail[1] to 3. + */ + if (fcntl(3, F_SETFD, fcntl(execfail[1], F_GETFD)) < 0) + goto child_errno_fail; + close(execfail[1]); + execfail[1] = 3; + } + /* Make (fairly!) sure all other fds are closed. */ - int max = sysconf(_SC_OPEN_MAX); - for (int i = 3; i < max; i++) - if (i != execfail[1]) - close(i); + closefrom(4); execvp(arr[0], arr); @@ -155,7 +167,8 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, exit(127); } - for (int i = 0; i < num_par_close; i++) + int i; + for (i = 0; i < num_par_close; i++) close(par_close[i]); /* Child will close this without writing on successful exec. */ @@ -175,7 +188,7 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, return childpid; fail: - for (int i = 0; i < num_par_close; i++) + for (i = 0; i < num_par_close; i++) close_noerr(par_close[i]); return -1; } diff --git a/ccan/ccan/str/base32/base32.c b/ccan/ccan/str/base32/base32.c index 71ca87d58..6145da300 100644 --- a/ccan/ccan/str/base32/base32.c +++ b/ccan/ccan/str/base32/base32.c @@ -70,7 +70,8 @@ static bool decode_8_chars(const char c[8], beint64_t *res, int *bytes) { uint64_t acc = 0; size_t num_pad = 0; - for (int i = 0; i < 8; i++) { + int i; + for (i = 0; i < 8; i++) { const char *p; acc <<= 5; diff --git a/ccan/tools/configurator/configurator.c b/ccan/tools/configurator/configurator.c index 9487e694c..57779f299 100644 --- a/ccan/tools/configurator/configurator.c +++ b/ccan/tools/configurator/configurator.c @@ -498,6 +498,43 @@ static const struct test base_tests[] = { " return __builtin_cpu_supports(\"mmx\");\n" "}" }, + { "HAVE_CLOSEFROM", "closefrom() offered by system", + "DEFINES_EVERYTHING", NULL, NULL, + "#include \n" + "#include \n" + "int main(void) {\n" + " closefrom(STDERR_FILENO + 1);\n" + " return 0;\n" + "}\n" + }, + { "HAVE_F_CLOSEM", "F_CLOSEM defined for fctnl.", + "DEFINES_EVERYTHING", NULL, NULL, + "#include \n" + "#include \n" + "int main(void) {\n" + " int res = fcntl(STDERR_FILENO + 1, F_CLOSEM, 0);\n" + " return res < 0;\n" + "}\n" + }, + { "HAVE_NR_CLOSE_RANGE", "close_range syscall available as __NR_close_range.", + "DEFINES_EVERYTHING", NULL, NULL, + "#include \n" + "#include \n" + "#include \n" + "int main(void) {\n" + " int res = syscall(__NR_close_range, STDERR_FILENO + 1, INT_MAX, 0);\n" + " return res < 0;\n" + "}\n" + }, + { "HAVE_F_MAXFD", "F_MAXFD defined for fcntl.", + "DEFINES_EVERYTHING", NULL, NULL, + "#include \n" + "#include \n" + "int main(void) {\n" + " int res = fcntl(0, F_MAXFD);\n" + " return res < 0;\n" + "}\n" + }, }; static void c12r_err(int eval, const char *fmt, ...) @@ -765,9 +802,7 @@ static bool run_test(const char *cmd, const char *wrapper, struct test *test) strcpy(cmd, wrapper); strcat(cmd, " ." DIR_SEP OUTPUT_FILE); output = run(cmd, &status); - if (wrapper) { - free(cmd); - } + free(cmd); if (!strstr(test->style, "EXECUTE") && status != 0) c12r_errx(EXIT_BAD_TEST, "Test for %s failed with %i:\n%s",