geturl: Avoid the shell when invoking curl

This commit is contained in:
Richard Hansen 2024-05-26 02:18:24 -04:00
parent 09d8d0426e
commit 8e901c3db6

View file

@ -2635,7 +2635,7 @@ sub curl_cmd {
my @params = @_; my @params = @_;
my $tmpfile; my $tmpfile;
my $tfh; my $tfh;
my $system_curl = quotemeta(subst_var('@CURL@', 'curl')); my $curl = subst_var('@CURL@', 'curl');
my %curl_codes = ( ## Subset of error codes from https://curl.haxx.se/docs/manpage.html my %curl_codes = ( ## Subset of error codes from https://curl.haxx.se/docs/manpage.html
2 => "Failed to initialize. (Most likely a bug in ddclient, please open issue at https://github.com/ddclient/ddclient)", 2 => "Failed to initialize. (Most likely a bug in ddclient, please open issue at https://github.com/ddclient/ddclient)",
3 => "URL malformed. The syntax was not correct", 3 => "URL malformed. The syntax was not correct",
@ -2653,11 +2653,11 @@ sub curl_cmd {
67 => "The user name, password, or similar was not accepted and curl failed to log in.", 67 => "The user name, password, or similar was not accepted and curl failed to log in.",
77 => "Problem with reading the SSL CA cert (path? access rights?).", 77 => "Problem with reading the SSL CA cert (path? access rights?).",
78 => "The resource referenced in the URL does not exist.", 78 => "The resource referenced in the URL does not exist.",
127 => "$system_curl was not found", 127 => "$curl was not found",
); );
debug("CURL: %s", $system_curl); debug("CURL: %s", $curl);
fatal("curl not found") if ($system_curl eq ''); fatal("curl not found") if ($curl eq '');
return '' if (scalar(@params) == 0); ## no parameters provided return '' if (scalar(@params) == 0); ## no parameters provided
# Hard code to /tmp rather than use system TMPDIR to protect from malicious # Hard code to /tmp rather than use system TMPDIR to protect from malicious
@ -2673,9 +2673,13 @@ sub curl_cmd {
print($tfh @params); print($tfh @params);
} }
close($tfh); close($tfh);
my $reply = qx{ $system_curl --config $tmpfile; }; # Use open's list form (as opposed to qx, backticks, or the scalar form of open) to avoid the
# shell and reduce the risk of a shell injection vulnerability.
open(my $cfh, '-|', $curl, '--config', $tmpfile) or fatal("failed to run curl ($curl): $!");
my $reply = do { local $/; <$cfh>; };
close($cfh); # Closing $cfh waits for the process to exit and sets $?.
if ((my $rc = $?>>8) != 0) { if ((my $rc = $?>>8) != 0) {
warning("CURL error (%d) %s", $rc, $curl_codes{$rc} // "Unknown return code. Check $system_curl is installed and its manpage."); warning("CURL error (%d) %s", $rc, $curl_codes{$rc} // "Unknown return code. Check $curl is installed and its manpage.");
} }
return $reply; return $reply;
} }