bin/90518: dhclient-script problems with symlink'd resolv.conf when /etc is read-only

John E. Hein jhein at
Fri Dec 16 12:50:10 PST 2005

>Number:         90518
>Category:       bin
>Synopsis:       dhclient-script problems with symlink'd resolv.conf when /etc is read-only
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Dec 16 20:50:03 GMT 2005
>Originator:     John E. Hein
>Release:        FreeBSD 4.8-RELEASE i386
Timing Solutions
System: noticed on 4.x; still appears to be a problem on -current

	Some situations - embedded products, for instance - call
	for a read-only root (& /etc) file system.  In such cases,
	we sym-link /etc/resolv.conf to a writable file system
    (e.g., /some/where/etc/resolv.conf).

    In 4.x, the 'rm /etc/resolv.conf.std' in dhclient-script fails
    and lines are appended to the actual resolv.conf file.  Over
    time, it can get quite large (in the case where new_domain_name
    is empty and thus the rm /etc/resolv.conf is attempted)).  In
    this case the easy fix is 'cp /dev/null /etc/resolv.conf' rather
    than using 'rm'.

    In -current, the problem is similar but the effect can be
    different.  The way dhclient-script works there, a temporary
    /etc/resolv.conf.std file is written to, then its contents is
    cat'd to the real resolv.conf.

    If /etc/resolv.conf.std does not exist on a read-only /etc,
    resolv.conf will never populate.

    If /etc/resolv.conf.std is a sym link (because the someone using
    a read-only /etc has looked into dhclient-script and seen what
    files it writes to), then you will hit the 'growing' resolv.conf
    issue described above.

    NB: I have not actually tried it on -current yet.  I have just
    looked at the add_new_resolv_conf() function.  If I did not dig
    deep enough, I apologize.  I'll try to verify it on -current
    when I get a chance.

	mount -ur /

	Then run dhclient for your interface (using a dhcp server that
    supplies DNS server info).

    Observe the effects (or lack thereof) on resolv.conf


	Here's a patch for -current.  The choice of using TMPDIR
	may be wrong.  There could be a possible security issue,
	but I'm not clear about all the ways dhclient-script can
	be invoked.  Writing to a less accessible directory might
	be prudent.  And using an env var here may allow a malicious
	user could point TMPDIR somewhere undesirable.

    Somewhere under /var/run might be a better place.

    OpenBSD's version has the same problem.

Index: dhclient-script
RCS file: /base/FreeBSD-CVS/src/sbin/dhclient/dhclient-script,v
retrieving revision 1.10
diff -u -p -r1.10 dhclient-script
--- dhclient-script	8 Sep 2005 22:49:17 -0000	1.10
+++ dhclient-script	16 Dec 2005 20:31:52 -0000
@@ -134,21 +134,22 @@ add_new_resolv_conf() {
 	# thus broke the script. This code creates the resolv.conf if either
 	# are provided.
-	rm -f /etc/resolv.conf.std
+	local tmpres=${TMPDIR:-/tmp}/resolv.conf.std
+	rm -f $tmpres
 	if [ -n "$new_domain_name" ]; then
-		echo "search $new_domain_name" >>/etc/resolv.conf.std
+		echo "search $new_domain_name" >>$tmpres
 	if [ -n "$new_domain_name_servers" ]; then
 		for nameserver in $new_domain_name_servers; do
-			echo "nameserver $nameserver" >>/etc/resolv.conf.std
+			echo "nameserver $nameserver" >>$tmpres
-	if [ -f /etc/resolv.conf.std ]; then
+	if [ -f $tmpres ]; then
 		if [ -f /etc/resolv.conf.tail ]; then
-			cat /etc/resolv.conf.tail >>/etc/resolv.conf.std
+			cat /etc/resolv.conf.tail >>$tmpres
 		# When resolv.conf is not changed actually, we don't
@@ -156,8 +157,8 @@ add_new_resolv_conf() {
 		# If /usr is not mounted yet, we cannot use cmp, then
 		# the following test fails.  In such case, we simply
 		# ignore an error and do update resolv.conf.
-		if cmp -s /etc/resolv.conf.std /etc/resolv.conf; then
-			rm -f /etc/resolv.conf.std
+		if cmp -s $tmpres /etc/resolv.conf; then
+			rm -f $tmpres
 			return 0
 		fi 2>/dev/null
@@ -168,8 +169,8 @@ add_new_resolv_conf() {
 		if [ -f /etc/resolv.conf ]; then
 			cat /etc/resolv.conf > /etc/
-		cat /etc/resolv.conf.std > /etc/resolv.conf
-		rm -f /etc/resolv.conf.std
+		cat $tmpres > /etc/resolv.conf
+		rm -f $tmpres
 		# Try to ensure correct ownership and permissions.
 		chown -RL root:wheel /etc/resolv.conf

More information about the freebsd-bugs mailing list