Skip to content

Commit 11dacb0

Browse files
committed
[http] strictly check arguments in ProduceExe
Always use DecodeUrlOptionValue method when processing URL arguments or URL string. Internally method provides escape symbols for quotes and backslash. If expecting numeric value - remove all symbols keeping alphanumeric, '.', '+', '-' and ':'
1 parent 83fdbf3 commit 11dacb0

1 file changed

Lines changed: 61 additions & 39 deletions

File tree

net/httpsniff/src/TRootSnifferFull.cxx

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -586,47 +586,46 @@ Bool_t TRootSnifferFull::ProduceExe(const std::string &path, const std::string &
586586
return debug != nullptr;
587587
const char *rest_url = pos + strlen(method_name) + 7;
588588
if (*rest_url == '&') ++rest_url;
589-
call_args.Form("\"%s\"", rest_url);
589+
call_args.Append("\"");
590+
call_args.Append(DecodeUrlOptionValue(rest_url, kTRUE));
591+
call_args.Append("\"");
590592
break;
591593
}
592594

593595
TString sval;
594596
const char *val = url.GetValueFromOptions(arg->GetName());
595-
if (val) {
596-
sval = DecodeUrlOptionValue(val, kFALSE);
597-
val = sval.Data();
598-
}
597+
if (val)
598+
sval = DecodeUrlOptionValue(val, kTRUE);
599+
600+
Bool_t sanitize_numeric = kFALSE;
599601

600-
if ((val != nullptr) && (strcmp(val, "_this_") == 0)) {
602+
if (sval == "_this_") {
601603
// special case - object itself is used as argument
602604
sval.Form("(%s*)0x%zx", obj_cl->GetName(), (size_t)obj_ptr);
603-
val = sval.Data();
604-
} else if ((val != nullptr) && (fCurrentArg != nullptr) && (fCurrentArg->GetPostData() != nullptr)) {
605+
} else if ((fCurrentArg != nullptr) && (fCurrentArg->GetPostData() != nullptr)) {
605606
// process several arguments which are specific for post requests
606-
if (strcmp(val, "_post_object_xml_") == 0) {
607+
if (sval == "_post_object_xml_") {
607608
// post data has extra 0 at the end and can be used as null-terminated string
608609
post_obj = TBufferXML::ConvertFromXML((const char *)fCurrentArg->GetPostData());
609-
if (!post_obj) {
610+
if (!post_obj)
610611
sval = "0";
611-
} else {
612+
else {
612613
sval.Form("(%s*)0x%zx", post_obj->ClassName(), (size_t)post_obj);
613614
if (url.HasOption("_destroy_post_"))
614615
garbage.Add(post_obj);
615616
}
616-
val = sval.Data();
617-
} else if (strcmp(val, "_post_object_json_") == 0) {
617+
} else if (sval == "_post_object_json_") {
618618
// post data has extra 0 at the end and can be used as null-terminated string
619619
post_obj = TBufferJSON::ConvertFromJSON((const char *)fCurrentArg->GetPostData());
620-
if (!post_obj) {
620+
if (!post_obj)
621621
sval = "0";
622-
} else {
622+
else {
623623
sval.Form("(%s*)0x%zx", post_obj->ClassName(), (size_t)post_obj);
624624
if (url.HasOption("_destroy_post_"))
625625
garbage.Add(post_obj);
626626
}
627-
val = sval.Data();
628-
} else if ((strcmp(val, "_post_object_") == 0) && url.HasOption("_post_class_")) {
629-
TString clname = url.GetValueFromOptions("_post_class_");
627+
} else if ((sval == "_post_object_") && url.HasOption("_post_class_")) {
628+
TString clname = DecodeUrlOptionValue(url.GetValueFromOptions("_post_class_"), kTRUE);
630629
TClass *arg_cl = gROOT->GetClass(clname, kTRUE, kTRUE);
631630
if ((arg_cl != nullptr) && (arg_cl->GetBaseClassOffset(TObject::Class()) == 0) && (post_obj == nullptr)) {
632631
post_obj = (TObject *)arg_cl->New();
@@ -643,38 +642,61 @@ Bool_t TRootSnifferFull::ProduceExe(const std::string &path, const std::string &
643642
garbage.Add(post_obj);
644643
}
645644
}
646-
sval.Form("(%s*)0x%zx", clname.Data(), (size_t)post_obj);
647-
val = sval.Data();
648-
} else if (strcmp(val, "_post_data_") == 0) {
645+
if (!post_obj)
646+
sval = "0";
647+
else
648+
sval.Form("(%s*)0x%zx", clname.Data(), (size_t)post_obj);
649+
} else if (sval == "_post_data_")
649650
sval.Form("(void*)0x%zx", (size_t)fCurrentArg->GetPostData());
650-
val = sval.Data();
651-
} else if (strcmp(val, "_post_length_") == 0) {
651+
else if (sval == "_post_length_")
652652
sval.Form("%ld", (long)fCurrentArg->GetPostDataLength());
653-
val = sval.Data();
654-
}
655-
}
653+
else
654+
sanitize_numeric = kTRUE;
655+
} else
656+
sanitize_numeric = kTRUE;
656657

657-
if (!val)
658-
val = arg->GetDefault();
658+
if (sval.IsNull() && arg->GetDefault())
659+
sval = arg->GetDefault();
659660

660661
if (debug)
661-
debug->append(Form(" Argument:%s Type:%s Value:%s \n", arg->GetName(), arg->GetFullTypeName(),
662-
val ? val : "<missed>"));
663-
if (!val)
664-
return debug != nullptr;
662+
debug->append(
663+
TString::Format(" Argument:%s Type:%s Value:%s \n", arg->GetName(), arg->GetFullTypeName(), sval.Data())
664+
.Data());
665665

666666
if (call_args.Length() > 0)
667667
call_args += ", ";
668668

669-
if ((strcmp(arg->GetFullTypeName(), "const char*") == 0) || (strcmp(arg->GetFullTypeName(), "Option_t*") == 0)) {
670-
int len = strlen(val);
671-
if ((strlen(val) < 2) || (*val != '\"') || (val[len - 1] != '\"'))
672-
call_args.Append(TString::Format("\"%s\"", val));
673-
else
674-
call_args.Append(val);
669+
Bool_t isstr = (strcmp(arg->GetFullTypeName(), "const char*") == 0) ||
670+
(strcmp(arg->GetFullTypeName(), "Option_t*") == 0) ||
671+
(strcmp(arg->GetFullTypeName(), "string") == 0);
672+
673+
if (isstr) {
674+
// check that quotes provided for the string argument
675+
// all special characters were escaped before
676+
if (sval.IsNull())
677+
sval = "\"\"";
678+
else {
679+
if (sval[0] != '"')
680+
sval.Prepend("\"");
681+
if (sval[sval.Length() - 1] != '"')
682+
sval.Append("\"");
683+
}
675684
} else {
676-
call_args.Append(val);
685+
// for numeric types keep only numeric and alphabetic characters
686+
// exclude others - especially remove all escape characters
687+
if (sanitize_numeric) {
688+
TString sanitized;
689+
for(Size_t i = 0; i < sval.Length(); ++i) {
690+
if (std::isalnum(sval[i]) || std::strchr(".:+-", sval[i]))
691+
sanitized.Append(sval[i]);
692+
}
693+
sval = sanitized;
694+
}
695+
if (sval.IsNull())
696+
sval = "0";
677697
}
698+
699+
call_args.Append(sval);
678700
}
679701

680702
TMethodCall *call = nullptr;

0 commit comments

Comments
 (0)