]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Escape | and & characters when passing to the shell.
authorRoy Marples <roy@marples.name>
Wed, 6 Apr 2011 08:16:32 +0000 (08:16 +0000)
committerRoy Marples <roy@marples.name>
Wed, 6 Apr 2011 08:16:32 +0000 (08:16 +0000)
Add functions for hooks to check validity of domain names and paths.
Ensure we set a valid hostname, DNS domain and NIS domain.
Document the need for input validation in dhcpcd-run-hooks(8).

Fixes CVE-2011-996.
Based on patches to dhcpcd-3 by Marius Tomaschewski <mt@suse.de>.

dhcp.c
dhcpcd-hooks/20-resolv.conf
dhcpcd-hooks/30-hostname
dhcpcd-hooks/50-yp.conf
dhcpcd-hooks/50-ypbind
dhcpcd-run-hooks.8.in
dhcpcd-run-hooks.in

diff --git a/dhcp.c b/dhcp.c
index d0a9e129911657c991f5c31ed59f19e311fcf519..2def24894359d487c5bf1cf5ecd71ad7d1faf091 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -1143,7 +1143,9 @@ print_string(char *s, ssize_t len, int dl, const uint8_t *data)
                case '\'': /* FALLTHROUGH */
                case '$':  /* FALLTHROUGH */
                case '`':  /* FALLTHROUGH */
-               case '\\':
+               case '\\': /* FALLTHROUGH */
+               case '|':  /* FALLTHROUGH */
+               case '&':
                        if (s) {
                                if (len < 3) {
                                        errno = ENOBUFS;
index ccc5f21ecb3f49d59d5ce2ab25522f70f540d516..984dae6907ad040a405e13720edfc6e1825fe260 100644 (file)
@@ -81,14 +81,22 @@ add_resolv_conf()
        if [ -n "$new_domain_name" ]; then
                set -- $new_domain_name
                new_domain_name="$1"
-               conf="${conf}domain $new_domain_name\n"
+               if valid_domainname "$new_domain_name"; then
+                       conf="${conf}domain $new_domain_name\n"
+               else
+                       syslog err "Invalid domain name: $new_domain_name"
+               fi
                # Support RFC violating search in domain
                if [ -z "$new_domain_search" -a -n "$2" ]; then
                        new_domain_search="$@"
                fi
        fi
        if [ -n "$new_domain_search" ]; then
-               conf="${conf}search $new_domain_search\n"
+               if valid_domainname_list; then
+                       conf="${conf}search $new_domain_search\n"
+               else
+                       syslog err "Invalid domain name in list: $new_domain_search"
+               fi
        fi
        for x in ${new_domain_name_servers}; do
                conf="${conf}nameserver $x\n"
index 87446fbe0cd688879c2c82c3f0e4d5fa05bbaf73..65d1a13b3ff3da1b1097c21c05daf3ce002e7400 100644 (file)
@@ -18,13 +18,22 @@ need_hostname()
        esac
 }
 
+try_hostname()
+{
+       if valid_domainname "$1"; then
+               hostname "$1"
+       else
+               syslog err "Invalid hostname: $1"
+       fi
+}
+
 set_hostname()
 {
        if need_hostname; then
                if [ -n "$new_host_name" ]; then
-                       hostname "$new_host_name"
+                       try_hostname "$new_host_name"
                elif [ -n "$new_fqdn_name" ]; then
-                       hostname "$new_fqdn_name"
+                       try_hostname "$new_fqdn_name"
                fi
        fi
 }
index a1f579880643cbff88090a6a5d5d8fc4a35d2738..1a2bf4fa11dfc34f31c8af3033db51a7630b816e 100644 (file)
@@ -13,6 +13,11 @@ make_yp_conf()
        rm -f "$cf"
        echo "$signature" > "$cf"
        if [ -n "$new_nis_domain" ]; then
+               if ! valid_domainname "$new_nis_domain"; then
+                       syslog err "Invalid NIS domain name: $new_nis_domain"
+                       rm -f "$cf"
+                       return 1
+               fi
                domainname "$new_nis_domain"
                if [ -n "$new_nis_servers" ]; then
                        prefix="domain $new_nis_domain server "
index 9a1feccd1f2d0da46ecca29dbf7bdeb0f4d75d1c..f63660e5081cb8ce82afe4f324e0440c1a1d336f 100644 (file)
@@ -67,7 +67,11 @@ if [ "$reason" = PREINIT ]; then
        rm -f "$ypbind_dir/$interface"
 elif $if_up || $if_down; then
        if [ -n "$new_nis_domain" ]; then
-               make_yp_binding
+               if valid_domainname "$new_nis_domain"; then
+                       make_yp_binding
+               else
+                       syslog err "Invalid NIS domain name: $new_nis_domain"
+               fi
        elif [ -n "$old_nis_domain" ]; then
                restore_yp_binding
        fi
index bcfc81dacc2194656147ce2449e7e0b6dae21d2d..1a1f70229965d5a61d1845b11d1dd9a82a5cfcd2 100644 (file)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2006-2010 Roy Marples
+.\" Copyright (c) 2006-2011 Roy Marples
 .\" All rights reserved
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd August 24, 2010
+.Dd March 23, 2011
 .Dt DHCPCD-RUN-HOOKS 8 SMM
 .Os
 .Sh NAME
@@ -135,3 +135,11 @@ in a lexical order and then finally
 .An Roy Marples Aq roy@marples.name
 .Sh BUGS
 Please report them to http://roy.marples.name/projects/dhcpcd
+.Sh SECURITY CONSIDERATIONS
+Little validation of DHCP options is done in dhcpcd itself.
+Instead, it is up to the hooks to handle any validation needed.
+To this end, some helper functions are provided, such as valid_domainname as
+used by the
+.Pa 20-resolv.conf
+hook to ensure that the hostname is not set to an invalid value.
+valid_path is also provided, but is currently unused by a stock hook script.
index 7a72041ca0f781021110bfbff322665679e6c3e3..11d29fb7b48c45101d3bc7ad97ebaf6c1730a4be 100644 (file)
@@ -147,6 +147,46 @@ syslog()
        fi
 }
 
+# Check for a valid domain name as per RFC1123 with the exception of
+# allowing - and _ as they seem to be widely used.
+valid_domainname()
+{
+       local name="$1" label
+
+       [ -z "$name" -o ${#name} -gt 255 ] && return 1
+       
+       while [ -n "$name" ]; do
+               label="${name%%.*}"
+               [ -z "$label" -o ${#label} -gt 63 ] && return 1
+               case "$label" in
+               -*|_*|*-|*_)            return 1;;
+               *[![:alnum:]-_]*)       return 1;;
+               esac
+               [ "$name" = "${name#*.}" ] && break
+               name="${name#*.}"
+       done
+       return 0        
+}
+
+valid_domainname_list()
+{
+       local name
+
+       for name in $@; do
+               valid_domainname "$name" || return $?
+       done
+       return 0
+}
+
+# Check for a valid path
+valid_path()
+{
+       case "$@" in
+       *[![:alnum:]#%+-_:\.,@~\\/\[\]=\ ]*) return 1;;
+       esac
+       return 0
+}
+
 # Check a system service exists 
 service_exists()
 {