Bug 493319

Summary: Dolphin segfaults when a file created in a directory whose parent directory is not readable for the user
Product: [Applications] dolphin Reporter: Philipp Maierhöfer <maiphi.public>
Component: generalAssignee: Dolphin Bug Assignee <dolphin-bugs-null>
Status: RESOLVED FIXED    
Severity: crash CC: akselmo, kdedev, kfm-devel, nicolas.fella
Priority: NOR    
Version: 24.08.1   
Target Milestone: ---   
Platform: Other   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: backtrace

Description Philipp Maierhöfer 2024-09-18 10:49:53 UTC
Created attachment 173824 [details]
backtrace

SUMMARY

Dolphin crashes with a segmentation fault when a file is created in a directory that lies in a directory on which the user has only executable right, but no read rights.

STEPS TO REPRODUCE
1.
mkdir -p hidden/visible
sudo chown root:root hidden
sudo chmod go-rw hidden

2.
Open Dolphin and navigate to hidden/visible/.
Right click to open the context menu.
Select Create New -> Text File, press enter.

OBSERVED RESULT
The file is created, but Dolphin crashes with a segmentation fault.

EXPECTED RESULT
No crash.

SOFTWARE/OS VERSIONS
Linux/KDE Plasma: Tumbleweed (up to date)
KDE Plasma Version: 6.1.5
KDE Frameworks Version: 6.6.0
Qt Version: 6.7.2
Graphics Platform: Wayland
Comment 1 Nicolas Fella 2024-09-23 10:26:55 UTC
#0  KFileItem::~KFileItem (this=0x0, this=<optimized out>) at /usr/src/debug/kio-6.6.0/src/core/kfileitem.cpp:630
#1  0x00007ffff79231ec in std::destroy_at<KFileItem> (__location=0x0) at /usr/include/c++/14/bits/stl_construct.h:88
#2  std::_Destroy<KFileItem> (__pointer=0x0) at /usr/include/c++/14/bits/stl_construct.h:149
#3  std::_Destroy_aux<false>::__destroy<KFileItem*> (__first=0x0, __last=0x8, __first=<optimized out>, __last=<optimized out>) at /usr/include/c++/14/bits/stl_construct.h:163
#4  std::_Destroy<KFileItem*> (__first=0x0, __last=0x8) at /usr/include/c++/14/bits/stl_construct.h:196
#5  std::destroy<KFileItem*> (__first=0x0, __last=0x8) at /usr/include/c++/14/bits/stl_construct.h:253
#6  QtPrivate::QMovableArrayOps<KFileItem>::erase (this=0x555555c031b0, b=0x0, n=<optimized out>) at /usr/include/qt6/QtCore/qarraydataops.h:856
#7  QList<KFileItem>::remove (this=0x555555c031b0, i=<optimized out>, n=<optimized out>) at /usr/include/qt6/QtCore/qlist.h:785
#8  QList<KFileItem>::remove (this=0x555555c031b0, i=<optimized out>, n=<optimized out>) at /usr/include/qt6/QtCore/qlist.h:776
#9  QList<KFileItem>::erase (this=0x555555c031b0, abegin=..., aend=...) at /usr/include/qt6/QtCore/qlist.h:879
#10 0x00007ffff7905fce in QList<KFileItem>::erase (this=0x555555c031b0, pos=...) at /usr/include/qt6/QtCore/qlist.h:628
#11 KCoreDirListerCache::reinsert (this=<optimized out>, item=..., oldUrl=<optimized out>) at /usr/src/debug/kio-6.6.0/src/core/kcoredirlister_p.h:328
#12 0x00007ffff79168bc in KCoreDirListerCache::processPendingUpdates (this=0x555555799920) at /usr/src/debug/kio-6.6.0/src/core/kcoredirlister.cpp:2012
#13 0x00007ffff55e7f90 in QtPrivate::QSlotObjectBase::call (a=0x7fffffffd010, r=0x555555799920, this=0x5555558bb300)
    at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/kernel/qobjectdefs_impl.h:469
#14 doActivate<false> (sender=0x555555799a40, signal_index=3, argv=0x7fffffffd010) at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/kernel/qobject.cpp:4086
#15 0x00007ffff55ec65a in QTimer::timeout (this=<optimized out>, _t1=...) at /usr/src/debug/qtbase-everywhere-src-6.7.2/build/src/corelib/Core_autogen/include/moc_qtimer.cpp:224
#16 0x00007ffff55d1dd6 in QObject::event (this=0x555555799a40, e=0x7fffffffd190) at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/kernel/qobject.cpp:1427
#17 0x00007ffff67c2f6e in QApplicationPrivate::notify_helper (this=<optimized out>, receiver=0x555555799a40, e=0x7fffffffd190)
    at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/widgets/kernel/qapplication.cpp:3287
#18 0x00007ffff558ec30 in QCoreApplication::notifyInternal2 (receiver=0x555555799a40, event=0x7fffffffd190)
    at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/kernel/qcoreapplication.cpp:1142
#19 0x00007ffff56eca5a in QTimerInfoList::activateTimers (this=0x555555704550) at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/kernel/qtimerinfo_unix.cpp:434
#20 0x00007ffff57c2e3c in timerSourceDispatch (source=<optimized out>) at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/kernel/qeventdispatcher_glib.cpp:150
#21 idleTimerSourceDispatch (source=<optimized out>) at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/kernel/qeventdispatcher_glib.cpp:197
#22 0x00007ffff3aaffb8 in g_main_dispatch (context=0x7fffe8000f00) at ../glib/gmain.c:3344
#23 g_main_context_dispatch_unlocked (context=context@entry=0x7fffe8000f00) at ../glib/gmain.c:4152
#24 0x00007ffff3ab1d38 in g_main_context_iterate_unlocked (context=context@entry=0x7fffe8000f00, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib/gmain.c:4217
#25 0x00007ffff3ab23ec in g_main_context_iteration (context=0x7fffe8000f00, may_block=1) at ../glib/gmain.c:4282
#26 0x00007ffff57c1adc in QEventDispatcherGlib::processEvents (this=0x5555556e4530, flags=...) at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/kernel/qeventdispatcher_glib.cpp:394
#27 0x00007ffff55993db in QEventLoop::exec (this=0x7fffffffd3f0, flags=...) at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/global/qflags.h:34
#28 0x00007ffff5592bb6 in QCoreApplication::exec () at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/corelib/global/qflags.h:74
#29 0x00007ffff5de7dec in QGuiApplication::exec () at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/gui/kernel/qguiapplication.cpp:1926
#30 0x00007ffff67bfff5 in QApplication::exec () at /usr/src/debug/qtbase-everywhere-src-6.7.2/src/widgets/kernel/qapplication.cpp:2555
#31 0x00005555555b28ac in main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/dolphin-24.08.1/src/main.cpp:259
Comment 2 Philipp Maierhöfer 2024-10-22 21:20:02 UTC
I tried to reproduce this with neon-user-20241020-0745 running in VirtualBox. Out of the box the segfault does not happen, but I was able to trace it back to a single setting:

Activate the folder panel (F7). That's all. The crash is 100% reproducible.
Comment 3 Akseli Lahtinen 2024-10-25 12:57:33 UTC
Can confirm the crash on git master version of dolphin

Followed your steps and opened the folder panel with F7. However, I had to create a folder inside the "visible" folder for the crash to occur.

System info:

Operating System: Fedora Linux 40
KDE Plasma Version: 6.2.80
KDE Frameworks Version: 6.8.0
Qt Version: 6.7.2
Kernel Version: 6.11.4-201.fc40.x86_64 (64-bit)
Graphics Platform: Wayland
Processors: 12 × AMD Ryzen 5 3600 6-Core Processor
Memory: 15,5 GiB of RAM
Graphics Processor: AMD Radeon RX 6600

Backtrace:

#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=11, no_tid=no_tid@entry=0)
at pthread_kill.c:44
#1  0x00007f2f61ca86d3 in __pthread_kill_internal (threadid=<optimized out>, signo=11) at pthread_kill.c:78
#2  0x00007f2f61c4fc4e in __GI_raise (sig=11) at ../sysdeps/posix/raise.c:26
#3  0x00007f2f650875ab in KCrash::defaultCrashHandler (sig=11)
at /home/akseli/Repositories/kde/src/kcrash/src/kcrash.cpp:596
#4  0x00007f2f61c4fd00 in <signal handler called> () at /lib64/libc.so.6
#5  QSharedDataPointer<KFileItemPrivate>::~QSharedDataPointer (this=0x0, __in_chrg=<optimized out>)
at /usr/include/qt6/QtCore/qshareddata.h:56
#6  KFileItem::~KFileItem (this=0x0, __in_chrg=<optimized out>)
at /home/akseli/Repositories/kde/src/kio/src/core/kfileitem.cpp:630
#7  0x00007f2f651ad9ac in std::destroy_at<KFileItem> (__location=0x0) at /usr/include/c++/14/bits/stl_construct.h:88
#8  std::_Destroy<KFileItem> (__pointer=0x0) at /usr/include/c++/14/bits/stl_construct.h:149
#9  std::_Destroy_aux<false>::__destroy<KFileItem*> (__first=0x0, __last=0x8)
at /usr/include/c++/14/bits/stl_construct.h:163
#10 std::_Destroy<KFileItem*> (__first=0x0, __last=0x8) at /usr/include/c++/14/bits/stl_construct.h:196
#11 std::destroy<KFileItem*> (__first=0x0, __last=0x8) at /usr/include/c++/14/bits/stl_construct.h:253
#12 QtPrivate::QMovableArrayOps<KFileItem>::erase (this=0x1a017a90, b=0x0, n=<optimized out>)
at /usr/include/qt6/QtCore/qarraydataops.h:856
#13 QList<KFileItem>::remove (this=0x1a017a90, i=<optimized out>, n=<optimized out>) at /usr/include/qt6/QtCore/qlist.h:785
#14 QList<KFileItem>::remove (this=0x1a017a90, i=<optimized out>, n=<optimized out>) at /usr/include/qt6/QtCore/qlist.h:776
#15 QList<KFileItem>::erase (this=this@entry=0x1a017a90, abegin=..., abegin@entry=..., aend=..., aend@entry=...)
at /usr/include/qt6/QtCore/qlist.h:879
#16 0x00007f2f651af401 in QList<KFileItem>::erase (this=0x1a017a90, pos=...) at /usr/include/qt6/QtCore/qlist.h:628
#17 KCoreDirListerCache::reinsert (this=this@entry=0x1968de60, item=..., oldUrl=...)
at /home/akseli/Repositories/kde/src/kio/src/core/kcoredirlister_p.h:328
#18 0x00007f2f6519c3e3 in KCoreDirListerCache::processPendingUpdates (this=0x1968de60)
at /home/akseli/Repositories/kde/src/kio/src/core/kcoredirlister.cpp:2012
#19 0x00007f2f623fc8f2 in QtPrivate::QSlotObjectBase::call (this=0x1960cf50, r=<optimized out>, a=0x7ffe00e7a2d0)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qobjectdefs_impl.h:469
#20 doActivate<false> (sender=0x1968df80, signal_index=3, argv=0x7ffe00e7a2d0)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qobject.cpp:4086
#21 0x00007f2f623f2bc7 in QMetaObject::activate
(sender=<optimized out>, m=m@entry=0x7f2f6288b100, local_signal_index=local_signal_index@entry=0, argv=argv@entry=0x7ffe0--Type <RET> for more, q to quit, c to continue without paging--c
0e7a2d0) at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qobject.cpp:4146
#22 0x00007f2f6240bcbd in QTimer::timeout (this=<optimized out>, _t1=...)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/redhat-linux-build/src/corelib/Core_autogen/include/moc_qtimer.cpp:224
#23 0x00007f2f623edd5f in QObject::event (this=0x1968df80, e=0x7ffe00e7a480)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qobject.cpp:1482
#24 0x00007f2f6358b218 in QApplicationPrivate::notify_helper (this=<optimized out>, receiver=0x1968df80, e=0x7ffe00e7a480)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/widgets/kernel/qapplication.cpp:3287
#25 0x00007f2f62396e88 in QCoreApplication::notifyInternal2 (receiver=0x1968df80, event=0x7ffe00e7a480)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qcoreapplication.cpp:1142
#26 0x00007f2f623970ed in QCoreApplication::sendEvent (receiver=<optimized out>, event=<optimized out>)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qcoreapplication.cpp:1583
#27 0x00007f2f62552b47 in QTimerInfoList::activateTimers (this=0x1939c040)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qtimerinfo_unix.cpp:434
#28 0x00007f2f62684fd9 in timerSourceDispatch (source=<optimized out>)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qeventdispatcher_glib.cpp:150
#29 0x00007f2f5f10ee8c in g_main_dispatch (context=0x7f2f48000f00) at ../glib/gmain.c:3344
#30 g_main_context_dispatch_unlocked (context=0x7f2f48000f00) at ../glib/gmain.c:4152
#31 0x00007f2f5f170c98 in g_main_context_iterate_unlocked.isra.0
(context=context@entry=0x7f2f48000f00, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>)
at ../glib/gmain.c:4217
#32 0x00007f2f5f110383 in g_main_context_iteration (context=0x7f2f48000f00, may_block=1) at ../glib/gmain.c:4282
#33 0x00007f2f626851a3 in QEventDispatcherGlib::processEvents (this=0x19346cc0, flags=...)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/kernel/qeventdispatcher_glib.cpp:394
#34 0x00007f2f623a3bc3 in QEventLoop::exec (this=this@entry=0x7ffe00e7a750, flags=..., flags@entry=...)
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/global/qflags.h:34
#35 0x00007f2f6239fa7c in QCoreApplication::exec ()
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/corelib/global/qflags.h:74
#36 0x00007f2f62bd66ed in QGuiApplication::exec ()
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/gui/kernel/qguiapplication.cpp:1926
#37 0x00007f2f6358b189 in QApplication::exec ()
at /usr/src/debug/qt6-qtbase-6.7.2-6.fc40.x86_64/src/widgets/kernel/qapplication.cpp:2555
#38 0x000000000043fbe9 in main (argc=<optimized out>, argv=<optimized out>)
at /home/akseli/Repositories/kde/src/dolphin/src/main.cpp:275
Comment 4 Bug Janitor Service 2024-11-14 13:24:56 UTC
A possibly relevant merge request was started @ https://invent.kde.org/frameworks/kio/-/merge_requests/1760
Comment 5 Akseli Lahtinen 2024-11-21 19:14:03 UTC
Git commit 125a451d524777c6423ed514e4bb1159b32c6e8a by Akseli Lahtinen.
Committed on 21/11/2024 at 19:14.
Pushed by akselmo into branch 'master'.

kcoredirlister: Remove iterator assert, use if instead

In cases where user adds files to a directory which parent
directory is not readable for the user, these asserts
would cause a crash, since the code would try to iterate over an empty list: 

Due to `reinsert` using parent folder of `visible`, which is `hidden`, we have no permissions to read anything in `hidden` so we get an empty list. Without `if (it != dirItem->lstItems.end())` this will cause a crash.

This would be okay if we did not allow users browse folders that we can read inside folders that we can't read. However, we allow this behavior if user manually types the
path to the Dolphin URL bar for example.

Instead we should just check if the iterator has reached it's end,
and just silently do nothing instead. If user is inside a hidden folder, we can't
really do any updates to our directory listing views etc. anyway.

M  +47   -0    autotests/kdirlistertest.cpp
M  +1    -0    autotests/kdirlistertest.h
M  +8    -5    src/core/kcoredirlister_p.h

https://invent.kde.org/frameworks/kio/-/commit/125a451d524777c6423ed514e4bb1159b32c6e8a