mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-21 14:09:27 +00:00
feat(real-world-vfc-slice): add labeled OpenSSL/Firefox/Chromium/curl pair corpus
Harvest 176 isolated vuln-vs-fix functions (109 CVEs, 352 training rows) into benchmarks/pairs/vfc with provenance and a JSONL training manifest. Score the slice as an honesty dashboard (ousast pairs --slice vfc); keep the pair gate on the local fixtures only.
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
/* Provenance: curl/curl Curl_follow (fixed).
|
||||
* repo: curl/curl
|
||||
* commit: 7214288898f5625a6cc196e22a74232eada7861c
|
||||
* parent: 184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9
|
||||
* commit_url: https://github.com/curl/curl/commit/7214288898f5625a6cc196e22a74232eada7861c
|
||||
* cve: CVE-2021-22876
|
||||
* license: curl
|
||||
* function: Curl_follow
|
||||
* relpath: lib/transfer.c
|
||||
*/
|
||||
|
||||
* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
|
||||
* as given by the remote server and set up the new URL to request.
|
||||
*
|
||||
* This function DOES NOT FREE the given url.
|
||||
*/
|
||||
CURLcode Curl_follow(struct Curl_easy *data,
|
||||
char *newurl, /* the Location: string */
|
||||
followtype type) /* see transfer.h */
|
||||
{
|
||||
#ifdef CURL_DISABLE_HTTP
|
||||
(void)data;
|
||||
(void)newurl;
|
||||
(void)type;
|
||||
/* Location: following will not happen when HTTP is disabled */
|
||||
return CURLE_TOO_MANY_REDIRECTS;
|
||||
#else
|
||||
|
||||
/* Location: redirect */
|
||||
bool disallowport = FALSE;
|
||||
bool reachedmax = FALSE;
|
||||
CURLUcode uc;
|
||||
|
||||
DEBUGASSERT(type != FOLLOW_NONE);
|
||||
|
||||
if(type == FOLLOW_REDIR) {
|
||||
if((data->set.maxredirs != -1) &&
|
||||
(data->state.followlocation >= data->set.maxredirs)) {
|
||||
reachedmax = TRUE;
|
||||
type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
|
||||
to URL */
|
||||
}
|
||||
else {
|
||||
/* mark the next request as a followed location: */
|
||||
data->state.this_is_a_follow = TRUE;
|
||||
|
||||
data->state.followlocation++; /* count location-followers */
|
||||
|
||||
if(data->set.http_auto_referer) {
|
||||
CURLU *u;
|
||||
char *referer;
|
||||
|
||||
/* We are asked to automatically set the previous URL as the referer
|
||||
when we get the next URL. We pick the ->url field, which may or may
|
||||
not be 100% correct */
|
||||
|
||||
if(data->state.referer_alloc) {
|
||||
Curl_safefree(data->state.referer);
|
||||
data->state.referer_alloc = FALSE;
|
||||
}
|
||||
|
||||
/* Make a copy of the URL without crenditals and fragment */
|
||||
u = curl_url();
|
||||
if(!u)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0);
|
||||
if(!uc)
|
||||
uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0);
|
||||
if(!uc)
|
||||
uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
|
||||
if(!uc)
|
||||
uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
|
||||
if(!uc)
|
||||
uc = curl_url_get(u, CURLUPART_URL, &referer, 0);
|
||||
|
||||
curl_url_cleanup(u);
|
||||
|
||||
if(uc || referer == NULL)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
data->state.referer = referer;
|
||||
data->state.referer_alloc = TRUE; /* yes, free this later */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((type != FOLLOW_RETRY) &&
|
||||
(data->req.httpcode != 401) && (data->req.httpcode != 407) &&
|
||||
Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN))
|
||||
/* If this is not redirect due to a 401 or 407 response and an absolute
|
||||
URL: don't allow a custom port number */
|
||||
disallowport = TRUE;
|
||||
|
||||
DEBUGASSERT(data->state.uh);
|
||||
uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
|
||||
(type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
|
||||
((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) );
|
||||
if(uc) {
|
||||
if(type != FOLLOW_FAKE)
|
||||
return Curl_uc_to_curlcode(uc);
|
||||
|
||||
/* the URL could not be parsed for some reason, but since this is FAKE
|
||||
mode, just duplicate the field as-is */
|
||||
newurl = strdup(newurl);
|
||||
if(!newurl)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
|
||||
uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
|
||||
if(uc)
|
||||
return Curl_uc_to_curlcode(uc);
|
||||
}
|
||||
|
||||
if(type == FOLLOW_FAKE) {
|
||||
/* we're only figuring out the new url if we would've followed locations
|
||||
but now we're done so we can get out! */
|
||||
data->info.wouldredirect = newurl;
|
||||
|
||||
if(reachedmax) {
|
||||
failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
|
||||
return CURLE_TOO_MANY_REDIRECTS;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
if(disallowport)
|
||||
data->state.allow_port = FALSE;
|
||||
|
||||
if(data->state.url_alloc)
|
||||
Curl_safefree(data->state.url);
|
||||
|
||||
data->state.url = newurl;
|
||||
data->state.url_alloc = TRUE;
|
||||
|
||||
infof(data, "Issue another request to this URL: '%s'\n", data->state.url);
|
||||
|
||||
/*
|
||||
* We get here when the HTTP code is 300-399 (and 401). We need to perform
|
||||
* differently based on exactly what return code there was.
|
||||
*
|
||||
* News from 7.10.6: we can also get here on a 401 or 407, in case we act on
|
||||
* a HTTP (proxy-) authentication scheme other than Basic.
|
||||
*/
|
||||
switch(data->info.httpcode) {
|
||||
/* 401 - Act on a WWW-Authenticate, we keep on moving and do the
|
||||
Authorization: XXXX header in the HTTP request code snippet */
|
||||
/* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
|
||||
Proxy-Authorization: XXXX header in the HTTP request code snippet */
|
||||
/* 300 - Multiple Choices */
|
||||
/* 306 - Not used */
|
||||
/* 307 - Temporary Redirect */
|
||||
default: /* for all above (and the unknown ones) */
|
||||
/* Some codes are explicitly mentioned since I've checked RFC2616 and they
|
||||
* seem to be OK to POST to.
|
||||
*/
|
||||
break;
|
||||
case 301: /* Moved Permanently */
|
||||
/* (quote from RFC7231, section 6.4.2)
|
||||
*
|
||||
* Note: For historical reasons, a user agent MAY change the request
|
||||
* method from POST to GET for the subsequent request. If this
|
||||
* behavior is undesired, the 307 (Temporary Redirect) status code
|
||||
* can be used instead.
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* Many webservers expect this, so these servers often answers to a POST
|
||||
* request with an error page. To be sure that libcurl gets the page that
|
||||
* most user agents would get, libcurl has to force GET.
|
||||
*
|
||||
* This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
|
||||
* can be overridden with CURLOPT_POSTREDIR.
|
||||
*/
|
||||
if((data->state.httpreq == HTTPREQ_POST
|
||||
|| data->state.httpreq == HTTPREQ_POST_FORM
|
||||
|| data->state.httpreq == HTTPREQ_POST_MIME)
|
||||
&& !(data->set.keep_post & CURL_REDIR_POST_301)) {
|
||||
infof(data, "Switch from POST to GET\n");
|
||||
data->state.httpreq = HTTPREQ_GET;
|
||||
}
|
||||
break;
|
||||
case 302: /* Found */
|
||||
/* (quote from RFC7231, section 6.4.3)
|
||||
*
|
||||
* Note: For historical reasons, a user agent MAY change the request
|
||||
* method from POST to GET for the subsequent request. If this
|
||||
* behavior is undesired, the 307 (Temporary Redirect) status code
|
||||
* can be used instead.
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* Many webservers expect this, so these servers often answers to a POST
|
||||
* request with an error page. To be sure that libcurl gets the page that
|
||||
* most user agents would get, libcurl has to force GET.
|
||||
*
|
||||
* This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
|
||||
* can be overridden with CURLOPT_POSTREDIR.
|
||||
*/
|
||||
if((data->state.httpreq == HTTPREQ_POST
|
||||
|| data->state.httpreq == HTTPREQ_POST_FORM
|
||||
|| data->state.httpreq == HTTPREQ_POST_MIME)
|
||||
&& !(data->set.keep_post & CURL_REDIR_POST_302)) {
|
||||
infof(data, "Switch from POST to GET\n");
|
||||
data->state.httpreq = HTTPREQ_GET;
|
||||
}
|
||||
break;
|
||||
|
||||
case 303: /* See Other */
|
||||
/* 'See Other' location is not the resource but a substitute for the
|
||||
* resource. In this case we switch the method to GET/HEAD, unless the
|
||||
* method is POST and the user specified to keep it as POST.
|
||||
* https://github.com/curl/curl/issues/5237#issuecomment-614641049
|
||||
*/
|
||||
if(data->state.httpreq != HTTPREQ_GET &&
|
||||
((data->state.httpreq != HTTPREQ_POST &&
|
||||
data->state.httpreq != HTTPREQ_POST_FORM &&
|
||||
data->state.httpreq != HTTPREQ_POST_MIME) ||
|
||||
!(data->set.keep_post & CURL_REDIR_POST_303))) {
|
||||
data->state.httpreq = HTTPREQ_GET;
|
||||
data->set.upload = false;
|
||||
infof(data, "Switch to %s\n",
|
||||
data->set.opt_no_body?"HEAD":"GET");
|
||||
}
|
||||
break;
|
||||
case 304: /* Not Modified */
|
||||
/* 304 means we did a conditional request and it was "Not modified".
|
||||
* We shouldn't get any Location: header in this response!
|
||||
*/
|
||||
break;
|
||||
case 305: /* Use Proxy */
|
||||
/* (quote from RFC2616, section 10.3.6):
|
||||
* "The requested resource MUST be accessed through the proxy given
|
||||
* by the Location field. The Location field gives the URI of the
|
||||
* proxy. The recipient is expected to repeat this single request
|
||||
* via the proxy. 305 responses MUST only be generated by origin
|
||||
* servers."
|
||||
*/
|
||||
break;
|
||||
}
|
||||
Curl_pgrsTime(data, TIMER_REDIRECT);
|
||||
Curl_pgrsResetTransferSizes(data);
|
||||
|
||||
return CURLE_OK;
|
||||
#endif /* CURL_DISABLE_HTTP */
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/* Provenance: curl/curl Curl_follow (vuln).
|
||||
* repo: curl/curl
|
||||
* commit: 184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9
|
||||
* parent: 184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9
|
||||
* commit_url: https://github.com/curl/curl/commit/7214288898f5625a6cc196e22a74232eada7861c
|
||||
* cve: CVE-2021-22876
|
||||
* license: curl
|
||||
* function: Curl_follow
|
||||
* relpath: lib/transfer.c
|
||||
*/
|
||||
|
||||
* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
|
||||
* as given by the remote server and set up the new URL to request.
|
||||
*
|
||||
* This function DOES NOT FREE the given url.
|
||||
*/
|
||||
CURLcode Curl_follow(struct Curl_easy *data,
|
||||
char *newurl, /* the Location: string */
|
||||
followtype type) /* see transfer.h */
|
||||
{
|
||||
#ifdef CURL_DISABLE_HTTP
|
||||
(void)data;
|
||||
(void)newurl;
|
||||
(void)type;
|
||||
/* Location: following will not happen when HTTP is disabled */
|
||||
return CURLE_TOO_MANY_REDIRECTS;
|
||||
#else
|
||||
|
||||
/* Location: redirect */
|
||||
bool disallowport = FALSE;
|
||||
bool reachedmax = FALSE;
|
||||
CURLUcode uc;
|
||||
|
||||
DEBUGASSERT(type != FOLLOW_NONE);
|
||||
|
||||
if(type == FOLLOW_REDIR) {
|
||||
if((data->set.maxredirs != -1) &&
|
||||
(data->state.followlocation >= data->set.maxredirs)) {
|
||||
reachedmax = TRUE;
|
||||
type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
|
||||
to URL */
|
||||
}
|
||||
else {
|
||||
/* mark the next request as a followed location: */
|
||||
data->state.this_is_a_follow = TRUE;
|
||||
|
||||
data->state.followlocation++; /* count location-followers */
|
||||
|
||||
if(data->set.http_auto_referer) {
|
||||
/* We are asked to automatically set the previous URL as the referer
|
||||
when we get the next URL. We pick the ->url field, which may or may
|
||||
not be 100% correct */
|
||||
|
||||
if(data->state.referer_alloc) {
|
||||
Curl_safefree(data->state.referer);
|
||||
data->state.referer_alloc = FALSE;
|
||||
}
|
||||
|
||||
data->state.referer = strdup(data->state.url);
|
||||
if(!data->state.referer)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
data->state.referer_alloc = TRUE; /* yes, free this later */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((type != FOLLOW_RETRY) &&
|
||||
(data->req.httpcode != 401) && (data->req.httpcode != 407) &&
|
||||
Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN))
|
||||
/* If this is not redirect due to a 401 or 407 response and an absolute
|
||||
URL: don't allow a custom port number */
|
||||
disallowport = TRUE;
|
||||
|
||||
DEBUGASSERT(data->state.uh);
|
||||
uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
|
||||
(type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
|
||||
((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) );
|
||||
if(uc) {
|
||||
if(type != FOLLOW_FAKE)
|
||||
return Curl_uc_to_curlcode(uc);
|
||||
|
||||
/* the URL could not be parsed for some reason, but since this is FAKE
|
||||
mode, just duplicate the field as-is */
|
||||
newurl = strdup(newurl);
|
||||
if(!newurl)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
|
||||
uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
|
||||
if(uc)
|
||||
return Curl_uc_to_curlcode(uc);
|
||||
}
|
||||
|
||||
if(type == FOLLOW_FAKE) {
|
||||
/* we're only figuring out the new url if we would've followed locations
|
||||
but now we're done so we can get out! */
|
||||
data->info.wouldredirect = newurl;
|
||||
|
||||
if(reachedmax) {
|
||||
failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
|
||||
return CURLE_TOO_MANY_REDIRECTS;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
if(disallowport)
|
||||
data->state.allow_port = FALSE;
|
||||
|
||||
if(data->state.url_alloc)
|
||||
Curl_safefree(data->state.url);
|
||||
|
||||
data->state.url = newurl;
|
||||
data->state.url_alloc = TRUE;
|
||||
|
||||
infof(data, "Issue another request to this URL: '%s'\n", data->state.url);
|
||||
|
||||
/*
|
||||
* We get here when the HTTP code is 300-399 (and 401). We need to perform
|
||||
* differently based on exactly what return code there was.
|
||||
*
|
||||
* News from 7.10.6: we can also get here on a 401 or 407, in case we act on
|
||||
* a HTTP (proxy-) authentication scheme other than Basic.
|
||||
*/
|
||||
switch(data->info.httpcode) {
|
||||
/* 401 - Act on a WWW-Authenticate, we keep on moving and do the
|
||||
Authorization: XXXX header in the HTTP request code snippet */
|
||||
/* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
|
||||
Proxy-Authorization: XXXX header in the HTTP request code snippet */
|
||||
/* 300 - Multiple Choices */
|
||||
/* 306 - Not used */
|
||||
/* 307 - Temporary Redirect */
|
||||
default: /* for all above (and the unknown ones) */
|
||||
/* Some codes are explicitly mentioned since I've checked RFC2616 and they
|
||||
* seem to be OK to POST to.
|
||||
*/
|
||||
break;
|
||||
case 301: /* Moved Permanently */
|
||||
/* (quote from RFC7231, section 6.4.2)
|
||||
*
|
||||
* Note: For historical reasons, a user agent MAY change the request
|
||||
* method from POST to GET for the subsequent request. If this
|
||||
* behavior is undesired, the 307 (Temporary Redirect) status code
|
||||
* can be used instead.
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* Many webservers expect this, so these servers often answers to a POST
|
||||
* request with an error page. To be sure that libcurl gets the page that
|
||||
* most user agents would get, libcurl has to force GET.
|
||||
*
|
||||
* This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
|
||||
* can be overridden with CURLOPT_POSTREDIR.
|
||||
*/
|
||||
if((data->state.httpreq == HTTPREQ_POST
|
||||
|| data->state.httpreq == HTTPREQ_POST_FORM
|
||||
|| data->state.httpreq == HTTPREQ_POST_MIME)
|
||||
&& !(data->set.keep_post & CURL_REDIR_POST_301)) {
|
||||
infof(data, "Switch from POST to GET\n");
|
||||
data->state.httpreq = HTTPREQ_GET;
|
||||
}
|
||||
break;
|
||||
case 302: /* Found */
|
||||
/* (quote from RFC7231, section 6.4.3)
|
||||
*
|
||||
* Note: For historical reasons, a user agent MAY change the request
|
||||
* method from POST to GET for the subsequent request. If this
|
||||
* behavior is undesired, the 307 (Temporary Redirect) status code
|
||||
* can be used instead.
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* Many webservers expect this, so these servers often answers to a POST
|
||||
* request with an error page. To be sure that libcurl gets the page that
|
||||
* most user agents would get, libcurl has to force GET.
|
||||
*
|
||||
* This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
|
||||
* can be overridden with CURLOPT_POSTREDIR.
|
||||
*/
|
||||
if((data->state.httpreq == HTTPREQ_POST
|
||||
|| data->state.httpreq == HTTPREQ_POST_FORM
|
||||
|| data->state.httpreq == HTTPREQ_POST_MIME)
|
||||
&& !(data->set.keep_post & CURL_REDIR_POST_302)) {
|
||||
infof(data, "Switch from POST to GET\n");
|
||||
data->state.httpreq = HTTPREQ_GET;
|
||||
}
|
||||
break;
|
||||
|
||||
case 303: /* See Other */
|
||||
/* 'See Other' location is not the resource but a substitute for the
|
||||
* resource. In this case we switch the method to GET/HEAD, unless the
|
||||
* method is POST and the user specified to keep it as POST.
|
||||
* https://github.com/curl/curl/issues/5237#issuecomment-614641049
|
||||
*/
|
||||
if(data->state.httpreq != HTTPREQ_GET &&
|
||||
((data->state.httpreq != HTTPREQ_POST &&
|
||||
data->state.httpreq != HTTPREQ_POST_FORM &&
|
||||
data->state.httpreq != HTTPREQ_POST_MIME) ||
|
||||
!(data->set.keep_post & CURL_REDIR_POST_303))) {
|
||||
data->state.httpreq = HTTPREQ_GET;
|
||||
data->set.upload = false;
|
||||
infof(data, "Switch to %s\n",
|
||||
data->set.opt_no_body?"HEAD":"GET");
|
||||
}
|
||||
break;
|
||||
case 304: /* Not Modified */
|
||||
/* 304 means we did a conditional request and it was "Not modified".
|
||||
* We shouldn't get any Location: header in this response!
|
||||
*/
|
||||
break;
|
||||
case 305: /* Use Proxy */
|
||||
/* (quote from RFC2616, section 10.3.6):
|
||||
* "The requested resource MUST be accessed through the proxy given
|
||||
* by the Location field. The Location field gives the URI of the
|
||||
* proxy. The recipient is expected to repeat this single request
|
||||
* via the proxy. 305 responses MUST only be generated by origin
|
||||
* servers."
|
||||
*/
|
||||
break;
|
||||
}
|
||||
Curl_pgrsTime(data, TIMER_REDIRECT);
|
||||
Curl_pgrsResetTransferSizes(data);
|
||||
|
||||
return CURLE_OK;
|
||||
#endif /* CURL_DISABLE_HTTP */
|
||||
}
|
||||
Reference in New Issue
Block a user