Don't allow cd'ing to above root.
authorJonas Gastal <jgastal@profusion.mobi>
Mon, 30 Jan 2012 00:57:56 +0000 (22:57 -0200)
committerQt by Nokia <qt-info@nokia.com>
Tue, 7 Feb 2012 21:05:51 +0000 (22:05 +0100)
Task-number: QTBUG-23893
Change-Id: Ifc6e22f135a1f6bff7c0fa8bef3ea7e1042ae819
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Reviewed-by: David Faure <david.faure@kdab.com>
src/corelib/io/qdir.cpp
tests/auto/corelib/io/qdir/tst_qdir.cpp

index afd6620..220fc43 100644 (file)
@@ -861,19 +861,28 @@ bool QDir::cd(const QString &dirName)
     if (isAbsolutePath(dirName)) {
         newPath = cleanPath(dirName);
     } else {
-        if (isRoot()) {
-            if (dirName == QLatin1String(".."))
-                return false;
+        if (isRoot())
             newPath = d->dirEntry.filePath();
-        } else {
+        else
             newPath = d->dirEntry.filePath() % QLatin1Char('/');
-        }
-
         newPath += dirName;
         if (dirName.indexOf(QLatin1Char('/')) >= 0
             || dirName == QLatin1String("..")
             || d->dirEntry.filePath() == QLatin1String(".")) {
             newPath = cleanPath(newPath);
+#if defined (Q_OS_UNIX)
+            //After cleanPath() if path is "/.." or starts with "/../" it means trying to cd above root.
+            if (newPath.startsWith(QLatin1String("/../")) || newPath == QLatin1String("/.."))
+#else
+            /*
+              cleanPath() already took care of replacing '\' with '/'.
+              We can't use startsWith here because the letter of the drive is unknown.
+              After cleanPath() if path is "[A-Z]:/.." or starts with "[A-Z]:/../" it means trying to cd above root.
+             */
+
+            if (newPath.midRef(1, 4) == QLatin1String(":/..") && (newPath.length() == 5 || newPath.at(5) == QLatin1Char('/')))
+#endif
+                return false;
             /*
               If newPath starts with .., we convert it to absolute to
               avoid infinite looping on
index f1c9015..539bea5 100644 (file)
@@ -190,6 +190,8 @@ private slots:
 
     void isReadable();
 
+    void cdBelowRoot();
+
 private:
     QString m_dataPath;
 };
@@ -1942,6 +1944,33 @@ void tst_QDir::isReadable()
 #endif
 }
 
+void tst_QDir::cdBelowRoot()
+{
+#if defined (Q_OS_UNIX)
+#define ROOT QString("/")
+#define DIR QString("/tmp")
+#define CD_INTO "tmp"
+#else
+#define ROOT QString::fromLocal8Bit(qgetenv("SystemDrive"))+"/"
+#define DIR QString::fromLocal8Bit(qgetenv("SystemRoot")).replace('\\', '/')
+#define CD_INTO QString::fromLocal8Bit(qgetenv("SystemRoot")).mid(3)
+#endif
+
+    QDir root(ROOT);
+    QVERIFY(!root.cd(".."));
+    QCOMPARE(root.path(), ROOT);
+    QVERIFY(root.cd(CD_INTO));
+    QCOMPARE(root.path(), DIR);
+
+    QDir dir(DIR);
+    QVERIFY(!dir.cd("../.."));
+    QCOMPARE(dir.path(), DIR);
+    QVERIFY(!dir.cd("../abs/../.."));
+    QCOMPARE(dir.path(), DIR);
+    QVERIFY(dir.cd(".."));
+    QCOMPARE(dir.path(), ROOT);
+}
+
 QTEST_MAIN(tst_QDir)
 #include "tst_qdir.moc"