2023-05-17 Fred Gleason <fredg@paravelsystems.com>

* Fixed a vulnerabilities in 'RDFormPost' that could allow maximum
	post length restrictions to be bypassed by use of a maliciously
	crafted HTTP transaction.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason
2023-05-17 14:38:52 -04:00
parent 5eb1c39231
commit 41224a393a
3 changed files with 62 additions and 16 deletions

View File

@@ -24124,3 +24124,7 @@
2023-05-17 Fred Gleason <fredg@paravelsystems.com> 2023-05-17 Fred Gleason <fredg@paravelsystems.com>
* Fixed a regression in the WebAPI that caused imports to bypass the * Fixed a regression in the WebAPI that caused imports to bypass the
maximum file size limitation set the 'System Settings' in rdadmin(1). maximum file size limitation set the 'System Settings' in rdadmin(1).
2023-05-17 Fred Gleason <fredg@paravelsystems.com>
* Fixed a vulnerabilities in 'RDFormPost' that could allow maximum
post length restrictions to be bypassed by use of a maliciously
crafted HTTP transaction.

View File

@@ -2,7 +2,7 @@
// //
// Handle data from an HTML form. // Handle data from an HTML form.
// //
// (C) Copyright 2009-2021 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2009-2023 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@@ -43,6 +43,7 @@ RDFormPost::RDFormPost(RDFormPost::Encoding encoding,int64_t maxsize,
post_auto_delete=auto_delete; post_auto_delete=auto_delete;
post_data=NULL; post_data=NULL;
post_tempdir=NULL; post_tempdir=NULL;
post_bytes_downloaded=0;
// //
// Client Info // Client Info
@@ -101,7 +102,13 @@ RDFormPost::RDFormPost(RDFormPost::Encoding encoding,int64_t maxsize,
// (Perhaps) autodetect the encoding type // (Perhaps) autodetect the encoding type
// //
char first[2]; char first[2];
RDCheckExitCode("RDFormPost::RDFormPost read",read(0,first,1)); ssize_t s;
if((s=read(0,first,1))<=0) {
post_error=RDFormPost::ErrorMalformedData;
return;
}
post_bytes_downloaded+=1;
if(post_encoding==RDFormPost::AutoEncoded) { if(post_encoding==RDFormPost::AutoEncoded) {
if(first[0]=='-') { if(first[0]=='-') {
post_encoding=RDFormPost::MultipartEncoded; post_encoding=RDFormPost::MultipartEncoded;
@@ -138,9 +145,11 @@ RDFormPost::~RDFormPost()
if(post_tempdir!=NULL) { if(post_tempdir!=NULL) {
delete post_tempdir; delete post_tempdir;
} }
/*
if(post_data!=NULL) { if(post_data!=NULL) {
delete post_data; delete post_data;
} }
*/
} }
} }
@@ -563,12 +572,13 @@ void RDFormPost::LoadUrlEncoding(char first)
post_error=RDFormPost::ErrorMalformedData; post_error=RDFormPost::ErrorMalformedData;
return; return;
} }
post_bytes_downloaded+=n;
total_read+=n; total_read+=n;
} }
// post_data[post_content_length]=0;
post_data[total_read]=0; post_data[total_read]=0;
lines=QString(post_data).split("&"); lines=QString(post_data).split("&");
for(int i=0;i<lines.size();i++) { for(int i=0;i<lines.size();i++) {
line=lines[i].split("=",QString::KeepEmptyParts); line=lines[i].split("=",QString::KeepEmptyParts);
for(int j=2;j<line.size();j++) { for(int j=2;j<line.size();j++) {
@@ -596,6 +606,8 @@ void RDFormPost::LoadUrlEncoding(char first)
void RDFormPost::LoadMultipartEncoding(char first) void RDFormPost::LoadMultipartEncoding(char first)
{ {
bool ok=false;
// //
// Create Stream Reader // Create Stream Reader
// //
@@ -627,7 +639,11 @@ void RDFormPost::LoadMultipartEncoding(char first)
// //
// Get Separator Line // Get Separator Line
// //
post_separator=first+QString::fromUtf8(GetLine()).trimmed(); post_separator=first+QString::fromUtf8(GetLine(&ok)).trimmed();
if(!ok) {
post_error=RDFormPost::ErrorMalformedData;
return;
}
// //
// Read Mime Parts // Read Mime Parts
@@ -638,7 +654,11 @@ void RDFormPost::LoadMultipartEncoding(char first)
bool again=false; bool again=false;
do { do {
again=GetMimePart(&name,&value,&is_file); again=GetMimePart(&name,&value,&is_file,&ok);
if(!ok) {
post_error=RDFormPost::ErrorMalformedData;
return;
}
post_values[name]=value; post_values[name]=value;
post_filenames[name]=is_file; post_filenames[name]=is_file;
} while(again); } while(again);
@@ -646,7 +666,8 @@ void RDFormPost::LoadMultipartEncoding(char first)
} }
bool RDFormPost::GetMimePart(QString *name,QString *value,bool *is_file) bool RDFormPost::GetMimePart(QString *name,QString *value,bool *is_file,
bool *ok)
{ {
QString line; QString line;
int fd=-1; int fd=-1;
@@ -659,7 +680,10 @@ bool RDFormPost::GetMimePart(QString *name,QString *value,bool *is_file)
// Headers // Headers
// //
do { do {
line=QString::fromUtf8(GetLine()); line=QString::fromUtf8(GetLine(ok));
if(!ok) {
return false;
}
QStringList f0=line.split(":"); QStringList f0=line.split(":");
if(f0.size()==2) { if(f0.size()==2) {
if(f0[0].toLower()=="content-disposition") { if(f0[0].toLower()=="content-disposition") {
@@ -692,20 +716,32 @@ bool RDFormPost::GetMimePart(QString *name,QString *value,bool *is_file)
// //
if(*is_file) { if(*is_file) {
QByteArray data; QByteArray data;
data=GetLine(); data=GetLine(ok);
if(!ok) {
return false;
}
line=QString::fromUtf8(data).trimmed(); line=QString::fromUtf8(data).trimmed();
while(!line.contains(post_separator)) { while(!line.contains(post_separator)) {
RDCheckExitCode("RDFormPost::GetMimePart write", RDCheckExitCode("RDFormPost::GetMimePart write",
write(fd,data,data.length())); write(fd,data,data.length()));
data=GetLine(); data=GetLine(ok);
if(!ok) {
return false;
}
line=QString::fromUtf8(data).trimmed(); line=QString::fromUtf8(data).trimmed();
} }
} }
else { else {
line=QString::fromUtf8(GetLine()); line=QString::fromUtf8(GetLine(ok));
if(!ok) {
return false;
}
while((!line.isEmpty())&&(!line.contains(post_separator))) { while((!line.isEmpty())&&(!line.contains(post_separator))) {
*value+=line; *value+=line;
line=QString::fromUtf8(GetLine()); line=QString::fromUtf8(GetLine(ok));
if(!ok) {
return false;
}
} }
*value=value->trimmed(); *value=value->trimmed();
} }
@@ -721,13 +757,18 @@ bool RDFormPost::GetMimePart(QString *name,QString *value,bool *is_file)
} }
QByteArray RDFormPost::GetLine() const QByteArray RDFormPost::GetLine(bool *ok)
{ {
char *data=NULL; char *data=NULL;
size_t n=0; size_t n=0;
n=getline(&data,&n,post_stream); if((n=getline(&data,&n,post_stream))<0) {
*ok=false;
}
post_bytes_downloaded+=n;
QByteArray ret(data,n); QByteArray ret(data,n);
free(data); free(data);
*ok=true;
return ret; return ret;
} }

View File

@@ -2,7 +2,7 @@
// //
// Handle POST data from an HTML form. // Handle POST data from an HTML form.
// //
// (C) Copyright 2009-2020 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2009-2023 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@@ -67,8 +67,8 @@ class RDFormPost
private: private:
void LoadUrlEncoding(char first); void LoadUrlEncoding(char first);
void LoadMultipartEncoding(char first); void LoadMultipartEncoding(char first);
bool GetMimePart(QString *name,QString *value,bool *is_file); bool GetMimePart(QString *name,QString *value,bool *is_file,bool *ok);
QByteArray GetLine() const; QByteArray GetLine(bool *ok);
QHostAddress post_client_address; QHostAddress post_client_address;
RDFormPost::Encoding post_encoding; RDFormPost::Encoding post_encoding;
RDFormPost::Error post_error; RDFormPost::Error post_error;
@@ -79,6 +79,7 @@ class RDFormPost
int64_t post_content_length; int64_t post_content_length;
QString post_content_type; QString post_content_type;
char *post_data; char *post_data;
int64_t post_bytes_downloaded;
QString post_separator; QString post_separator;
FILE *post_stream; FILE *post_stream;
}; };