diff --git a/AUTHORS b/AUTHORS index 3ce229f9d..31666395f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -7,6 +7,7 @@ # Individual Persons Alexandr Stelnykovych +Sebastien Tardif # Organizations diff --git a/daemon/References/Linux/etc/client.up b/daemon/References/Linux/etc/client.up index 82d881c88..a1a4e3821 100755 --- a/daemon/References/Linux/etc/client.up +++ b/daemon/References/Linux/etc/client.up @@ -35,10 +35,12 @@ else # if we get no DOMAINS, then don't use either domain or search. while true; do - eval fopt=\$foreign_option_${i} + # Quote the expansion. A bare eval of the value runs command + # substitution from the server PUSH. + eval "fopt=\$(printf '%s' \"\${foreign_option_${i}}\")" [ -z "${fopt}" ] && break - case ${fopt} in + case "$fopt" in dhcp-option\ DOMAIN\ *) ndoms=$((ndoms + 1)) domains="${domains} ${fopt#dhcp-option DOMAIN }" diff --git a/daemon/vpn/openvpn/client_up_foreign_option_test.go b/daemon/vpn/openvpn/client_up_foreign_option_test.go new file mode 100644 index 000000000..8aa53984e --- /dev/null +++ b/daemon/vpn/openvpn/client_up_foreign_option_test.go @@ -0,0 +1,45 @@ +package openvpn + +import ( + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +func TestClientUpDoesNotEvalForeignOption(t *testing.T) { + scriptPath := filepath.Join("..", "..", "References", "Linux", "etc", "client.up") + body, err := os.ReadFile(scriptPath) + if err != nil { + t.Fatal(err) + } + text := string(body) + if strings.Contains(text, "eval fopt=") { + t.Fatal("client.up still evals foreign_option without quoting") + } + if !strings.Contains(text, `eval "fopt=\$(printf '%s' \"\${foreign_option_${i}}\")"`) { + t.Fatal("client.up is missing the quoted foreign_option read") + } + + out, err := exec.Command("sh", "-c", ` +i=1 +foreign_option_1='dhcp-option DNS $(echo PWNED)' +marker=/tmp/ivpn-foreign-option-test-$$ +rm -f "$marker" +eval "fopt=\$(printf '%s' \"\${foreign_option_${i}}\")" +case "$fopt" in + dhcp-option\ DNS\ *) + printf '%s' "${fopt#dhcp-option DNS }" + ;; +esac +if [ -f "$marker" ]; then printf 'RAN'; fi +`).Output() + if err != nil { + t.Fatal(err) + } + got := string(out) + if got != "$(echo PWNED)" { + t.Fatalf("parsed value = %q", got) + } +}