From 042cc1f69ec0878f542667cb684378869f859911 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 2 Mar 2009 23:05:31 +0000 Subject: - David Kierznowski notified us about a security flaw (http://curl.haxx.se/docs/adv_20090303.html also known as CVE-2009-0037) in which previous libcurl versions (by design) can be tricked to access an arbitrary local/different file instead of a remote one when CURLOPT_FOLLOWLOCATION is enabled. This flaw is now fixed in this release together this the addition of two new setopt options for controlling this new behavior: o CURLOPT_REDIR_PROTOCOLS controls what protocols libcurl is allowed to follow to when CURLOPT_FOLLOWLOCATION is enabled. By default, this option excludes the FILE and SCP protocols and thus you nee to explicitly allow them in your app if you really want that behavior. o CURLOPT_PROTOCOLS controls what protocol(s) libcurl is allowed to fetch using the primary URL option. This is useful if you want to allow a user or other outsiders control what URL to pass to libcurl and yet not allow all protocols libcurl may have been built to support. --- CHANGES | 21 +++++++++++++++++++++ RELEASE-NOTES | 10 ++++++++-- docs/libcurl/curl_easy_setopt.3 | 24 ++++++++++++++++++++++++ docs/libcurl/symbols-in-versions | 15 +++++++++++++++ include/curl/curl.h | 27 +++++++++++++++++++++++++++ lib/url.c | 36 +++++++++++++++++++++++++++++++++++- lib/urldata.h | 35 ++++++++++++++++++++++------------- 7 files changed, 152 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index 4074f10e7..10e6b7d48 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,27 @@ Changelog +Version 7.19.4 (3 March 2009) + +Daniel Stenberg (3 Mar 2009) +- David Kierznowski notified us about a security flaw + (http://curl.haxx.se/docs/adv_20090303.html also known as CVE-2009-0037) in + which previous libcurl versions (by design) can be tricked to access an + arbitrary local/different file instead of a remote one when + CURLOPT_FOLLOWLOCATION is enabled. This flaw is now fixed in this release + together this the addition of two new setopt options for controlling this + new behavior: + + o CURLOPT_REDIR_PROTOCOLS controls what protocols libcurl is allowed to + follow to when CURLOPT_FOLLOWLOCATION is enabled. By default, this option + excludes the FILE and SCP protocols and thus you nee to explicitly allow + them in your app if you really want that behavior. + + o CURLOPT_PROTOCOLS controls what protocol(s) libcurl is allowed to fetch + using the primary URL option. This is useful if you want to allow a user or + other outsiders control what URL to pass to libcurl and yet not allow all + protocols libcurl may have been built to support. + Daniel Stenberg (27 Feb 2009) - Senthil Raja Velu reported a problem when CURLOPT_INTERFACE and CURLOPT_LOCALPORT were used together (the local port bind failed), and diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 0027eebc5..71525341a 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -2,11 +2,16 @@ Curl and libcurl 7.19.4 Public curl releases: 110 Command line options: 132 - curl_easy_setopt() options: 161 + curl_easy_setopt() options: 163 Public functions in libcurl: 58 Known libcurl bindings: 38 Contributors: 700 +This release includes the following security-related fix: + + o CVE-2009-0037 with the curl advisory here: + http://curl.haxx.se/docs/adv_20090303.html + This release includes the following changes: o Added CURLOPT_NOPROXY and the corresponding --noproxy @@ -24,6 +29,7 @@ This release includes the following changes: o CURLOPT_FTP_CREATE_MISSING_DIRS can now be set to 2 to retry the CWD even when MKD fails o GnuTLS initing moved to curl_global_init() + o Added CURLOPT_REDIR_PROTOCOLS and CURLOPT_PROTOCOLS This release includes the following bugfixes: @@ -59,6 +65,6 @@ advice from friends like these: Patrick Scott, Hidemoto Nakada, Jocelyn Jaubert, Andre Guibert de Bruet, Kamil Dudka, Patrik Thunstrom, Linus Nielsen Feltzing, Mark Incley, Daniel Johnson, James Cheng, Brian J. Murrell, Senthil Raja Velu, - Markus Koetter + Markus Koetter, David Kierznowski, Michal Marek Thanks! (and sorry if I forgot to mention someone) diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 9c4c6afa0..dd3473b99 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -440,6 +440,26 @@ The string given to CURLOPT_URL must be url-encoded and follow RFC 2396 \fICURLOPT_URL\fP is the only option that \fBmust\fP be set before \fIcurl_easy_perform(3)\fP is called. + +\fICURLOPT_PROTOCOLS\fP can be used to limit what protocols libcurl will use +for this transfer, independent of what libcurl has been compiled to +support. That may be useful if you accept the URL from an external source and +want to limit the accessibility. +.IP CURLOPT_PROTOCOLS +Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask +limits what protocols libcurl may use in the transfer. This allows you to have +a libcurl built to support a wide range of protocols but still limit specific +transfers to only be allowed to use a subset of them. By default libcurl will +accept all protocols it supports. See also +\fICURLOPT_REDIR_PROTOCOLS\fP. (Added in 7.19.4) +.IP CURLOPT_REDIR_PROTOCOLS +Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask +limits what protocols libcurl may use in a transfer that it follows to in a +redirect when \fICURLOPT_FOLLOWLOCATION\fP is enabled. This allows you to +limit specific transfers to only be allowed to use a subset of protocols in +redirections. By default libcurl will allow all protocols except for FILE and +SCP. This is a difference compared to pre-7.19.4 versions which +unconditionally would follow to all protocols supported. (Added in 7.19.4) .IP CURLOPT_PROXY Set HTTP proxy to use. The parameter should be a char * to a zero terminated string holding the host name or dotted IP address. To specify port number in @@ -743,6 +763,10 @@ This means that the library will re-send the same request on the new location and follow new Location: headers all the way until no more such headers are returned. \fICURLOPT_MAXREDIRS\fP can be used to limit the number of redirects libcurl will follow. + +NOTE: since 7.19.4, libcurl can limit to what protocols it will automatically +follow. The accepted protocols are set with \fICURLOPT_REDIR_PROTOCOLS\fP and +it excludes the FILE protocol by default. .IP CURLOPT_UNRESTRICTED_AUTH A parameter set to 1 tells the library it can continue to send authentication (user+password) when following locations, even when hostname changed. This diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 7184ecc6a..e429f2e98 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -191,6 +191,7 @@ CURLOPT_PRIVATE 7.10.3 CURLOPT_PROGRESSDATA 7.1 CURLOPT_PROGRESSFUNCTION 7.1 CURLOPT_PROGRESSMODE 7.1 - 7.9.2 +CURLOPT_PROTOCOLS 7.19.4 CURLOPT_PROXY 7.1 CURLOPT_PROXYAUTH 7.10.7 CURLOPT_PROXYPASSWORD 7.19.1 @@ -205,6 +206,7 @@ CURLOPT_RANDOM_FILE 7.7 CURLOPT_RANGE 7.1 CURLOPT_READDATA 7.9.7 CURLOPT_READFUNCTION 7.1 +CURLOPT_REDIR_PROTOCOLS 7.19.4 CURLOPT_REFERER 7.1 CURLOPT_RESUME_FROM 7.1 CURLOPT_RESUME_FROM_LARGE 7.11.0 @@ -261,6 +263,19 @@ CURLOPT_VERBOSE 7.1 CURLOPT_WRITEDATA 7.9.7 CURLOPT_WRITEFUNCTION 7.1 CURLOPT_WRITEHEADER 7.1 +CURLPROTO_ALL 7.19.4 +CURLPROTO_DICT 7.19.4 +CURLPROTO_FILE 7.19.4 +CURLPROTO_FTP 7.19.4 +CURLPROTO_FTPS 7.19.4 +CURLPROTO_HTTP 7.19.4 +CURLPROTO_HTTPS 7.19.4 +CURLPROTO_LDAP 7.19.4 +CURLPROTO_LDAPS 7.19.4 +CURLPROTO_SCP 7.19.4 +CURLPROTO_SFTP 7.19.4 +CURLPROTO_TELNET 7.19.4 +CURLPROTO_TFTP 7.19.4 CURLPROXY_HTTP 7.10 CURLPROXY_HTTP_1_0 7.19.4 CURLPROXY_SOCKS4 7.10 diff --git a/include/curl/curl.h b/include/curl/curl.h index 69fe45757..8d952caab 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -550,6 +550,21 @@ typedef enum { CURLFTPMETHOD_LAST /* not an option, never use */ } curl_ftpmethod; +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_ALL (~0) /* enable everything */ + /* long may be 32 or 64 bits, but we should never depend on anything else but 32 */ #define CURLOPTTYPE_LONG 0 @@ -1185,6 +1200,18 @@ typedef enum { /* Socks Service */ CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/url.c b/lib/url.c index 389fdc84f..6d2e6d4b7 100644 --- a/lib/url.c +++ b/lib/url.c @@ -683,6 +683,12 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->new_file_perms = 0644; /* Default permissions */ set->new_directory_perms = 0755; /* Default permissions */ + /* for the *protocols fields we don't use the CURLPROTO_ALL convenience + define since we internally only use the lower 16 bits for the passed + in bitmask to not conflict with the private bits */ + set->allowed_protocols = PROT_EXTMASK; + set->redir_protocols = + PROT_EXTMASK & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* @@ -2217,6 +2223,22 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.scope = (unsigned int) va_arg(param, long); break; + case CURLOPT_PROTOCOLS: + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + data->set.allowed_protocols = va_arg(param, long) & PROT_EXTMASK; + break; + + case CURLOPT_REDIR_PROTOCOLS: + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + data->set.redir_protocols = va_arg(param, long) & PROT_EXTMASK; + break; + default: /* unknown tag and its companion, just ignore: */ result = CURLE_FAILED_INIT; /* correct this */ @@ -3371,7 +3393,19 @@ static CURLcode setup_connection_internals(struct SessionHandle *data, for (pp = protocols; (p = *pp) != NULL; pp++) if(Curl_raw_equal(p->scheme, conn->protostr)) { - /* Protocol found in table. Perform setup complement if some. */ + /* Protocol found in table. Check if allowed */ + if(!(data->set.allowed_protocols & p->protocol)) + /* nope, get out */ + break; + + /* it is allowed for "normal" request, now do an extra check if this is + the result of a redirect */ + if(data->state.this_is_a_follow && + !(data->set.redir_protocols & p->protocol)) + /* nope, get out */ + break; + + /* Perform setup complement if some. */ conn->handler = p; if(p->setup_connection) { diff --git a/lib/urldata.h b/lib/urldata.h index 6969f1ebb..a50ede005 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -891,19 +891,26 @@ struct connectdata { long connectindex; /* what index in the connection cache connects index this particular struct has */ long protocol; /* PROT_* flags concerning the protocol set */ -#define PROT_MISSING (1<<0) -#define PROT_HTTP (1<<2) -#define PROT_HTTPS (1<<3) -#define PROT_FTP (1<<4) -#define PROT_TELNET (1<<5) -#define PROT_DICT (1<<6) -#define PROT_LDAP (1<<7) -#define PROT_FILE (1<<8) -#define PROT_FTPS (1<<9) -#define PROT_SSL (1<<10) /* protocol requires SSL */ -#define PROT_TFTP (1<<11) -#define PROT_SCP (1<<12) -#define PROT_SFTP (1<<13) +#define PROT_HTTP CURLPROTO_HTTP +#define PROT_HTTPS CURLPROTO_HTTPS +#define PROT_FTP CURLPROTO_FTP +#define PROT_TELNET CURLPROTO_TELNET +#define PROT_DICT CURLPROTO_DICT +#define PROT_LDAP CURLPROTO_LDAP +#define PROT_FILE CURLPROTO_FILE +#define PROT_FTPS CURLPROTO_FTPS +#define PROT_TFTP CURLPROTO_TFTP +#define PROT_SCP CURLPROTO_SCP +#define PROT_SFTP CURLPROTO_SFTP + +/* CURLPROTO_TFTP (1<<11) is currently the highest used bit in the public + bitmask. We make sure we use "private bits" above the first 16 to make + things easier. */ + +#define PROT_EXTMASK 0xffff + +#define PROT_SSL (1<<22) /* protocol requires SSL */ +#define PROT_MISSING (1<<23) #define PROT_CLOSEACTION PROT_FTP /* these ones need action before socket close */ @@ -1533,6 +1540,8 @@ struct UserDefined { via an HTTP proxy */ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ unsigned int scope; /* address scope for IPv6 */ + long allowed_protocols; + long redir_protocols; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) long socks5_gssapi_nec; /* flag to support nec socks5 server */ #endif -- cgit v1.2.3