From 3836b16c4338ebd11cb4d34c1c2f2e5c00870642 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Joan=20Lled=C3=B3?= Date: Tue, 19 May 2026 15:21:54 +0100 Subject: [PATCH] hooks: Escape interface names and use printf In the Hurd, interface names can include invalid characters like `/`. So those must be escaped. --- hooks/01-test | 10 +++++----- hooks/20-resolv.conf | 8 ++++---- hooks/29-lookup-hostname | 6 +++--- hooks/30-hostname.in | 4 ++-- hooks/50-dhcpcd-compat | 2 +- hooks/50-ntp.conf | 8 ++++---- hooks/50-yp.conf | 6 +++--- hooks/50-ypbind.in | 4 ++-- hooks/dhcpcd-run-hooks.in | 12 ++++++------ src/dhcp-common.c | 11 ++++++----- src/dhcp-common.h | 2 +- src/dhcp.c | 2 +- src/script.c | 9 +++++++-- 13 files changed, 45 insertions(+), 39 deletions(-) diff --git a/hooks/01-test b/hooks/01-test index e7d53216..91768fc1 100644 --- a/hooks/01-test +++ b/hooks/01-test @@ -8,32 +8,32 @@ if [ "$reason" = "TEST" ]; then set | while read line; do case "$line" in interface=*|pid=*|reason=*|protocol=*|profile=*|skip_hooks=*) - echo "$line";; + printf '%s\n' "$line";; esac done # Interface flags set | while read line; do case "$line" in ifcarrier=*|ifflags=*|ifmetric=*|ifmtu=*|ifwireless=*|ifssid=*) - echo "$line";; + printf '%s\n' "$line";; esac done # Old lease set | while read line; do case "$line" in - old_*) echo "$line";; + old_*) printf '%s\n' "$line";; esac done # New lease set | while read line; do case "$line" in - new_*) echo "$line";; + new_*) printf '%s\n' "$line";; esac done # Router Advertisements set | while read line; do case "$line" in - nd[0-9]*_*) echo "$line";; + nd[0-9]*_*) printf '%s\n' "$line";; esac done exit 0 diff --git a/hooks/20-resolv.conf b/hooks/20-resolv.conf index 0ef599f8..6aae9cc1 100644 --- a/hooks/20-resolv.conf +++ b/hooks/20-resolv.conf @@ -60,17 +60,17 @@ build_resolv_conf() # Assemble resolv.conf using our head and tail files [ -f "$cf" ] && rm -f "$cf" [ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir" - echo "$header" > "$cf" + printf '%s\n' "$header" > "$cf" if [ -f /etc/resolv.conf.head ]; then cat /etc/resolv.conf.head >> "$cf" else - echo "# /etc/resolv.conf.head can replace this line" >> "$cf" + printf '%s\n' "# /etc/resolv.conf.head can replace this line" >> "$cf" fi printf %s "$domain$search$servers" >> "$cf" if [ -f /etc/resolv.conf.tail ]; then cat /etc/resolv.conf.tail >> "$cf" else - echo "# /etc/resolv.conf.tail can replace this line" >> "$cf" + printf '%s\n' "# /etc/resolv.conf.tail can replace this line" >> "$cf" fi if change_file /etc/resolv.conf "$cf"; then chmod 644 /etc/resolv.conf @@ -220,7 +220,7 @@ if $if_configured; then if $have_resolvconf && [ "$reason" = NOCARRIER_ROAMING ]; then # avoid calling resolvconf -c on CARRIER unless we roam mkdir -p "$nocarrier_roaming_dir" - echo " " >"$nocarrier_roaming_dir/$interface" + printf ' \n' >"$nocarrier_roaming_dir/$interface" "$resolvconf" -C "$interface.*" elif $have_resolvconf && [ "$reason" = CARRIER ]; then # Not all resolvconf implementations support -c diff --git a/hooks/29-lookup-hostname b/hooks/29-lookup-hostname index 7c6d3ab8..a432d96e 100644 --- a/hooks/29-lookup-hostname +++ b/hooks/29-lookup-hostname @@ -10,20 +10,20 @@ lookup_hostname() if command -v dig >/dev/null 2>&1; then h=$(dig +short -x $new_ip_address) if [ $? = 0 ]; then - echo "$h" | sed 's/\.$//' + printf '%s\n' "$h" | sed 's/\.$//' return 0 fi elif command -v host >/dev/null 2>&1; then h=$(host $new_ip_address) if [ $? = 0 ]; then - echo "$h" \ + printf '%s\n' "$h" \ | sed 's/.* domain name pointer \(.*\)./\1/' return 0 fi elif command -v getent >/dev/null 2>&1; then h=$(getent hosts $new_ip_address) if [ $? = 0 ]; then - echo "$h" | sed 's/[^ ]* *\([^ ]*\).*/\1/' + printf '%s\n' "$h" | sed 's/[^ ]* *\([^ ]*\).*/\1/' return 0 fi fi diff --git a/hooks/30-hostname.in b/hooks/30-hostname.in index 773eca24..66e4bed4 100644 --- a/hooks/30-hostname.in +++ b/hooks/30-hostname.in @@ -27,7 +27,7 @@ _hostname() { if [ -z "${1+x}" ]; then if [ -r /proc/sys/kernel/hostname ]; then - read name /dev/null 2>/dev/null; then hostname elif sysctl kern.hostname >/dev/null 2>&1; then @@ -41,7 +41,7 @@ _hostname() fi if [ -w /proc/sys/kernel/hostname ]; then - echo "$1" >/proc/sys/kernel/hostname + printf '%s\n' "$1" >/proc/sys/kernel/hostname elif [ -n "$1" ] && command -v hostname >/dev/null 2>&1; then hostname "$1" elif sysctl kern.hostname >/dev/null 2>&1; then diff --git a/hooks/50-dhcpcd-compat b/hooks/50-dhcpcd-compat index e9c406fa..48e10cab 100644 --- a/hooks/50-dhcpcd-compat +++ b/hooks/50-dhcpcd-compat @@ -37,7 +37,7 @@ if [ "$r" != "down" ]; then for x in IPADDR INTERFACE NETMASK BROADCAST NETWORK DHCPSID GATEWAYS \ DNSSERVERS DNSDOMAIN DNSSEARCH NISDOMAIN NISSERVERS \ NTPSERVERS GATEWAY DNS; do - eval echo "$x=\'\$$x\'" >> /var/lib/dhcpcd-"$INTERFACE".info + eval printf '%s\\n' "$x=\'\$$x\'" >> /var/lib/dhcpcd-"$INTERFACE".info done fi diff --git a/hooks/50-ntp.conf b/hooks/50-ntp.conf index 9000d37e..8097a20f 100644 --- a/hooks/50-ntp.conf +++ b/hooks/50-ntp.conf @@ -96,9 +96,9 @@ build_ntp_conf() fi if [ -n "$servers" ]; then - echo "$signature_base${header:+ $from }$header" >> "$cf" - printf %s "$servers" >> "$cf" - echo "$signature_base_end${header:+ $from }$header" >> "$cf" + printf '%s\n' "$signature_base${header:+ $from }$header" >> "$cf" + printf '%s' "$servers" >> "$cf" + printf '%s\n' "$signature_base_end${header:+ $from }$header" >> "$cf" else [ -e "$ntp_conf" ] && [ -e "$cf" ] || return fi @@ -117,7 +117,7 @@ add_ntp_conf() [ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir" if [ -n "$new_ntp_servers" ]; then for x in $(uniqify $new_ntp_servers); do - echo "server $x" >> "$cf" + printf '%s\n' "server $x" >> "$cf" done fi build_ntp_conf diff --git a/hooks/50-yp.conf b/hooks/50-yp.conf index f91eb9a2..3fdfd6bd 100644 --- a/hooks/50-yp.conf +++ b/hooks/50-yp.conf @@ -14,7 +14,7 @@ make_yp_conf() [ -z "${new_nis_domain}${new_nis_servers}" ] && return 0 cf=/etc/yp.conf."$ifname" rm -f "$cf" - echo "$signature" > "$cf" + printf '%s\n' "$signature" > "$cf" prefix= if [ -n "$new_nis_domain" ]; then if ! valid_domainname "$new_nis_domain"; then @@ -26,13 +26,13 @@ make_yp_conf() if [ -n "$new_nis_servers" ]; then prefix="domain $new_nis_domain server " else - echo "domain $new_nis_domain broadcast" >> "$cf" + printf '%s\n' "domain $new_nis_domain broadcast" >> "$cf" fi else prefix="ypserver " fi for x in $new_nis_servers; do - echo "$prefix$x" >> "$cf" + printf '%s\n' "$prefix$x" >> "$cf" done save_conf /etc/yp.conf cat "$cf" > /etc/yp.conf diff --git a/hooks/50-ypbind.in b/hooks/50-ypbind.in index 017936a7..da5127df 100644 --- a/hooks/50-ypbind.in +++ b/hooks/50-ypbind.in @@ -24,7 +24,7 @@ best_domain() make_yp_binding() { [ -d "$ypbind_dir" ] || mkdir -p "$ypbind_dir" - echo "$new_nis_domain" >"$ypbind_dir/$ifname" + printf '%s\n' "$new_nis_domain" >"$ypbind_dir/$ifname" if [ -z "$ypdomain_dir" ]; then false @@ -34,7 +34,7 @@ make_yp_binding() ncf="$cf.$ifname" rm -f "$ncf" for x in $new_nis_servers; do - echo "$x" >>"$ncf" + printf '%s\n' "$x" >>"$ncf" done change_file "$cf" "$ncf" else diff --git a/hooks/dhcpcd-run-hooks.in b/hooks/dhcpcd-run-hooks.in index 999f2ec9..bd1fcd26 100644 --- a/hooks/dhcpcd-run-hooks.in +++ b/hooks/dhcpcd-run-hooks.in @@ -28,7 +28,7 @@ uniqify() *) result="$result${result:+ }$i";; esac done - echo "$result" + printf '%s\n' "$result" } # List interface config files in a directory. @@ -58,7 +58,7 @@ trim() if [ -z "$var" ]; then # So it seems our shell doesn't support wctype(3) patterns # Fall back to sed - var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//') + var=$(printf '%s\n' "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//') fi printf %s "$var" } @@ -76,7 +76,7 @@ key_get_value() for x do while read line; do case "$line" in - "$key"*) echo "${line##$key}";; + "$key"*) printf '%s\n' "${line##$key}";; esac done < "$x" done @@ -100,7 +100,7 @@ remove_markers() case "$line" in "$m1"*) in_marker=1;; "$m2"*) in_marker=0;; - *) [ $in_marker = 0 ] && echo "$line";; + *) [ $in_marker = 0 ] && printf '%s\n' "$line";; esac done < "$x" done @@ -178,8 +178,8 @@ syslog() [ -n "$lvl" ] && shift [ -n "$*" ] || return 0 case "$lvl" in - err|error) echo "$interface: $*" >&2;; - *) echo "$interface: $*";; + err|error) printf '%s\n' "$interface: $*" >&2;; + *) printf '%s\n' "$interface: $*";; esac if command -v logger >/dev/null 2>&1; then logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*" diff --git a/src/dhcp-common.c b/src/dhcp-common.c index 73532cb5..d8bcb87a 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -476,8 +476,9 @@ valid_domainname(char *lbl, int type) */ static const char hexchrs[] = "0123456789abcdef"; ssize_t -print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl) +print_string(char *dst, size_t len, int type, const void *data, size_t dl) { + const uint8_t *d = (const uint8_t *)data; char *odst; uint8_t c; const uint8_t *e; @@ -485,10 +486,10 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl) odst = dst; bytes = 0; - e = data + dl; + e = d + dl; - while (data < e) { - c = *data++; + while (d < e) { + c = *d++; if (type & OT_BINHEX) { if (dst) { if (len == 0 || len == 1) { @@ -856,7 +857,7 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family, if (ifp->wireless) { ssid[0] = '-'; print_string(ssid + 1, sizeof(ssid) - 1, OT_ESCFILE, - (const uint8_t *)ifp->ssid, ifp->ssid_len); + ifp->ssid, ifp->ssid_len); } else ssid[0] = '\0'; return snprintf(leasefile, len, diff --git a/src/dhcp-common.h b/src/dhcp-common.h index 841486bd..d3d3fd32 100644 --- a/src/dhcp-common.h +++ b/src/dhcp-common.h @@ -121,7 +121,7 @@ int make_option_mask(const struct dhcp_opt *, size_t, const struct dhcp_opt *, size_t encode_rfc1035(const char *src, uint8_t *dst); ssize_t decode_rfc1035(char *, size_t, const uint8_t *, size_t); -ssize_t print_string(char *, size_t, int, const uint8_t *, size_t); +ssize_t print_string(char *, size_t, int, const void *, size_t); int dhcp_set_leasefile(char *, size_t, int, const struct interface *); void dhcp_envoption(struct dhcpcd_ctx *, FILE *, const char *, const char *, diff --git a/src/dhcp.c b/src/dhcp.c index f7195bc7..2733e91c 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -2971,7 +2971,7 @@ log_dhcp(int loglevel, const char *msg, const struct interface *ifp, free(a); return; } - print_string(tmp, tmpl, OT_STRING, (uint8_t *)a, al); + print_string(tmp, tmpl, OT_STRING, a, al); free(a); a = tmp; } diff --git a/src/script.c b/src/script.c index c1d309d6..084b6238 100644 --- a/src/script.c +++ b/src/script.c @@ -215,6 +215,7 @@ make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp, const struct interface *ifp2; int af; bool is_stdin = ifp->name[0] == '\0'; + char if_name[sizeof(ifp->name) * 4]; const char *if_up, *if_down; rb_tree_t ifaces; struct rt *rt; @@ -330,7 +331,9 @@ make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp, #endif if (!is_stdin) { - if (efprintf(fp, "interface=%s", ifp->name) == -1) + print_string(if_name, sizeof(if_name), OT_ESCFILE, ifp->name, + strlen(ifp->name)); + if (efprintf(fp, "interface=%s", if_name) == -1) goto eexit; if (protocols[protocol] != NULL) { if (efprintf(fp, "protocol=%s", protocols[protocol]) == @@ -387,9 +390,11 @@ make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp, goto eexit; RB_TREE_FOREACH(rt, &ifaces) { + print_string(if_name, sizeof(if_name), OT_ESCFILE, + rt->rt_ifp->name, strlen(rt->rt_ifp->name)); if (rt != RB_TREE_MIN(&ifaces) && fprintf(fp, "%s", " ") == -1) goto eexit; - if (fprintf(fp, "%s", rt->rt_ifp->name) == -1) + if (fprintf(fp, "%s", if_name) == -1) goto eexit; } rt_headclear(&ifaces, AF_UNSPEC); -- 2.47.3