Subject: | prevent SELinux errors on file I/O |
Date: | Thu, 08 Jan 2009 16:46:29 -1000 |
To: | dhcp-bugs@isc.org |
From: | David Cantrell <dcantrell@redhat.com> |
On Fedora and RHEL systems (and probably other systems using SELinux),
error messages will appear in the system log for all file I/O operations
from dhclient, dhcrelay, dhcpd, etc.
SELinux developers discovered what needed to be changed in the ISC
software and helped me generate the attached patch. The problem is that
all file descriptors need to be closed-on-exec (O_CLOEXEC).
Using fopen() or fdopen(), you can add 'e' to the mode string. When
using open(), or in O_CLOEXEC to the mode.
The attached patch uses O_CLOEXEC if it's available. For the fopen()
and fdopen() calls, I added 'e' to the mode strings.
--
David Cantrell <dcantrell@redhat.com>
Red Hat / Honolulu, HI
Index: client/clparse.c
===================================================================
RCS file: /var/snapdf/DHCP/client/clparse.c,v
retrieving revision 1.84
diff -u -p -r1.84 clparse.c
--- client/clparse.c 23 May 2008 13:22:23 -0000 1.84
+++ client/clparse.c 9 Jan 2009 02:17:24 -0000
@@ -210,7 +210,11 @@ int read_client_conf_file (const char *n
int token;
isc_result_t status;
+#ifdef O_CLOEXEC
+ if ((file = open (name, O_RDONLY | O_CLOEXEC)) < 0)
+#else
if ((file = open (name, O_RDONLY)) < 0)
+#endif
return uerr2isc (errno);
cfile = NULL;
@@ -247,7 +251,11 @@ void read_client_leases ()
/* Open the lease file. If we can't open it, just return -
we can safely trust the server to remember our state. */
+#ifdef O_CLOEXEC
+ if ((file = open (path_dhclient_db, O_RDONLY | O_CLOEXEC)) < 0)
+#else
if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
+#endif
return;
cfile = NULL;
Index: client/dhclient.c
===================================================================
RCS file: /var/snapdf/DHCP/client/dhclient.c,v
retrieving revision 1.171
diff -u -p -r1.171 dhclient.c
--- client/dhclient.c 6 Jan 2009 00:32:19 -0000 1.171
+++ client/dhclient.c 9 Jan 2009 02:17:26 -0000
@@ -110,6 +110,11 @@ main(int argc, char **argv) {
int local_family_set = 0;
#endif /* DHCPv6 */
char *s;
+#ifdef O_CLOEXEC
+ mode_t mode = O_RDWR | O_CLOEXEC;
+#else
+ mode_t mode = O_RDWR;
+#endif
/* Initialize client globals. */
memset(&default_duid, 0, sizeof(default_duid));
@@ -117,11 +122,11 @@ main(int argc, char **argv) {
/* Make sure that file descriptors 0 (stdin), 1, (stdout), and
2 (stderr) are open. To do this, we assume that when we
open a file the lowest available file descriptor is used. */
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 0)
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 1)
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 2)
log_perror = 0; /* No sense logging to /dev/null. */
else if (fd != -1)
@@ -365,7 +370,7 @@ main(int argc, char **argv) {
int e;
oldpid = 0;
- if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) {
+ if ((pidfd = fopen(path_dhclient_pid, "re")) != NULL) {
e = fscanf(pidfd, "%ld\n", &temp);
oldpid = (pid_t)temp;
@@ -2559,7 +2564,7 @@ void rewrite_client_leases ()
if (leaseFile != NULL)
fclose (leaseFile);
- leaseFile = fopen (path_dhclient_db, "w");
+ leaseFile = fopen (path_dhclient_db, "we");
if (leaseFile == NULL) {
log_error ("can't create %s: %m", path_dhclient_db);
return;
@@ -2663,7 +2668,7 @@ write_duid(struct data_string *duid)
return ISC_R_INVALIDARG;
if (leaseFile == NULL) { /* XXX? */
- leaseFile = fopen(path_dhclient_db, "w");
+ leaseFile = fopen(path_dhclient_db, "we");
if (leaseFile == NULL) {
log_error("can't create %s: %m", path_dhclient_db);
return ISC_R_IOERROR;
@@ -2843,7 +2848,7 @@ int write_client_lease (client, lease, r
return 1;
if (leaseFile == NULL) { /* XXX */
- leaseFile = fopen (path_dhclient_db, "w");
+ leaseFile = fopen (path_dhclient_db, "we");
if (leaseFile == NULL) {
log_error ("can't create %s: %m", path_dhclient_db);
return 0;
@@ -3260,6 +3265,11 @@ void go_daemon ()
{
static int state = 0;
int pid;
+#ifdef O_CLOEXEC
+ mode_t mode = O_RDWR | O_CLOEXEC;
+#else
+ mode_t mode = O_RDWR;
+#endif
/* Don't become a daemon if the user requested otherwise. */
if (no_daemon) {
@@ -3289,9 +3299,9 @@ void go_daemon ()
close(2);
/* Reopen them on /dev/null. */
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
+ open("/dev/null", mode);
+ open("/dev/null", mode);
+ open("/dev/null", mode);
write_client_pid_file ();
@@ -3303,14 +3313,18 @@ void write_client_pid_file ()
FILE *pf;
int pfdesc;
+#ifdef O_CLOEXEC
+ pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
+#else
pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+#endif
if (pfdesc < 0) {
log_error ("Can't create %s: %m", path_dhclient_pid);
return;
}
- pf = fdopen (pfdesc, "w");
+ pf = fdopen (pfdesc, "we");
if (!pf)
log_error ("Can't fdopen %s: %m", path_dhclient_pid);
else {
Index: common/bpf.c
===================================================================
RCS file: /var/snapdf/DHCP/common/bpf.c,v
retrieving revision 1.59
diff -u -p -r1.59 bpf.c
--- common/bpf.c 23 Aug 2007 09:49:51 -0000 1.59
+++ common/bpf.c 9 Jan 2009 02:17:28 -0000
@@ -94,7 +94,11 @@ int if_register_bpf (info)
for (b = 0; 1; b++) {
/* %Audit% 31 bytes max. %2004.06.17,Safe% */
sprintf(filename, BPF_FORMAT, b);
+#ifdef O_CLOEXEC
+ sock = open (filename, O_RDWR | O_CLOEXEC, 0);
+#else
sock = open (filename, O_RDWR, 0);
+#endif
if (sock < 0) {
if (errno == EBUSY) {
continue;
Index: common/discover.c
===================================================================
RCS file: /var/snapdf/DHCP/common/discover.c,v
retrieving revision 1.71
diff -u -p -r1.71 discover.c
--- common/discover.c 29 Aug 2008 17:48:57 -0000 1.71
+++ common/discover.c 9 Jan 2009 02:17:29 -0000
@@ -409,7 +409,7 @@ begin_iface_scan(struct iface_conf_list
int len;
int i;
- ifaces->fp = fopen("/proc/net/dev", "r");
+ ifaces->fp = fopen("/proc/net/dev", "re");
if (ifaces->fp == NULL) {
log_error("Error opening '/proc/net/dev' to list interfaces");
return 0;
@@ -443,7 +443,7 @@ begin_iface_scan(struct iface_conf_list
}
#ifdef DHCPv6
- ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
+ ifaces->fp6 = fopen("/proc/net/if_inet6", "re");
if (ifaces->fp6 == NULL) {
log_error("Error opening '/proc/net/if_inet6' to "
"list IPv6 interfaces; %m");
Index: common/dlpi.c
===================================================================
RCS file: /var/snapdf/DHCP/common/dlpi.c,v
retrieving revision 1.37
diff -u -p -r1.37 dlpi.c
--- common/dlpi.c 29 Feb 2008 23:57:56 -0000 1.37
+++ common/dlpi.c 9 Jan 2009 02:17:30 -0000
@@ -795,7 +795,11 @@ dlpiopen(const char *ifname) {
}
*dp = '\0';
+#ifdef O_CLOEXEC
+ return open (devname, O_RDWR | O_CLOEXEC, 0);
+#else
return open (devname, O_RDWR, 0);
+#endif
}
/*
Index: common/nit.c
===================================================================
RCS file: /var/snapdf/DHCP/common/nit.c,v
retrieving revision 1.38
diff -u -p -r1.38 nit.c
--- common/nit.c 5 Sep 2007 17:32:10 -0000 1.38
+++ common/nit.c 9 Jan 2009 02:17:30 -0000
@@ -81,7 +81,11 @@ int if_register_nit (info)
struct strioctl sio;
/* Open a NIT device */
+#ifdef O_CLOEXEC
+ sock = open ("/dev/nit", O_RDWR | O_CLOEXEC);
+#else
sock = open ("/dev/nit", O_RDWR);
+#endif
if (sock < 0)
log_fatal ("Can't open NIT device for %s: %m", info -> name);
Index: common/resolv.c
===================================================================
RCS file: /var/snapdf/DHCP/common/resolv.c,v
retrieving revision 1.22
diff -u -p -r1.22 resolv.c
--- common/resolv.c 7 Mar 2008 20:12:44 -0000 1.22
+++ common/resolv.c 9 Jan 2009 02:17:30 -0000
@@ -49,7 +49,11 @@ void read_resolv_conf (parse_time)
struct domain_search_list *dp, *dl, *nd;
isc_result_t status;
+#ifdef O_CLOEXEC
+ if ((file = open (path_resolv_conf, O_RDONLY | O_CLOEXEC)) < 0) {
+#else
if ((file = open (path_resolv_conf, O_RDONLY)) < 0) {
+#endif
log_error ("Can't open %s: %m", path_resolv_conf);
return;
}
Index: common/upf.c
===================================================================
RCS file: /var/snapdf/DHCP/common/upf.c,v
retrieving revision 1.25
diff -u -p -r1.25 upf.c
--- common/upf.c 13 Jul 2007 06:43:42 -0000 1.25
+++ common/upf.c 9 Jan 2009 02:17:30 -0000
@@ -77,7 +77,11 @@ int if_register_upf (info)
/* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
sprintf(filename, "/dev/pf/pfilt%d", b);
+#ifdef O_CLOEXEC
+ sock = open (filename, O_RDWR | O_CLOEXEC, 0);
+#else
sock = open (filename, O_RDWR, 0);
+#endif
if (sock < 0) {
if (errno == EBUSY) {
continue;
Index: dst/dst_api.c
===================================================================
RCS file: /var/snapdf/DHCP/dst/dst_api.c,v
retrieving revision 1.6
diff -u -p -r1.6 dst_api.c
--- dst/dst_api.c 30 Nov 2007 21:51:43 -0000 1.6
+++ dst/dst_api.c 9 Jan 2009 02:17:32 -0000
@@ -436,7 +436,7 @@ dst_s_write_private_key(const DST_KEY *k
PRIVATE_KEY, PATH_MAX);
/* Do not overwrite an existing file */
- if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) {
+ if ((fp = dst_s_fopen(file, "we", 0600)) != NULL) {
int nn;
if ((nn = fwrite(encoded_block, 1, len, fp)) != len) {
EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n",
@@ -493,7 +493,7 @@ dst_s_read_public_key(const char *in_nam
* flags, proto, alg stored as decimal (or hex numbers FIXME).
* (FIXME: handle parentheses for line continuation.)
*/
- if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
+ if ((fp = dst_s_fopen(name, "re", 0)) == NULL) {
EREPORT(("dst_read_public_key(): Public Key not found %s\n",
name));
return (NULL);
@@ -615,7 +615,7 @@ dst_s_write_public_key(const DST_KEY *ke
return (0);
}
/* create public key file */
- if ((fp = dst_s_fopen(filename, "w+", 0644)) == NULL) {
+ if ((fp = dst_s_fopen(filename, "w+e", 0644)) == NULL) {
EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n",
filename, errno));
return (0);
@@ -849,7 +849,7 @@ dst_s_read_private_key_file(char *name,
return (0);
}
/* first check if we can find the key file */
- if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) {
+ if ((fp = dst_s_fopen(filename, "re", 0)) == NULL) {
EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n",
filename, dst_path[0] ? dst_path :
(char *) getcwd(NULL, PATH_MAX - 1)));
Index: dst/prandom.c
===================================================================
RCS file: /var/snapdf/DHCP/dst/prandom.c,v
retrieving revision 1.6
diff -u -p -r1.6 prandom.c
--- dst/prandom.c 30 Nov 2007 21:51:43 -0000 1.6
+++ dst/prandom.c 9 Jan 2009 02:17:32 -0000
@@ -267,7 +267,11 @@ get_dev_random(u_char *output, unsigned
s = stat("/dev/random", &st);
if (s == 0 && S_ISCHR(st.st_mode)) {
+#ifdef O_CLOEXEC
+ if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK | O_CLOEXEC)) != -1) {
+#else
if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) != -1) {
+#endif
if ((n = read(fd, output, size)) < 0)
n = 0;
close(fd);
@@ -478,7 +482,7 @@ digest_file(dst_work *work)
work->file_digest = dst_free_key(work->file_digest);
return (0);
}
- if ((fp = fopen(name, "r")) == NULL)
+ if ((fp = fopen(name, "re")) == NULL)
return (0);
for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0;
no += i)
Index: minires/res_init.c
===================================================================
RCS file: /var/snapdf/DHCP/minires/res_init.c,v
retrieving revision 1.11
diff -u -p -r1.11 res_init.c
--- minires/res_init.c 28 Feb 2008 21:21:56 -0000 1.11
+++ minires/res_init.c 9 Jan 2009 02:17:33 -0000
@@ -233,7 +233,7 @@ minires_vinit(res_state statp, int prein
(line[sizeof(name) - 1] == ' ' || \
line[sizeof(name) - 1] == '\t'))
- if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
+ if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
/* read the config file */
while (fgets(buf, sizeof(buf), fp) != NULL) {
/* skip comments */
Index: minires/res_query.c
===================================================================
RCS file: /var/snapdf/DHCP/minires/res_query.c,v
retrieving revision 1.9
diff -u -p -r1.9 res_query.c
--- minires/res_query.c 28 Feb 2008 21:21:56 -0000 1.9
+++ minires/res_query.c 9 Jan 2009 02:17:33 -0000
@@ -379,7 +379,7 @@ res_hostalias(const res_state statp, con
if (statp->options & RES_NOALIASES)
return (NULL);
file = getenv("HOSTALIASES");
- if (file == NULL || (fp = fopen(file, "r")) == NULL)
+ if (file == NULL || (fp = fopen(file, "re")) == NULL)
return (NULL);
setbuf(fp, NULL);
buf[sizeof(buf) - 1] = '\0';
Index: omapip/trace.c
===================================================================
RCS file: /var/snapdf/DHCP/omapip/trace.c,v
retrieving revision 1.16
diff -u -p -r1.16 trace.c
--- omapip/trace.c 13 Jul 2007 06:43:42 -0000 1.16
+++ omapip/trace.c 9 Jan 2009 02:17:33 -0000
@@ -140,10 +140,18 @@ isc_result_t trace_begin (const char *fi
return ISC_R_INVALIDARG;
}
+#ifdef O_CLOEXEC
+ traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL | O_CLOEXEC, 0600);
+#else
traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0600);
+#endif
if (traceoutfile < 0 && errno == EEXIST) {
log_error ("WARNING: Overwriting trace file \"%s\"", filename);
+#ifdef O_CLOEXEC
+ traceoutfile = open (filename, O_WRONLY | O_EXCL | O_CLOEXEC, 0600);
+#else
traceoutfile = open (filename, O_WRONLY | O_EXCL, 0600);
+#endif
}
if (traceoutfile < 0) {
@@ -429,7 +437,7 @@ void trace_file_replay (const char *file
isc_result_t result;
int len;
- traceinfile = fopen (filename, "r");
+ traceinfile = fopen (filename, "re");
if (!traceinfile) {
log_error ("Can't open tracefile %s: %m", filename);
return;
Index: relay/dhcrelay.c
===================================================================
RCS file: /var/snapdf/DHCP/relay/dhcrelay.c,v
retrieving revision 1.73
diff -u -p -r1.73 dhcrelay.c
--- relay/dhcrelay.c 6 Jan 2009 00:32:19 -0000 1.73
+++ relay/dhcrelay.c 9 Jan 2009 02:17:34 -0000
@@ -170,15 +170,20 @@ main(int argc, char **argv) {
struct stream_list *sl = NULL;
int local_family_set = 0;
#endif
+#ifdef O_CLOEXEC
+ mode_t mode = O_RDWR | O_CLOEXEC;
+#else
+ mode_t mode = O_RDWR;
+#endif
/* Make sure that file descriptors 0(stdin), 1,(stdout), and
2(stderr) are open. To do this, we assume that when we
open a file the lowest available file descriptor is used. */
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 0)
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 1)
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 2)
log_perror = 0; /* No sense logging to /dev/null. */
else if (fd != -1)
@@ -510,13 +515,18 @@ main(int argc, char **argv) {
else if (pid)
exit(0);
+#ifdef O_CLOEXEC
+ pfdesc = open(path_dhcrelay_pid,
+ O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
+#else
pfdesc = open(path_dhcrelay_pid,
O_CREAT | O_TRUNC | O_WRONLY, 0644);
+#endif
if (pfdesc < 0) {
log_error("Can't create %s: %m", path_dhcrelay_pid);
} else {
- pf = fdopen(pfdesc, "w");
+ pf = fdopen(pfdesc, "we");
if (!pf)
log_error("Can't fdopen %s: %m",
path_dhcrelay_pid);
Index: server/confpars.c
===================================================================
RCS file: /var/snapdf/DHCP/server/confpars.c,v
retrieving revision 1.195
diff -u -p -r1.195 confpars.c
--- server/confpars.c 22 Oct 2008 11:41:57 -0000 1.195
+++ server/confpars.c 9 Jan 2009 02:17:38 -0000
@@ -106,7 +106,11 @@ isc_result_t read_conf_file (const char
}
#endif
+#ifdef O_CLOEXEC
+ if ((file = open (filename, O_RDONLY | O_CLOEXEC)) < 0) {
+#else
if ((file = open (filename, O_RDONLY)) < 0) {
+#endif
if (leasep) {
log_error ("Can't open lease database %s: %m --",
path_dhcpd_db);
Index: server/db.c
===================================================================
RCS file: /var/snapdf/DHCP/server/db.c,v
retrieving revision 1.91
diff -u -p -r1.91 db.c
--- server/db.c 31 Mar 2008 13:49:45 -0000 1.91
+++ server/db.c 9 Jan 2009 02:17:38 -0000
@@ -1021,7 +1021,7 @@ void db_startup (testp)
}
#endif
if (!testp) {
- db_file = fopen (path_dhcpd_db, "a");
+ db_file = fopen (path_dhcpd_db, "ae");
if (!db_file)
log_fatal ("Can't open %s for append.", path_dhcpd_db);
expire_all_pools ();
@@ -1069,12 +1069,16 @@ int new_lease_file ()
path_dhcpd_db, (int)t) >= sizeof newfname)
log_fatal("new_lease_file: lease file path too long");
+#ifdef O_CLOEXEC
+ db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0664);
+#else
db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664);
+#endif
if (db_fd < 0) {
log_error ("Can't create new lease file: %m");
return 0;
}
- if ((new_db_file = fdopen(db_fd, "w")) == NULL) {
+ if ((new_db_file = fdopen(db_fd, "we")) == NULL) {
log_error("Can't fdopen new lease file: %m");
close(db_fd);
goto fdfail;
Index: server/dhcpd.c
===================================================================
RCS file: /var/snapdf/DHCP/server/dhcpd.c,v
retrieving revision 1.148
diff -u -p -r1.148 dhcpd.c
--- server/dhcpd.c 6 Jan 2009 00:32:19 -0000 1.148
+++ server/dhcpd.c 9 Jan 2009 02:17:39 -0000
@@ -253,6 +253,11 @@ main(int argc, char **argv) {
char *traceinfile = (char *)0;
char *traceoutfile = (char *)0;
#endif
+#ifdef O_CLOEXEC
+ mode_t mode = O_RDWR | O_CLOEXEC;
+#else
+ mode_t mode = O_RDWR;
+#endif
#if defined (PARANOIA)
char *set_user = 0;
@@ -266,11 +271,11 @@ main(int argc, char **argv) {
/* Make sure that file descriptors 0 (stdin), 1, (stdout), and
2 (stderr) are open. To do this, we assume that when we
open a file the lowest available file descriptor is used. */
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 0)
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 1)
- fd = open("/dev/null", O_RDWR);
+ fd = open("/dev/null", mode);
if (fd == 2)
log_perror = 0; /* No sense logging to /dev/null. */
else if (fd != -1)
@@ -763,7 +768,11 @@ main(int argc, char **argv) {
#endif /* PARANOIA */
/* Read previous pid file. */
+#ifdef O_CLOEXEC
+ if ((i = open (path_dhcpd_pid, O_RDONLY | O_CLOEXEC)) >= 0) {
+#else
if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
+#endif
status = read(i, pbuf, (sizeof pbuf) - 1);
close (i);
if (status > 0) {
@@ -781,7 +790,11 @@ main(int argc, char **argv) {
}
/* Write new pid file. */
+#ifdef O_CLOEXEC
+ if ((i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644)) >= 0) {
+#else
if ((i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0) {
+#endif
sprintf(pbuf, "%d\n", (int) getpid());
write(i, pbuf, strlen(pbuf));
close(i);
@@ -807,9 +820,9 @@ main(int argc, char **argv) {
close(2);
/* Reopen them on /dev/null. */
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
+ open("/dev/null", mode);
+ open("/dev/null", mode);
+ open("/dev/null", mode);
log_perror = 0; /* No sense logging to /dev/null. */
chdir("/");