Skip to content

Commit aa1008b

Browse files
committed
Fixing security vulnerability with Qt 4.8.5+ and PostgreSQL.
Properly detects whether Qt performs slash escaping in SQL queries or not, and then configures PostgreSQL accordingly. This bug was a introduced due to a bugfix in Qt 4.8.5 disables slash escaping when binding queries: https://bugreports.qt-project.org/browse/QTBUG-30076 Thanks to brot and Tucos. [Fixes #1244]
1 parent 61bf666 commit aa1008b

File tree

4 files changed

+49
-10
lines changed

4 files changed

+49
-10
lines changed

src/core/abstractsqlstorage.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,14 @@ void AbstractSqlStorage::addConnectionToPool()
9191
}
9292

9393
if (!db.open()) {
94-
qWarning() << "Unable to open database" << displayName() << "for thread" << QThread::currentThread();
95-
qWarning() << "-" << db.lastError().text();
94+
quWarning() << "Unable to open database" << displayName() << "for thread" << QThread::currentThread();
95+
quWarning() << "-" << db.lastError().text();
9696
}
9797
else {
98-
initDbSession(db);
98+
if (!initDbSession(db)) {
99+
quWarning() << "Unable to initialize database" << displayName() << "for thread" << QThread::currentThread();
100+
db.close();
101+
}
99102
}
100103
}
101104

src/core/abstractsqlstorage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public slots:
8080
* When reimplementing this method, don't use logDB() inside this function as
8181
* this would cause as we're just about to initialize that DB connection.
8282
*/
83-
inline virtual void initDbSession(QSqlDatabase & /* db */) {}
83+
inline virtual bool initDbSession(QSqlDatabase & /* db */) { return true; }
8484

8585
private slots:
8686
void connectionDestroyed();

src/core/postgresqlstorage.cpp

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,47 @@ QVariantMap PostgreSqlStorage::setupDefaults() const
9696
}
9797

9898

99-
void PostgreSqlStorage::initDbSession(QSqlDatabase &db)
100-
{
101-
// this blows... but unfortunately Qt's PG driver forces us to this...
102-
db.exec("set standard_conforming_strings = off");
103-
db.exec("set escape_string_warning = off");
99+
bool PostgreSqlStorage::initDbSession(QSqlDatabase &db)
100+
{
101+
// check whether the Qt driver performs string escaping or not.
102+
// i.e. test if it doubles slashes.
103+
QSqlField testField;
104+
testField.setType(QVariant::String);
105+
testField.setValue("\\");
106+
QString formattedString = db.driver()->formatValue(testField);
107+
switch(formattedString.count('\\')) {
108+
case 2:
109+
// yes it does... and we cannot do anything to change the behavior of Qt.
110+
// If this is a legacy DB (Postgres < 8.2), then everything is already ok,
111+
// as this is the expected behavior.
112+
// If it is a newer version, switch to legacy mode.
113+
114+
quWarning() << "Switching Postgres to legacy mode. (set standard conforming strings to off)";
115+
// If the following calls fail, it is a legacy DB anyways, so it doesn't matter
116+
// and no need to check the outcome.
117+
db.exec("set standard_conforming_strings = off");
118+
db.exec("set escape_string_warning = off");
119+
break;
120+
case 1:
121+
// ok, so Qt does not escape...
122+
// That means we have to ensure that postgres uses standard conforming strings...
123+
{
124+
QSqlQuery query = db.exec("set standard_conforming_strings = on");
125+
if (query.lastError().isValid()) {
126+
// We cannot enable standard conforming strings...
127+
// since Quassel does no escaping by itself, this would yield a major vulnerability.
128+
quError() << "Failed to enable standard_conforming_strings for the Postgres db!";
129+
return false;
130+
}
131+
}
132+
break;
133+
default:
134+
// The slash got replaced with 0 or more than 2 slashes! o_O
135+
quError() << "Your version of Qt does something _VERY_ strange to slashes in QSqlQueries! You should consult your trusted doctor!";
136+
return false;
137+
break;
138+
}
139+
return true;
104140
}
105141

106142

src/core/postgresqlstorage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public slots:
103103
virtual QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1);
104104

105105
protected:
106-
virtual void initDbSession(QSqlDatabase &db);
106+
virtual bool initDbSession(QSqlDatabase &db);
107107
virtual void setConnectionProperties(const QVariantMap &properties);
108108
inline virtual QString driverName() { return "QPSQL"; }
109109
inline virtual QString hostName() { return _hostName; }

0 commit comments

Comments
 (0)