[arch-commits] Commit in kdelibs/trunk (3 files)

Andrea Scarpino andrea at archlinux.org
Sun Mar 27 13:27:39 UTC 2011


    Date: Sunday, March 27, 2011 @ 09:27:39
  Author: andrea
Revision: 117004

CVE-2011-1168; fix empty dolphin /home/andrea

Added:
  kdelibs/trunk/CVE-2011-1168.patch
  kdelibs/trunk/fix-empty-dolphin-home.patch
Modified:
  kdelibs/trunk/PKGBUILD

------------------------------+
 CVE-2011-1168.patch          |   14 +
 PKGBUILD                     |   14 +
 fix-empty-dolphin-home.patch |  389 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 414 insertions(+), 3 deletions(-)

Added: CVE-2011-1168.patch
===================================================================
--- CVE-2011-1168.patch	                        (rev 0)
+++ CVE-2011-1168.patch	2011-03-27 13:27:39 UTC (rev 117004)
@@ -0,0 +1,14 @@
+--- a/khtml/khtml_part.cpp
++++ b/khtml/khtml_part.cpp
+@@ -1804,7 +1804,10 @@ void KHTMLPart::htmlError( int errorCode
+   stream >> errorName >> techName >> description >> causes >> solutions;
+ 
+   QString url, protocol, datetime;
+-  url = Qt::escape( reqUrl.prettyUrl() );
++
++  // This is somewhat confusing, but we have to escape the externally-
++  // controlled URL twice: once for i18n, and once for HTML.
++  url = Qt::escape( Qt::escape( reqUrl.prettyUrl() ) );
+   protocol = reqUrl.protocol();
+   datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
+                                                 KLocale::LongDate );

Modified: PKGBUILD
===================================================================
--- PKGBUILD	2011-03-27 13:06:05 UTC (rev 117003)
+++ PKGBUILD	2011-03-27 13:27:39 UTC (rev 117004)
@@ -4,7 +4,7 @@
 
 pkgname=kdelibs
 pkgver=4.6.1
-pkgrel=2
+pkgrel=3
 pkgdesc="KDE Core Libraries"
 arch=('i686' 'x86_64')
 url='http://www.kde.org'
@@ -19,11 +19,15 @@
 replaces=('arts' 'kdelibs-experimental')
 install='kdelibs.install'
 source=("http://download.kde.org/stable/${pkgver}/src/${pkgname}-${pkgver}.tar.bz2"
-        'kde-applications-menu.patch' 'archlinux-menu.patch' 'abs-syntax-highlight.patch')
+        'kde-applications-menu.patch' 'archlinux-menu.patch' 'abs-syntax-highlight.patch'
+        'CVE-2011-1168.patch'
+        'fix-empty-dolphin-home.patch')
 sha1sums=('5868d43084b2dc9de4c0404dbec137375664e893'
           '86ee8c8660f19de8141ac99cd6943964d97a1ed7'
           '63a850ab4196b9d06934f2b4a13acd9f7739bc67'
-          'd994f262356af5b9e4e9619646e471bd98c91efb')
+          'd994f262356af5b9e4e9619646e471bd98c91efb'
+          '730534a337c88ef2a7c716f5d118f445d06898e7'
+          'aaec293322f1483990ad8edbb1ec1a6dd69cf3ee')
 
 build() {
        cd ${srcdir}/${pkgname}-${pkgver}
@@ -35,6 +39,10 @@
        # add syntax highlightning for PKGBUILD and .install files
        patch -p1 -i $srcdir/abs-syntax-highlight.patch
 
+       # Already fixed upstream
+       patch -Np1 -i ${srcdir}/CVE-2011-1168.patch
+       patch -Np1 -i ${srcdir}/fix-empty-dolphin-home.patch
+
        cd ${srcdir}
        mkdir build
        cd build

Added: fix-empty-dolphin-home.patch
===================================================================
--- fix-empty-dolphin-home.patch	                        (rev 0)
+++ fix-empty-dolphin-home.patch	2011-03-27 13:27:39 UTC (rev 117004)
@@ -0,0 +1,389 @@
+commit 51707e7154082b549216b8a8ecde73505302fadc
+Author: David Faure <faure at kde.org>
+Date:   Tue Mar 8 11:23:47 2011 +0100
+
+    Fix stop() killing the list job even if another dirlister needs it.
+    
+    Regression introduced by me in bef0bd3e3ff.
+    Symptom: "dolphin $HOME" showed up empty.
+    
+    In the case of concurrent listings, I made the use of the cached items job
+    conditional (only created if there's anything to emit) so that we can join
+    the current listjob without killing it (updateDirectory) if it hasn't emitted
+    anything yet.
+    The unittest also uncovered inconsistencies in the emission of the cancelled
+    signal, now cacheditemsjob behaves like the listjob in this respect.
+    
+    FIXED-IN: 4.6.2
+    BUG: 267709
+
+diff --git a/kio/kio/kdirlister.cpp b/kio/kio/kdirlister.cpp
+index 75360e08f..df81dc8 100644
+--- a/kio/kio/kdirlister.cpp
++++ b/kio/kio/kdirlister.cpp
+@@ -194,7 +194,7 @@ bool KDirListerCache::listDir( KDirLister *lister, const KUrl& _u,
+ 
+             // List items from the cache in a delayed manner, just like things would happen
+             // if we were not using the cache.
+-            new KDirLister::Private::CachedItemsJob(lister, itemU->lstItems, itemU->rootItem, _url, _reload);
++            new KDirLister::Private::CachedItemsJob(lister, _url, _reload);
+ 
+         } else {
+             // dir not in cache or _reload is true
+@@ -260,8 +260,13 @@ bool KDirListerCache::listDir( KDirLister *lister, const KUrl& _u,
+ 
+         // List existing items in a delayed manner, just like things would happen
+         // if we were not using the cache.
+-        //kDebug() << "Listing" << itemU->lstItems.count() << "cached items soon";
+-        new KDirLister::Private::CachedItemsJob(lister, itemU->lstItems, itemU->rootItem, _url, _reload);
++        if (!itemU->lstItems.isEmpty()) {
++            kDebug() << "Listing" << itemU->lstItems.count() << "cached items soon";
++            new KDirLister::Private::CachedItemsJob(lister, _url, _reload);
++        } else {
++            // The other lister hasn't emitted anything yet. Good, we'll just listen to it.
++            // One problem could be if we have _reload=true and the existing job doesn't, though.
++        }
+ 
+ #ifdef DEBUG_CACHE
+         printDebug();
+@@ -280,11 +285,9 @@ KDirLister::Private::CachedItemsJob* KDirLister::Private::cachedItemsJobForUrl(c
+     return 0;
+ }
+ 
+-KDirLister::Private::CachedItemsJob::CachedItemsJob(KDirLister* lister, const KFileItemList& items, 
+-                                                    const KFileItem& rootItem, const KUrl& url, bool reload)
++KDirLister::Private::CachedItemsJob::CachedItemsJob(KDirLister* lister, const KUrl& url, bool reload)
+   : KJob(lister),
+     m_lister(lister), m_url(url),
+-    m_items(items), m_rootItem(rootItem),
+     m_reload(reload), m_emitCompleted(true)
+ {
+     //kDebug() << "Creating CachedItemsJob" << this << "for lister" << lister << url;
+@@ -301,40 +304,70 @@ void KDirLister::Private::CachedItemsJob::done()
+ {
+     if (!m_lister) // job was already killed, but waiting deletion due to deleteLater
+         return;
+-    kDirListerCache->emitItemsFromCache(this, m_lister, m_items, m_rootItem, m_url, m_reload, m_emitCompleted);
++    kDirListerCache->emitItemsFromCache(this, m_lister, m_url, m_reload, m_emitCompleted);
+     emitResult();
+ }
+ 
+ bool KDirLister::Private::CachedItemsJob::doKill()
+ {
+-    //kDebug() << this;
+-    kDirListerCache->emitItemsFromCache(this, m_lister, KFileItemList(), KFileItem(), m_url, false, false);
++    //kDebug(7004) << this;
++    kDirListerCache->forgetCachedItemsJob(this, m_lister, m_url);
++    if (!property("_kdlc_silent").toBool()) {
++        emit m_lister->canceled(m_url);
++        emit m_lister->canceled();
++    }
+     m_lister = 0;
+     return true;
+ }
+ 
+-void KDirListerCache::emitItemsFromCache(KDirLister::Private::CachedItemsJob* cachedItemsJob, KDirLister* lister, const KFileItemList& items, const KFileItem& rootItem, const KUrl& _url, bool _reload, bool _emitCompleted)
++void KDirListerCache::emitItemsFromCache(KDirLister::Private::CachedItemsJob* cachedItemsJob, KDirLister* lister, const KUrl& _url, bool _reload, bool _emitCompleted)
+ {
+     const QString urlStr = _url.url();
+-    DirItem *itemU = kDirListerCache->itemsInUse.value(urlStr);
+-    Q_ASSERT(itemU); // hey we're listing that dir, so this can't be 0, right?
+-
+     KDirLister::Private* kdl = lister->d;
+-
+     kdl->complete = false;
+ 
+-    if (kdl->rootFileItem.isNull() && !rootItem.isNull() && kdl->url == _url) {
+-        kdl->rootFileItem = rootItem;
++    DirItem *itemU = kDirListerCache->itemsInUse.value(urlStr);
++    if (!itemU) {
++        kWarning(7004) << "Can't find item for directory" << urlStr << "anymore";
++    } else {
++        const KFileItemList items = itemU->lstItems;
++        const KFileItem rootItem = itemU->rootItem;
++        _reload = _reload || !itemU->complete;
++
++        if (kdl->rootFileItem.isNull() && !rootItem.isNull() && kdl->url == _url) {
++            kdl->rootFileItem = rootItem;
++        }
++        if (!items.isEmpty()) {
++            //kDebug(7004) << "emitting" << items.count() << "for lister" << lister;
++            kdl->addNewItems(_url, items);
++            kdl->emitItems();
++        }
+     }
+-    if (!items.isEmpty()) {
+-        //kDebug(7004) << "emitting" << items.count() << "for lister" << lister;
+-        kdl->addNewItems(_url, items);
+-        kdl->emitItems();
++
++    forgetCachedItemsJob(cachedItemsJob, lister, _url);
++
++    // Emit completed, unless we were told not to,
++    // or if listDir() was called while another directory listing for this dir was happening,
++    // so we "joined" it. We detect that using jobForUrl to ensure it's a real ListJob,
++    // not just a lister-specific CachedItemsJob (which wouldn't emit completed for us).
++    if (_emitCompleted) {
++
++        kdl->complete = true;
++        emit lister->completed( _url );
++        emit lister->completed();
++
++        if ( _reload ) {
++            updateDirectory( _url );
++        }
+     }
++}
+ 
++void KDirListerCache::forgetCachedItemsJob(KDirLister::Private::CachedItemsJob* cachedItemsJob, KDirLister* lister, const KUrl& _url)
++{
+     // Modifications to data structures only below this point;
+     // so that addNewItems is called with a consistent state
+ 
++    const QString urlStr = _url.url();
+     lister->d->m_cachedItemsJobs.removeAll(cachedItemsJob);
+ 
+     KDirListerCacheDirectoryData& dirData = directoryData[urlStr];
+@@ -343,27 +376,12 @@ void KDirListerCache::emitItemsFromCache(KDirLister::Private::CachedItemsJob* ca
+     KIO::ListJob *listJob = jobForUrl(urlStr);
+     if (!listJob) {
+         Q_ASSERT(!dirData.listersCurrentlyHolding.contains(lister));
+-        kDebug(7004) << "Moving from listing to holding, because no more job" << lister << urlStr;
++        //kDebug(7004) << "Moving from listing to holding, because no more job" << lister << urlStr;
+         dirData.listersCurrentlyHolding.append( lister );
+         dirData.listersCurrentlyListing.removeAll( lister );
+     } else {
+         //kDebug(7004) << "Still having a listjob" << listJob << ", so not moving to currently-holding.";
+     }
+-
+-    // Emit completed, unless we were told not to,
+-    // or if listDir() was called while another directory listing for this dir was happening,
+-    // so we "joined" it. We detect that using jobForUrl to ensure it's a real ListJob,
+-    // not just a lister-specific CachedItemsJob (which wouldn't emit completed for us).
+-    if (_emitCompleted) {
+-
+-        kdl->complete = true;
+-        emit lister->completed( _url );
+-        emit lister->completed();
+-
+-        if ( _reload || !itemU->complete ) {
+-            updateDirectory( _url );
+-        }
+-    }
+ }
+ 
+ bool KDirListerCache::validUrl( const KDirLister *lister, const KUrl& url ) const
+@@ -396,19 +414,13 @@ void KDirListerCache::stop( KDirLister *lister, bool silent )
+ #ifdef DEBUG_CACHE
+     //printDebug();
+ #endif
+-    //kDebug(7004) << "lister: " << lister;
++    //kDebug(7004) << "lister:" << lister << "silent=" << silent;
+ 
+     const KUrl::List urls = lister->d->lstDirs;
+     Q_FOREACH(const KUrl& url, urls) {
+-        //kDebug() << "Stopping any listjob for" << url.url();
+-        stopListJob(url.url(), silent);
++        stopListingUrl(lister, url, silent);
+     }
+-
+-    Q_FOREACH(KDirLister::Private::CachedItemsJob* job, lister->d->m_cachedItemsJobs) {
+-        //kDebug() << "Killing cached items job";
+-        job->kill(); // removes job from list, too
+-    }
+-
++    
+ #if 0 // test code
+     QHash<QString,KDirListerCacheDirectoryData>::iterator dirit = directoryData.begin();
+     const QHash<QString,KDirListerCacheDirectoryData>::iterator dirend = directoryData.end();
+@@ -416,6 +428,7 @@ void KDirListerCache::stop( KDirLister *lister, bool silent )
+         KDirListerCacheDirectoryData& dirData = dirit.value();
+         if (dirData.listersCurrentlyListing.contains(lister)) {
+             kDebug(7004) << "ERROR: found lister" << lister << "in list - for" << dirit.key();
++            Q_ASSERT(false);
+         }
+     }
+ #endif
+@@ -429,6 +442,9 @@ void KDirListerCache::stopListingUrl(KDirLister *lister, const KUrl& _u, bool si
+ 
+     KDirLister::Private::CachedItemsJob* cachedItemsJob = lister->d->cachedItemsJobForUrl(url);
+     if (cachedItemsJob) {
++        if (silent) {
++            cachedItemsJob->setProperty("_kdlc_silent", true);
++        }
+         cachedItemsJob->kill(); // removes job from list, too
+     }
+ 
+@@ -440,9 +456,18 @@ void KDirListerCache::stopListingUrl(KDirLister *lister, const KUrl& _u, bool si
+         return;
+     KDirListerCacheDirectoryData& dirData = dirit.value();
+     if (dirData.listersCurrentlyListing.contains(lister)) {
+-
+         //kDebug(7004) << " found lister" << lister << "in list - for" << urlStr;
+-        stopListJob(urlStr, silent);
++        if (dirData.listersCurrentlyListing.count() == 1) {
++            // This was the only dirlister interested in the list job -> kill the job
++            stopListJob(urlStr, silent);
++        } else {
++            // Leave the job running for the other dirlisters, just unsubscribe us.
++            dirData.listersCurrentlyListing.removeAll(lister);
++            if (!silent) {
++                emit lister->canceled();
++                emit lister->canceled(url);
++            }
++        }
+     }
+ }
+ 
+@@ -460,9 +485,10 @@ void KDirListerCache::stopListJob(const QString& url, bool silent)
+ 
+     KIO::ListJob *job = jobForUrl(url);
+     if (job) {
+-        //kDebug() << "Killing list job" << job;
+-        if (silent)
++        //kDebug() << "Killing list job" << job << "for" << url;
++        if (silent) {
+             job->setProperty("_kdlc_silent", true);
++        }
+         job->kill(KJob::EmitResult);
+     }
+ }
+diff --git a/kio/kio/kdirlister_p.h b/kio/kio/kdirlister_p.h
+index 4464c16..dd4c00f 100644
+--- a/kio/kio/kdirlister_p.h
++++ b/kio/kio/kdirlister_p.h
+@@ -209,10 +209,12 @@ public:
+     KFileItem *findByUrl(const KDirLister *lister, const KUrl &url) const;
+ 
+     // Called by CachedItemsJob:
+-    // Emits those items, for this lister and this url
++    // Emits the cached items, for this lister and this url
+     void emitItemsFromCache(KDirLister::Private::CachedItemsJob* job, KDirLister* lister,
+-                            const KFileItemList& lst, const KFileItem& rootItem,
+                             const KUrl& _url, bool _reload, bool _emitCompleted);
++    // Called by CachedItemsJob:
++    void forgetCachedItemsJob(KDirLister::Private::CachedItemsJob* job, KDirLister* lister,
++                              const KUrl& url);
+ 
+ public Q_SLOTS:
+   /**
+@@ -464,8 +466,7 @@ struct KDirListerCacheDirectoryData
+ class KDirLister::Private::CachedItemsJob : public KJob {
+     Q_OBJECT
+ public:
+-    CachedItemsJob(KDirLister* lister, const KFileItemList& items, const KFileItem& rootItem,
+-                   const KUrl& url, bool reload);
++    CachedItemsJob(KDirLister* lister, const KUrl& url, bool reload);
+ 
+     /*reimp*/ void start() { QMetaObject::invokeMethod(this, "done", Qt::QueuedConnection); }
+ 
+@@ -483,8 +484,6 @@ public Q_SLOTS:
+ private:
+     KDirLister* m_lister;
+     KUrl m_url;
+-    KFileItemList m_items;
+-    KFileItem m_rootItem;
+     bool m_reload;
+     bool m_emitCompleted;
+ };
+diff --git a/kio/tests/kdirlistertest.cpp b/kio/tests/kdirlistertest.cpp
+index e543c1f..3047fdd 100644
+--- a/kio/tests/kdirlistertest.cpp
++++ b/kio/tests/kdirlistertest.cpp
+@@ -678,12 +678,83 @@ void KDirListerTest::testConcurrentHoldingListing()
+     QCOMPARE(m_dirLister.spyClear.count(), 1);
+     QCOMPARE(m_dirLister.spyClearKUrl.count(), 0);
+     QVERIFY(dirLister2.isFinished());
+-    disconnect(&dirLister2, 0, this, 0);
+     QVERIFY(m_dirLister.isFinished());
+     disconnect(&m_dirLister, 0, this, 0);
+     QCOMPARE(m_items.count(), origItemCount);
+ }
+ 
++void KDirListerTest::testConcurrentListingAndStop()
++{
++    m_items.clear();
++    m_items2.clear();
++
++    MyDirLister dirLister2;
++
++    // Use a new tempdir for this test, so that we don't use the cache at all.
++    KTempDir tempDir;
++    const QString path = tempDir.name();
++    createTestFile(path+"file_1");
++    createTestFile(path+"file_2");
++    createTestFile(path+"file_3");
++
++    connect(&m_dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewItems(KFileItemList)));
++    connect(&dirLister2, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewItems2(KFileItemList)));
++
++    // Before m_dirLister has time to emit the items, let's make dirLister2 call stop().
++    // This should not stop the list job for m_dirLister (#267709).
++    dirLister2.openUrl(KUrl(path), KDirLister::Reload);
++    m_dirLister.openUrl(KUrl(path)/*, KDirLister::Reload*/);
++
++    QCOMPARE(m_dirLister.spyStarted.count(), 1);
++    QCOMPARE(m_dirLister.spyCompleted.count(), 0);
++    QCOMPARE(m_dirLister.spyCompletedKUrl.count(), 0);
++    QCOMPARE(m_dirLister.spyCanceled.count(), 0);
++    QCOMPARE(m_dirLister.spyCanceledKUrl.count(), 0);
++    QCOMPARE(m_dirLister.spyClear.count(), 1);
++    QCOMPARE(m_dirLister.spyClearKUrl.count(), 0);
++    QCOMPARE(m_items.count(), 0);
++
++    QCOMPARE(dirLister2.spyStarted.count(), 1);
++    QCOMPARE(dirLister2.spyCompleted.count(), 0);
++    QCOMPARE(dirLister2.spyCompletedKUrl.count(), 0);
++    QCOMPARE(dirLister2.spyCanceled.count(), 0);
++    QCOMPARE(dirLister2.spyCanceledKUrl.count(), 0);
++    QCOMPARE(dirLister2.spyClear.count(), 1);
++    QCOMPARE(dirLister2.spyClearKUrl.count(), 0);
++    QCOMPARE(m_items2.count(), 0);
++    QVERIFY(!m_dirLister.isFinished());
++    QVERIFY(!dirLister2.isFinished());
++
++    dirLister2.stop();
++
++    QCOMPARE(dirLister2.spyStarted.count(), 1);
++    QCOMPARE(dirLister2.spyCompleted.count(), 0);
++    QCOMPARE(dirLister2.spyCompletedKUrl.count(), 0);
++    QCOMPARE(dirLister2.spyCanceled.count(), 1);
++    QCOMPARE(dirLister2.spyCanceledKUrl.count(), 1);
++    QCOMPARE(dirLister2.spyClear.count(), 1);
++    QCOMPARE(dirLister2.spyClearKUrl.count(), 0);
++    QCOMPARE(m_items2.count(), 0);
++
++    // then wait for completed
++    qDebug("waiting for completed");
++    connect(&m_dirLister, SIGNAL(completed()), this, SLOT(exitLoop()));
++    enterLoop();
++
++    QCOMPARE(m_items.count(), 3);
++    QCOMPARE(m_items2.count(), 0);
++
++    //QCOMPARE(m_dirLister.spyStarted.count(), 1); // 2 when in cache
++    QCOMPARE(m_dirLister.spyCompleted.count(), 1);
++    QCOMPARE(m_dirLister.spyCompletedKUrl.count(), 1);
++    QCOMPARE(m_dirLister.spyCanceled.count(), 0);
++    QCOMPARE(m_dirLister.spyCanceledKUrl.count(), 0);
++    QCOMPARE(m_dirLister.spyClear.count(), 1);
++    QCOMPARE(m_dirLister.spyClearKUrl.count(), 0);
++
++    disconnect(&m_dirLister, 0, this, 0);
++}
++
+ void KDirListerTest::testDeleteListerEarly()
+ {
+     // Do the same again, it should behave the same, even with the items in the cache
+diff --git a/kio/tests/kdirlistertest.h b/kio/tests/kdirlistertest.h
+index 531abd5..a781aca 100644
+--- a/kio/tests/kdirlistertest.h
++++ b/kio/tests/kdirlistertest.h
+@@ -101,6 +101,7 @@ private Q_SLOTS:
+     void testRenameAndOverwrite();
+     void testConcurrentListing();
+     void testConcurrentHoldingListing();
++    void testConcurrentListingAndStop();
+     void testDeleteListerEarly();
+     void testOpenUrlTwice();
+     void testOpenUrlTwiceWithKeep();




More information about the arch-commits mailing list