Skip to content

Commit ba06722

Browse files
authored
Merge pull request #2611 from pqarmitage/updates
Ensure file descriptors are not leaked to scripts
2 parents e3eae32 + 167d59b commit ba06722

35 files changed

+220
-68
lines changed

README.kernel_versions

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ dnl -- Since Linux 5.7
7878
NFT_SET_CONCAT
7979
NFTNL_SET_EXPR also libnftnl 1.1.7, nft 0.9.5
8080

81+
Since Linux 5.9
82+
close_range syscall
83+
84+
Since Linux 5.11
85+
CLOSE_RANGE_CLOEXEC
86+
87+
Since glibc 2.34
88+
close_range() library function
89+
8190
Since Linux 5.18
8291
IFA_PROTO
8392

configure.ac

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,8 +1380,7 @@ AC_FUNC_FORK
13801380
# We add malloc and realloc to AC_CHECK_FUNCS instead.
13811381
#AC_FUNC_MALLOC
13821382
#AC_FUNC_REALLOC
1383-
dnl - dup3 since Linux 2.6.27 and glibc 2.9
1384-
AC_CHECK_FUNCS([dup2 dup3 getcwd gettimeofday malloc memmove memset realloc select setenv socket strcasecmp strchr strdup strerror strpbrk strstr strtol strtoul uname])
1383+
AC_CHECK_FUNCS([getcwd gettimeofday malloc memmove memset realloc select setenv socket strcasecmp strchr strdup strerror strpbrk strstr strtol strtoul uname])
13851384
dnl - vsyslog() Not defined by Posix, but available in glibc and musl
13861385
AC_CHECK_FUNCS([vsyslog], [add_system_opt([VSYSLOG])])
13871386
@@ -1396,6 +1395,21 @@ AS_IF([test "x$ac_cv_func_memfd_create" != xyes],
13961395
[[#include <sys/syscall.h>]])
13971396
])
13981397
1398+
dnl - close_range() - since Linux 5.9 and glibc 2.34
1399+
dnl - close_range() appeared in the kernel some time before it appeared in
1400+
dnl - glibc so we use the raw syscall if it is available
1401+
dnl - CLOSE_RANGE_CLOEXEC added in Linux 5.11.
1402+
AC_CHECK_FUNCS([close_range], [add_system_opt([CLOSE_RANGE])])
1403+
AS_IF([test "x$ac_cv_func_close_range" != xyes],
1404+
[
1405+
AC_CHECK_DECLS([__NR_close_range],
1406+
[
1407+
AC_DEFINE([USE_CLOSE_RANGE_SYSCALL], [ 1 ], [Use syscall for close_range])
1408+
add_system_opt([CLOSE_RANGE_SYSCALL])
1409+
], [], [[#include <sys/syscall.h>]])
1410+
])
1411+
AC_CHECK_DECLS([CLOSE_RANGE_CLOEXEC], [], [], [[#include <linux/close_range.h>]])
1412+
13991413
dnl - Since Linux 3.17
14001414
AC_CHECK_DECLS([O_TMPFILE], [], [], [[#include <fcntl.h>]])
14011415

keepalived/bfd/bfd_daemon.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ start_bfd_child(void)
465465
/* Clear any child finder functions set in parent */
466466
set_child_finder_name(NULL);
467467

468-
/* Create an independant file descriptor for the shared config file */
468+
/* Create an independent file descriptor for the shared config file */
469469
separate_config_file();
470470

471471
/* Child process part, write pidfile */

keepalived/bfd/bfd_scheduler.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ bfd_open_fd_in(const char *port)
972972
return -1;
973973
}
974974

975-
if ((fd_in = socket(AF_INET6, ai_in->ai_socktype, ai_in->ai_protocol)) == -1) {
975+
if ((fd_in = socket(AF_INET6, ai_in->ai_socktype | SOCK_CLOEXEC, ai_in->ai_protocol)) == -1) {
976976
sav_errno = errno;
977977

978978
freeaddrinfo(ai_in);
@@ -990,7 +990,7 @@ bfd_open_fd_in(const char *port)
990990
return -1;
991991
}
992992

993-
if ((fd_in = socket(AF_INET, ai_in->ai_socktype, ai_in->ai_protocol)) == -1) {
993+
if ((fd_in = socket(AF_INET, ai_in->ai_socktype | SOCK_CLOEXEC, ai_in->ai_protocol)) == -1) {
994994
log_message(LOG_ERR, "socket(AF_INET) error %d (%m)", errno);
995995
freeaddrinfo(ai_in);
996996
return -1;
@@ -1031,7 +1031,7 @@ read_local_port_range(uint32_t port_limits[2])
10311031
port_limits[0] = 49152;
10321032
port_limits[1] = 60999;
10331033

1034-
fd = open("/proc/sys/net/ipv4/ip_local_port_range", O_RDONLY);
1034+
fd = open("/proc/sys/net/ipv4/ip_local_port_range", O_RDONLY | O_CLOEXEC);
10351035
if (fd == -1)
10361036
return false;
10371037
len = read(fd, buf, sizeof(buf));
@@ -1068,7 +1068,7 @@ bfd_open_fd_out(bfd_t *bfd)
10681068
assert(bfd);
10691069
assert(bfd->fd_out == -1);
10701070

1071-
bfd->fd_out = socket(bfd->nbr_addr.ss_family, SOCK_DGRAM, IPPROTO_UDP);
1071+
bfd->fd_out = socket(bfd->nbr_addr.ss_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
10721072
if (bfd->fd_out == -1) {
10731073
log_message(LOG_ERR, "(%s) socket() error (%m)",
10741074
bfd->iname);

keepalived/check/check_daemon.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ start_check_child(void)
772772
/* Clear any child finder functions set in parent */
773773
set_child_finder_name(NULL);
774774

775-
/* Create an independant file descriptor for the shared config file */
775+
/* Create an independent file descriptor for the shared config file */
776776
separate_config_file();
777777

778778
/* Child process part, write pidfile */

keepalived/check/check_ping.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ set_ping_group_range(bool set)
6262
if (set == checked_ping_group_range)
6363
return true;
6464

65-
fd = open(ping_group_range, O_RDWR);
65+
fd = open(ping_group_range, O_RDWR | O_CLOEXEC);
6666
if (fd == -1)
6767
return false;
6868
len = read(fd, buf, sizeof(buf));

keepalived/check/libipvs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ dump_nl_msg(const char *msg, struct nl_msg *nlmsg)
218218
const char *filename;
219219

220220
filename = make_tmp_filename("nlmsg.dmp");
221-
fp = fopen(filename, "a");
221+
fp = fopen(filename, "ae");
222222
FREE_CONST(filename);
223223

224224
fprintf(fp, "\n%s\n\n", msg);

keepalived/core/config_notify.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ save_config(bool post, const char *process, void(*func)(FILE *))
118118

119119
sprintf(buf, "%s/keepalived_%s.%d.%u.%s", config_save_dir, process, our_pid, reload_num, post ? "post" : "pre");
120120

121-
file = fopen_safe(buf, "w");
121+
file = fopen_safe(buf, "we");
122122
if (!file) {
123123
log_message(LOG_INFO, "Failed to open config_save file %s", buf);
124124
return;

keepalived/core/global_data.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ open_dump_file(const char *default_file_name)
586586
global_data->data_use_instance && global_data->instance_name ? global_data->instance_name : "",
587587
dot);
588588

589-
fp = fopen_safe(full_file_name, "w");
589+
fp = fopen_safe(full_file_name, "we");
590590

591591
if (!fp)
592592
log_message(LOG_INFO, "Can't open dump file %s (%d: %s)",

keepalived/core/main.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,7 @@ sigend(__attribute__((unused)) void *v, __attribute__((unused)) int sig)
11631163
}
11641164
}
11651165

1166-
efd = epoll_create(1);
1166+
efd = epoll_create1(EPOLL_CLOEXEC);
11671167
epoll_ctl(efd, EPOLL_CTL_ADD, signal_fd, &ev);
11681168

11691169
gettimeofday(&start_time, NULL);
@@ -1324,7 +1324,7 @@ update_core_dump_pattern(const char *pattern_str)
13241324
if (initialising)
13251325
orig_core_dump_pattern = MALLOC(CORENAME_MAX_SIZE);
13261326

1327-
fd = open ("/proc/sys/kernel/core_pattern", O_RDWR);
1327+
fd = open("/proc/sys/kernel/core_pattern", O_RDWR | O_CLOEXEC);
13281328

13291329
if (fd == -1 ||
13301330
(initialising && read(fd, orig_core_dump_pattern, CORENAME_MAX_SIZE - 1) == -1) ||
@@ -1742,7 +1742,7 @@ set_debug_options(const char *options)
17421742
static void
17431743
report_distro(void)
17441744
{
1745-
FILE *fp = fopen("/etc/os-release", "r");
1745+
FILE *fp = fopen("/etc/os-release", "re");
17461746
char buf[128];
17471747
const char * const var = "PRETTY_NAME=";
17481748
const size_t var_len = strlen(var);
@@ -1784,7 +1784,7 @@ read_config_opts(const char *filename)
17841784
if (stat(filename, &statbuf))
17851785
return NULL;
17861786

1787-
if ((fd = open(filename, O_RDONLY)) == -1) {
1787+
if ((fd = open(filename, O_RDONLY | O_CLOEXEC)) == -1) {
17881788
fprintf(stderr, "Failed to open %s\n", filename);
17891789
return NULL;
17901790
}
@@ -2214,7 +2214,7 @@ parse_cmdline(int argc, char **argv)
22142214
__set_bit(DONT_FORK_BIT, &debug);
22152215
__set_bit(NO_SYSLOG_BIT, &debug);
22162216
if (optarg && optarg[0]) {
2217-
int fd = open(optarg, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
2217+
int fd = open(optarg, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
22182218
if (fd == -1) {
22192219
fprintf(stderr, "Unable to open config-test log file %s %d - %m\n", optarg, errno);
22202220
exit(EXIT_FAILURE);

keepalived/core/namespaces.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ set_namespaces(const char* net_namespace)
275275
strcpy(netns_path, netns_dir);
276276
strcat(netns_path, net_namespace);
277277

278-
fd = open(netns_path, O_RDONLY);
278+
fd = open(netns_path, O_RDONLY | O_CLOEXEC);
279279
if (fd == -1) {
280280
log_message(LOG_INFO, "Failed to open %s", netns_path);
281281
goto err;

keepalived/core/nftables.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ nl_socket_open(void)
139139
}
140140
#endif
141141

142-
nl = mnl_socket_open(NETLINK_NETFILTER);
142+
nl = mnl_socket_open2(NETLINK_NETFILTER, SOCK_CLOEXEC);
143143
if (nl == NULL) {
144144
log_message(LOG_INFO, "mnl_socket_open failed - %d", errno);
145145

@@ -187,7 +187,7 @@ exchange_nl_msg(struct mnl_nlmsg_batch *batch)
187187

188188
if (prog_type == PROG_TYPE_VRRP) {
189189
file_name = make_tmp_filename("nftrace");
190-
fp = fopen(file_name, "a");
190+
fp = fopen(file_name, "ae");
191191
FREE_CONST(file_name);
192192
unsigned char *p = mnl_nlmsg_batch_head(batch);
193193
size_t i;
@@ -267,7 +267,7 @@ exchange_nl_msg_single(struct nlmsghdr *nlm, int (*cb_func)(const struct nlmsghd
267267
FILE *fp;
268268

269269
filename = make_tmp_filename("nftrace");
270-
fp = fopen(filename, "a");
270+
fp = fopen(filename, "ae");
271271
FREE_CONST(filename);
272272

273273
mnl_nlmsg_fprintf(fp, PTR_CAST(char, nlm), nlm->nlmsg_len, 0);
@@ -716,7 +716,7 @@ set_nf_ifname_type(void)
716716
unsigned nft_version = 0;
717717
int ifname_type;
718718

719-
fp = popen("nft -v 2>/dev/null", "r");
719+
fp = popen("nft -v 2>/dev/null", "re");
720720
if (fp) {
721721
if (fgets(nft_ver_buf, sizeof(nft_ver_buf), fp)) {
722722
if (!(p = strchr(nft_ver_buf, ' ')))

keepalived/core/reload_monitor.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ parse_datetime(const char *timestr, bool *date_specified)
218218
static void
219219
read_file(void)
220220
{
221-
FILE *fp = fopen(global_data->reload_time_file, "r");
221+
FILE *fp = fopen(global_data->reload_time_file, "re");
222222
size_t len;
223223
time_t reload_time;
224224
char time_buf[21];

keepalived/core/smtp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ smtp_log_to_file(smtp_t *smtp)
550550
email_t *email;
551551

552552
file_name = make_tmp_filename("smtp-alert.log");
553-
fp = fopen_safe(file_name, "a");
553+
fp = fopen_safe(file_name, "ae");
554554
FREE_CONST(file_name);
555555

556556
if (fp) {

keepalived/core/snmp.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@
2323
#include "config.h"
2424

2525
#include <stdio.h>
26+
#if defined HAVE_CLOSE_RANGE_CLOEXEC
27+
#if !defined DEFINE_CLOSE_RANGE && !defined _GNU_SOURCE
28+
#define _GNU_SOURCE
29+
#endif
30+
#include <linux/close_range.h>
31+
#else
32+
#include <fcntl.h>
33+
#endif
34+
#include <unistd.h>
35+
2636
#include "scheduler.h"
2737
#include "snmp.h"
2838
#include "logger.h"
@@ -456,9 +466,18 @@ snmp_unregister_mib(oid *myoid, size_t len)
456466
void
457467
snmp_agent_init(const char *snmp_socket_name, bool base_mib)
458468
{
469+
#ifndef HAVE_DECL_CLOSE_RANGE_CLOEXEC
470+
uint64_t fds[2][16];
471+
unsigned max_fd;
472+
#endif
473+
459474
if (snmp_running)
460475
return;
461476

477+
#ifndef HAVE_DECL_CLOSE_RANGE_CLOEXEC
478+
get_open_fds(fds[0], sizeof(fds[0]) / sizeof(fds[0][0]));
479+
#endif
480+
462481
log_message(LOG_INFO, "Starting SNMP subagent");
463482
netsnmp_enable_subagent();
464483
snmp_disable_log();
@@ -509,6 +528,27 @@ snmp_agent_init(const char *snmp_socket_name, bool base_mib)
509528
/* Set up the fd threads */
510529
snmp_epoll_info(master);
511530

531+
#ifdef HAVE_DECL_CLOSE_RANGE_CLOEXEC
532+
/* This assumes that child processes should only have stdin, stdout and stderr open */
533+
close_range(STDERR_FILENO + 1, ~0U, CLOSE_RANGE_CLOEXEC);
534+
#else
535+
max_fd = get_open_fds(fds[1], sizeof(fds[1]) / sizeof(fds[1][0]));
536+
537+
for (size_t i = 0; i < sizeof(fds[0]) / sizeof(fds[0][0]) && i * 64 <= max_fd; i++) {
538+
if (fds[0][i] != fds[1][i]) {
539+
uint64_t fds_diff = fds[0][i] ^ fds[1][i], bit_mask;
540+
unsigned j;
541+
for (bit_mask = 1, j = i * 64; j < (i + 1) * 64 && j <= max_fd; j++, bit_mask <<= 1) {
542+
if (j <= STDERR_FILENO)
543+
continue;
544+
545+
if (fds_diff & bit_mask)
546+
fcntl(j, F_SETFD, fcntl(j, F_GETFD) | FD_CLOEXEC);
547+
}
548+
}
549+
}
550+
#endif
551+
512552
snmp_running = true;
513553
}
514554

keepalived/core/track_process.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ read_procs(list_head_t *processes)
293293
if (vrrp_data->vrrp_use_process_cmdline) {
294294
snprintf(cmdline, sizeof(cmdline), "/proc/%.*s/cmdline", PID_MAX_DIGITS, ent->d_name);
295295

296-
if ((fd = open(cmdline, O_RDONLY)) == -1)
296+
if ((fd = open(cmdline, O_RDONLY | O_CLOEXEC)) == -1)
297297
continue;
298298

299299
/* Read max name len + null byte + 1 extra char */
@@ -307,7 +307,7 @@ read_procs(list_head_t *processes)
307307
if (vrrp_data->vrrp_use_process_comm) {
308308
snprintf(cmdline, sizeof(cmdline), "/proc/%.*s/stat", PID_MAX_DIGITS, ent->d_name);
309309

310-
if ((fd = open(cmdline, O_RDONLY)) == -1)
310+
if ((fd = open(cmdline, O_RDONLY | O_CLOEXEC)) == -1)
311311
continue;
312312

313313
len = read(fd, stat_buf, sizeof(stat_buf) - 1);
@@ -432,7 +432,7 @@ check_process(pid_t pid, char *comm, tracked_process_instance_t *tpi)
432432
if (vrrp_data->vrrp_use_process_cmdline) {
433433
snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
434434

435-
if ((fd = open(cmdline, O_RDONLY)) == -1) {
435+
if ((fd = open(cmdline, O_RDONLY | O_CLOEXEC)) == -1) {
436436
#ifdef _TRACK_PROCESS_DEBUG_
437437
if (do_track_process_debug_detail)
438438
log_message(LOG_INFO, "check_process failed to open %s, errno %d", cmdline, errno);
@@ -461,7 +461,7 @@ check_process(pid_t pid, char *comm, tracked_process_instance_t *tpi)
461461
if (vrrp_data->vrrp_use_process_comm) {
462462
snprintf(cmdline, sizeof(cmdline), "/proc/%d/comm", pid);
463463

464-
if ((fd = open(cmdline, O_RDONLY)) == -1) {
464+
if ((fd = open(cmdline, O_RDONLY | O_CLOEXEC)) == -1) {
465465
#ifdef _TRACK_PROCESS_DEBUG_
466466
if (do_track_process_debug_detail)
467467
log_message(LOG_INFO, "check_process failed to open %s, errno %d", cmdline, errno);

keepalived/trackers/track_file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ track_file_end_handler(void)
497497
if (!reload && !__test_bit(CONFIG_TEST_BIT, &debug) &&
498498
(ret || track_file_init == TRACK_FILE_OVERWRITE)) { // the file doesn't exist or we want to overwrite it
499499
/* Write the value to the file */
500-
if ((tf = fopen_safe(track_file->file_path, "w"))) {
500+
if ((tf = fopen_safe(track_file->file_path, "we"))) {
501501
fprintf(tf, "%d\n", track_file_init_value);
502502
fclose(tf);
503503
}
@@ -809,7 +809,7 @@ process_track_file(tracked_file_t *tfile, bool init)
809809
int fd;
810810
ssize_t len;
811811

812-
if ((fd = open(tfile->file_path, O_RDONLY | O_NONBLOCK)) != -1) {
812+
if ((fd = open(tfile->file_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)) != -1) {
813813
len = read(fd, buf, sizeof(buf) - 1);
814814
close(fd);
815815
if (len > 0) {

keepalived/vrrp/vrrp.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,7 @@ vrrp_build_vrrp_v2(vrrp_t *vrrp, char *buffer)
13361336
struct in6_addr *ip6arr;
13371337
ip_address_t *ip_addr;
13381338

1339-
/* Family independant */
1339+
/* Family independent */
13401340
hd->vers_type = (VRRP_VERSION_2 << 4) | VRRP_PKT_ADVERT;
13411341
hd->vrid = vrrp->vrid;
13421342
hd->priority = vrrp->effective_priority;
@@ -1388,7 +1388,7 @@ vrrp_build_vrrp_v3(vrrp_t *vrrp, char *buffer, struct iphdr *ip)
13881388
ip_address_t *ip_addr;
13891389
ipv4_phdr_t ipv4_phdr;
13901390

1391-
/* Family independant */
1391+
/* Family independent */
13921392
hd->vers_type = (VRRP_VERSION_3 << 4) | VRRP_PKT_ADVERT;
13931393
hd->vrid = vrrp->vrid;
13941394
hd->priority = vrrp->effective_priority;
@@ -4719,7 +4719,7 @@ check_vmac_conflicts(void)
47194719
ip_address_t *vip, *vip1;
47204720
list_head_t *vip_list, *vip_list1;
47214721

4722-
/* Now check that independant vrrp instances (i.e. not in a sync group)
4722+
/* Now check that independent vrrp instances (i.e. not in a sync group)
47234723
* are not trying to use the same VMAC (macvlan) interface. */
47244724
list_for_each_entry(vrrp, &vrrp_data->vrrp, e_list) {
47254725
list_for_each_entry(vrrp1, &vrrp_data->vrrp, e_list) {

0 commit comments

Comments
 (0)