Skip to content

Segmentation fault on exiting keepassxc-cli after DB was opened #5367

@Colfenor

Description

@Colfenor

Overview

After opening a database file with the keepassxc-cli,
entering a valid command and exiting the cli a seg-fault occurs.

Steps to Reproduce

  1. Open a .kdbx database file with the keepassxc-cli open cmd
  2. Enter any valid command as defined in the namespace commands
  3. Exit the shell by either "exit" or "quit"
    -> boom, segmentation fault.

After investigating with AddressSanitizer it seems that
the ~Database destructor is called twice, since the QSharedPointer
variable cmd->currentDatabase & currentDatabase is initialized to
the the same address.

seen in:
https://github.com/keepassxreboot/keepassxc/blob/develop/src/cli/keepassxc-cli.cpp#L167#L169

Expected Behavior

No call to destructor of currentDatabase variable twice.

Actual Behavior

Segmentation fault due to double-free.

Context

KeePassXC - Version 2.6.1-snapshot
Build Type: Snapshot
Revision: f49f62d

Qt 5.15.0
Debugging mode is enabled.

Operating system: Arch Linux
CPU architecture: x86_64
Kernel: linux 5.8.5-arch1-1

Enabled extensions:

  • Auto-Type
  • Browser Integration
  • SSH Agent
  • KeeShare (signed and unsigned sharing)
  • YubiKey
  • Secret Service Integration

Cryptographic libraries:
libgcrypt 1.8.6

AddressSanitizer Debug-output:

./keepassxc-cli open ~/Passwords.kdbx
Enter password to unlock /home/ExampleUser/Passwords.kdbx: 
Passwords> ls
internet/
Passwords> exit
=================================================================
==57198==ERROR: AddressSanitizer: heap-use-after-free on address 0x60400000b9e4 at pc 0x56517f75b886 bp 0x7ffd6a6c1190 sp 0x7ffd6a6c1180
READ of size 4 at 0x60400000b9e4 thread T0
    #0 0x56517f75b885 in QHash<QUuid, QPointer<Database> >::isEmpty() const (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x5f6885)
    #1 0x56517f758525 in QHash<QUuid, QPointer<Database> >::remove(QUuid const&) (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x5f3525)
    #2 0x56517f750a96 in Database::releaseData() /home/ExampleUser/Code/keepassxc/src/core/Database.cpp:436
    #3 0x56517f74d9c6 in Database::~Database() /home/ExampleUser/Code/keepassxc/src/core/Database.cpp:75
    #4 0x56517f6b7f5b in QtSharedPointer::ExternalRefCountWithContiguousData<Database>::deleter(QtSharedPointer::ExternalRefCountData*) /usr/include/qt/QtCore/qsharedpointer_impl.h:247
    #5 0x56517f68c40f in QtSharedPointer::ExternalRefCountData::destroy() /usr/include/qt/QtCore/qsharedpointer_impl.h:148
    #6 0x56517f68e8f6 in QSharedPointer<Database>::deref(QtSharedPointer::ExternalRefCountData*) /usr/include/qt/QtCore/qsharedpointer_impl.h:456
    #7 0x56517f68e14e in QSharedPointer<Database>::deref() /usr/include/qt/QtCore/qsharedpointer_impl.h:451
    #8 0x56517f68d16f in QSharedPointer<Database>::~QSharedPointer() /usr/include/qt/QtCore/qsharedpointer_impl.h:309
    #9 0x56517f68fe82 in Command::~Command() /home/ExampleUser/Code/keepassxc/src/cli/Command.cpp:108
    #10 0x56517f68f45a in DatabaseCommand::~DatabaseCommand() /home/ExampleUser/Code/keepassxc/src/cli/DatabaseCommand.h:27
    #11 0x56517f6b3d54 in List::~List() /home/ExampleUser/Code/keepassxc/src/cli/List.h:23
    #12 0x56517f6b3d6f in List::~List() /home/ExampleUser/Code/keepassxc/src/cli/List.h:23
    #13 0x56517f6a0062 in QtSharedPointer::CustomDeleter<List, QtSharedPointer::NormalDeleter>::execute() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53b062)
    #14 0x56517f69dd09 in QtSharedPointer::ExternalRefCountWithCustomDeleter<List, QtSharedPointer::NormalDeleter>::deleter(QtSharedPointer::ExternalRefCountData*) /usr/include/qt/QtCore/qsharedpointer_impl.h:204
    #15 0x56517f68c40f in QtSharedPointer::ExternalRefCountData::destroy() /usr/include/qt/QtCore/qsharedpointer_impl.h:148
    #16 0x56517f68e9e2 in QSharedPointer<Command>::deref(QtSharedPointer::ExternalRefCountData*) /usr/include/qt/QtCore/qsharedpointer_impl.h:456
    #17 0x56517f68e238 in QSharedPointer<Command>::deref() /usr/include/qt/QtCore/qsharedpointer_impl.h:451
    #18 0x56517f68d293 in QSharedPointer<Command>::~QSharedPointer() /usr/include/qt/QtCore/qsharedpointer_impl.h:309
    #19 0x56517f6a09b7 in std::enable_if<QTypeInfo<QSharedPointer<Command> >::isComplex, void>::type QMapNodeBase::callDestructorIfNecessary<QSharedPointer<Command> >(QSharedPointer<Command>&) (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53b9b7)
    #20 0x56517f69f3d9 in QMapNode<QString, QSharedPointer<Command> >::destroySubTree() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53a3d9)
    #21 0x56517f6a0a0d in QMapNode<QString, QSharedPointer<Command> >::doDestroySubTree(std::integral_constant<bool, true>) (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53ba0d)
    #22 0x56517f69f3e5 in QMapNode<QString, QSharedPointer<Command> >::destroySubTree() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53a3e5)
    #23 0x56517f6a0a0d in QMapNode<QString, QSharedPointer<Command> >::doDestroySubTree(std::integral_constant<bool, true>) (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53ba0d)
    #24 0x56517f69f3e5 in QMapNode<QString, QSharedPointer<Command> >::destroySubTree() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53a3e5)
    #25 0x56517f6a0a53 in QMapNode<QString, QSharedPointer<Command> >::doDestroySubTree(std::integral_constant<bool, true>) (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53ba53)
    #26 0x56517f69f3e5 in QMapNode<QString, QSharedPointer<Command> >::destroySubTree() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53a3e5)
    #27 0x56517f6a0a53 in QMapNode<QString, QSharedPointer<Command> >::doDestroySubTree(std::integral_constant<bool, true>) (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53ba53)
    #28 0x56517f69f3e5 in QMapNode<QString, QSharedPointer<Command> >::destroySubTree() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53a3e5)
    #29 0x56517f69c74b in QMapData<QString, QSharedPointer<Command> >::destroy() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x53774b)
    #30 0x56517f698cba in QMap<QString, QSharedPointer<Command> >::~QMap() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x533cba)
    #31 0x7ff6b7ad8db6 in __run_exit_handlers (/usr/lib/libc.so.6+0x3fdb6)
    #32 0x7ff6b7ad8f5d in __GI_exit (/usr/lib/libc.so.6+0x3ff5d)
    #33 0x7ff6b7ac1158 in __libc_start_main (/usr/lib/libc.so.6+0x28158)
    #34 0x56517f68846d in _start (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x52346d)

0x60400000b9e4 is located 20 bytes inside of 48-byte region [0x60400000b9d0,0x60400000ba00)
freed by thread T0 here:
    #0 0x7ff6b98e0009 in operator delete(void*, unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:172
    #1 0x56517f75dc58 in QHash<QUuid, QPointer<Database> >::freeData(QHashData*) (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x5f8c58)
    #2 0x56517f760205 in QHash<QUuid, QPointer<Database> >::~QHash() (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x5fb205)
    #3 0x7ff6b7ad8db6 in __run_exit_handlers (/usr/lib/libc.so.6+0x3fdb6)

previously allocated by thread T0 here:
    #0 0x7ff6b98def41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7ff6b81cfd47 in QHashData::detach_helper(void (*)(QHashData::Node*, void*), void (*)(QHashData::Node*), int, int) (/usr/lib/libQt5Core.so.5+0x107d47)

SUMMARY: AddressSanitizer: heap-use-after-free (/home/ExampleUser/Code/keepassxc/build/src/cli/keepassxc-cli+0x5f6885) in QHash<QUuid, QPointer<Database> >::isEmpty() const
Shadow bytes around the buggy address:
  0x0c087fff96e0: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 00 fa
  0x0c087fff96f0: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa
  0x0c087fff9700: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa
  0x0c087fff9710: fa fa 00 00 00 00 00 fa fa fa fd fd fd fd fd fa
  0x0c087fff9720: fa fa fd fd fd fd fd fa fa fa 00 00 00 00 00 fa
=>0x0c087fff9730: fa fa fd fd fd fd fd fd fa fa fd fd[fd]fd fd fd
  0x0c087fff9740: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 00 fa
  0x0c087fff9750: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fa
  0x0c087fff9760: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd
  0x0c087fff9770: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x0c087fff9780: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==57198==ABORTING

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions