tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

/dev/clockctl, O_CLOEXEC and forking



While looking whether it's possible to change ntpd to work when
chrooted to a file system mounted with the nodev flag, I noticed
that /dev/clockctl is open with O_CLOEXEC and its file descriptor
is kept in a static variable.  I'm not sure it will work after a
fork correctly. ntpd doesn't open /dev/clockctl before forking but
things may change in a future. Any opinions?

PS I attach my proof-of-concept patch that attempts to configure
/dev/clockctl before chrooting ntpd but it doesn't work because
clockctl's file descriptor is closed by the fork.

-- 
Alex
Index: src/external/bsd/ntp/dist/ntpd/ntpd.c
===================================================================
RCS file: /cvsroot/src/external/bsd/ntp/dist/ntpd/ntpd.c,v
retrieving revision 1.15
diff -p -u -u -r1.15 ntpd.c
--- src/external/bsd/ntp/dist/ntpd/ntpd.c	7 Apr 2018 00:19:53 -0000	1.15
+++ src/external/bsd/ntp/dist/ntpd/ntpd.c	29 Apr 2018 16:06:36 -0000
@@ -214,6 +214,10 @@ extern int syscall	(int, ...);
 static volatile int signalled	= 0;
 static volatile int signo	= 0;
 
+#if 1 /* XXX HAVE_CLOCKCTL_CONFIGURE */
+extern int clockctl_configure(void);
+#endif
+
 /* In an ideal world, 'finish_safe()' would declared as noreturn... */
 static	void		finish_safe	(int);
 static	RETSIGTYPE	finish		(int);
@@ -1027,6 +1031,11 @@ getgroup:
 				msyslog(LOG_ERR, "Cannot chdir() to `%s': %m", chrootdir);
 				exit (-1);
 			}
+#if 1			/* XXX HAVE_CLOCKCTL_CONFIGURE */
+			/* open /dev/clockctl while it's still accessible */
+			if (user != NULL)
+				clockctl_configure();
+#endif
 			if (chroot(chrootdir)) {
 				msyslog(LOG_ERR, "Cannot chroot() to `%s': %m", chrootdir);
 				exit (-1);
Index: src/lib/libc/sys/clock_settime.c
===================================================================
RCS file: /cvsroot/src/lib/libc/sys/clock_settime.c,v
retrieving revision 1.12
diff -p -u -u -r1.12 clock_settime.c
--- src/lib/libc/sys/clock_settime.c	15 Oct 2011 23:00:02 -0000	1.12
+++ src/lib/libc/sys/clock_settime.c	29 Apr 2018 16:06:36 -0000
@@ -51,23 +51,23 @@ __RCSID("$NetBSD: clock_settime.c,v 1.12
 
 #include <sys/clockctl.h>
  
-extern int __clockctl_fd;
-
+int clockctl_configure(void);
+int clockctl_is_configured(void);
 int ____clock_settime50(clockid_t, const struct timespec *);
 
 int
 clock_settime(clockid_t clock_id, const struct timespec *tp)
 {
 	struct clockctl_clock_settime args;
-	int rv;
+	int rv, clockctl = -1;
 
 	/*
 	 * always try the syscall first and attempt to switch to
 	 * clockctl if that fails.
 	 */
-	if (__clockctl_fd == -1) {
+	if (!clockctl_is_configured()) {
 		rv = ____clock_settime50(clock_id, tp);
-	
+
 		/*
 		 * return unless we failed with EPERM
 		 */
@@ -78,19 +78,18 @@ clock_settime(clockid_t clock_id, const 
 		 * If this fails, it means that we are not root
 		 * and we cannot open clockctl. This is a failure.
 		 */
-		__clockctl_fd = open(_PATH_CLOCKCTL, O_WRONLY | O_CLOEXEC, 0);
-		if (__clockctl_fd == -1) {
+		if ((clockctl = clockctl_configure()) == -1) {
 			/* original error was EPERM - don't leak open errors */
 			errno = EPERM;
 			return -1;
 		}
 	}
 
-	/* 
-	 * If __clockctl_fd >=0, clockctl has already been open
+	/*
+	 * If we're here, clockctl has already been open
 	 * and used, so we carry on using it.
 	 */
 	args.clock_id = clock_id;
 	args.tp = tp;
-	return ioctl(__clockctl_fd, CLOCKCTL_CLOCK_SETTIME, &args);
+	return ioctl(clockctl, CLOCKCTL_CLOCK_SETTIME, &args);
 }
Index: src/lib/libc/sys/adjtime.c
===================================================================
RCS file: /cvsroot/src/lib/libc/sys/adjtime.c,v
retrieving revision 1.12
diff -p -u -u -r1.12 adjtime.c
--- src/lib/libc/sys/adjtime.c	15 Oct 2011 23:00:02 -0000	1.12
+++ src/lib/libc/sys/adjtime.c	29 Apr 2018 16:06:36 -0000
@@ -48,24 +48,24 @@ __RCSID("$NetBSD: adjtime.c,v 1.12 2011/
 #include <sys/syscall.h>
 
 #include <sys/clockctl.h>
- 
-extern int __clockctl_fd;
 
+int clockctl_configure(void);
+int clockctl_is_configured(void);
 int ____adjtime50(const struct timeval *, struct timeval *);
 
 int
 adjtime(const struct timeval *delta, struct timeval *olddelta)
 {
 	struct clockctl_adjtime args;
-	int rv;
+	int rv, clockctl = -1;
 
 	/*
-	 * we always attempt the syscall first and switch to 
+	 * we always attempt the syscall first and switch to
 	 * clockctl if that fails with EPERM
 	 */
-	if (__clockctl_fd == -1) {
+	if (!clockctl_is_configured()) {
 		rv = ____adjtime50(delta, olddelta);
-	
+
 		/*
 		 * try via clockctl if the call fails with EPERM
 		 */
@@ -76,19 +76,18 @@ adjtime(const struct timeval *delta, str
 		 * If this fails, it means that we are not root
 		 * and we cannot open clockctl. This is a failure.
 		 */
-		__clockctl_fd = open(_PATH_CLOCKCTL, O_WRONLY | O_CLOEXEC, 0);
-		if (__clockctl_fd == -1) {
+		if ((clockctl = clockctl_configure()) == -1) {
 			/* original error was EPERM - don't leak open errors */
 			errno = EPERM;
 			return -1;
 		}
 	}
 
-	/* 
-	 * If __clockctl_fd >=0, clockctl has already been open
+	/*
+	 * If we're, clockctl has already been open
 	 * and used, so we carry on using it.
 	 */
 	args.delta = delta;
 	args.olddelta = olddelta;
-	return ioctl(__clockctl_fd, CLOCKCTL_ADJTIME, &args);
+	return ioctl(clockctl, CLOCKCTL_ADJTIME, &args);
 }
Index: src/lib/libc/sys/ntp_adjtime.c
===================================================================
RCS file: /cvsroot/src/lib/libc/sys/ntp_adjtime.c,v
retrieving revision 1.13
diff -p -u -u -r1.13 ntp_adjtime.c
--- src/lib/libc/sys/ntp_adjtime.c	20 Mar 2012 16:26:12 -0000	1.13
+++ src/lib/libc/sys/ntp_adjtime.c	29 Apr 2018 16:06:36 -0000
@@ -55,8 +55,8 @@ __RCSID("$NetBSD: ntp_adjtime.c,v 1.13 2
 __weak_alias(ntp_adjtime,_ntp_adjtime)
 #endif
 
-extern int __clockctl_fd;
-
+int clockctl_configure(void);
+int clockctl_is_configured(void);
 int __ntp_adjtime(struct timex *);
 
 int
@@ -64,7 +64,7 @@ ntp_adjtime(struct timex *tp)
 {
 	struct clockctl_ntp_adjtime args;
 	int error;
-	int rv;
+	int rv, clockctl = -1;
 
 	/*
 	 * we always attempt to use the syscall unless we had to
@@ -72,9 +72,9 @@ ntp_adjtime(struct timex *tp)
 	 *
 	 * ntp_adjtime() is callable for mortals if tp->modes == 0 !
 	 */
-	if (__clockctl_fd == -1) {
+	if (!clockctl_is_configured()) {
 		rv = __ntp_adjtime(tp);
-	
+
 		/*
 		 * if we fail with EPERM we try the clockctl device
 		 */
@@ -86,8 +86,7 @@ ntp_adjtime(struct timex *tp)
 		 * and we cannot open clockctl. This is a true
 		 * failure.
 		 */
-		__clockctl_fd = open(_PATH_CLOCKCTL, O_WRONLY | O_CLOEXEC, 0);
-		if (__clockctl_fd == -1) {
+		if ((clockctl = clockctl_configure()) == -1) {
 			/* original error was EPERM - don't leak open errors */
 			errno = EPERM;
 			return -1;
@@ -95,11 +94,11 @@ ntp_adjtime(struct timex *tp)
 	}
 
 	/*
-	 * If __clockctl_fd >=0, clockctl has already been open
+	 * If we're, clockctl has already been open
 	 * and used, so we carry on using it.
 	 */
 	args.tp = tp;
-	error = ioctl(__clockctl_fd, CLOCKCTL_NTP_ADJTIME, &args);
+	error = ioctl(clockctl, CLOCKCTL_NTP_ADJTIME, &args);
 
 	/*
 	 * There is no way to get retval set through ioctl(), hence we
Index: src/lib/libc/sys/settimeofday.c
===================================================================
RCS file: /cvsroot/src/lib/libc/sys/settimeofday.c,v
retrieving revision 1.14
diff -p -u -u -r1.14 settimeofday.c
--- src/lib/libc/sys/settimeofday.c	15 Oct 2011 23:00:02 -0000	1.14
+++ src/lib/libc/sys/settimeofday.c	29 Apr 2018 16:06:36 -0000
@@ -50,24 +50,45 @@ __RCSID("$NetBSD: settimeofday.c,v 1.14 
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
- 
-int __clockctl_fd = -1;
 
+static int __clockctl_fd = -1;
+
+int clockctl_configure(void);
+int clockctl_is_configured(void);
 int ____settimeofday50(const struct timeval *, const void *);
 
 int
+clockctl_configure(void)
+{
+
+	if (__clockctl_fd == -1) {
+		__clockctl_fd = open(_PATH_CLOCKCTL, O_WRONLY | O_CLOEXEC, 0);
+		/* XXX Check that __clockctl_fd is usable. */
+	}
+
+	return __clockctl_fd;
+}
+
+int
+clockctl_is_configured(void)
+{
+
+	return __clockctl_fd != -1;
+}
+
+int
 settimeofday(const struct timeval *tv, const void *tzp)
 {
 	struct clockctl_settimeofday args;
-	int rv;
+	int rv, clockctl = -1;
 
 	/*
 	 * try syscal first and attempt to switch to clockctl
 	 * if that fails with EPERM
 	 */
-	if (__clockctl_fd == -1) {
+	if (!clockctl_is_configured()) {
 		rv = ____settimeofday50(tv, tzp);
-	
+
 		/*
 		 * switch to clockctl if we fail with EPERM, this
 		 * may be cause by an attempt to set the time backwards
@@ -77,19 +98,18 @@ settimeofday(const struct timeval *tv, c
 		if (rv != -1 || errno != EPERM)
 			return rv;
 
-		__clockctl_fd = open(_PATH_CLOCKCTL, O_WRONLY | O_CLOEXEC, 0);
-		if (__clockctl_fd == -1) {
+		if ((clockctl = clockctl_configure()) == -1) {
 			/* original error was EPERM - don't leak open errors */
 			errno = EPERM;
 			return -1;
 		}
 	}
 
-	/* 
-	 * If __clockctl_fd >=0, clockctl has already been open
+	/*
+	 * If we're, clockctl has already been open
 	 * and used, so we carry on using it.
 	 */
 	args.tv = tv;
 	args.tzp = tzp;
-	return ioctl(__clockctl_fd, CLOCKCTL_SETTIMEOFDAY, &args);
+	return ioctl(clockctl, CLOCKCTL_SETTIMEOFDAY, &args);
 }


Home | Main Index | Thread Index | Old Index