Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
6.8.2
-
None
-
Ubuntu 20.04 with qt 6.8.2 installed from nixpkgs. x86_64
Description
If a system CA directory like /etc/ssl/certs contains a broken symlink, then QTlsBackendOpenSSL::systemCaCertificates() will walk all directories in the current working directory, recursively. If the current working directory is the root of a very large tree of directories, the function can block at 100 % CPU for several minutes.
I think this is due to this line:
https://github.com/qt/qtbase/blob/6.8.2/src/plugins/tls/openssl/qtlsbackend_openssl.cpp#L398
my build of qt is optimized but indirect observations suggests that fromPath is called with an empty string. This is coherent with the documentation of canonicalFilePath which returns an empty string in case of error.
Steps to reproduce:
compile this code:
#include <QString> #include <QSslCertificate> int main(char *, char**) { QString pem(" \ -----BEGIN CERTIFICATE----- \ MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA \ MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD \ VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy \ MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt \ c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB \ AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ \ OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG \ vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud \ 316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo \ 0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE \ y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF \ zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE \ +cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN \ I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs \ x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa \ ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC \ 4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV \ HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 \ 7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg \ JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti \ 2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk \ pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF \ FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt \ rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk \ ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 \ u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP \ 4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 \ N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 \ vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 \ -----END CERTIFICATE----- \ "); QByteArray data = pem.toLocal8Bit(); QSslCertificate cert(data); qDebug() << cert.toText(); return 0; }
Ensure that the openssl backend is used, for example by force-linking openssl instead of relying on dlopen().
The actual certificate here is not important I just wanted it to be valid.
In a temporary directory create a directory whose name is unique in the full filesystem:
mkdir df0d6eda-1d57-4612-bf58-e477819dfffc
create a broken symlink as follows:
sudo ln -s /nonexistent /etc/ssl/certs/ffff.pem
Ensure that the current working directory is the one containing df0d6eda-1d57-4612-bf58-e477819dfffc and run the program in strace:
strace -yy -s 1000 ./build/foo |& grep df0d6eda-1d57-4612-bf58-e477819dfffc readlink("/tmp/qtreproducer/df0d6eda-1d57-4612-bf58-e477819dfffc", 0x7ffc31a08010, 1023) = -1 EINVAL (Invalid argument) openat(AT_FDCWD, "./df0d6eda-1d57-4612-bf58-e477819dfffc", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4</tmp/qtreproducer/df0d6eda-1d57-4612-bf58-e477819dfffc> fstat(4</tmp/qtreproducer/df0d6eda-1d57-4612-bf58-e477819dfffc>, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 getdents64(4</tmp/qtreproducer/df0d6eda-1d57-4612-bf58-e477819dfffc>, /* 2 entries */, 32768) = 48 getdents64(4</tmp/qtreproducer/df0d6eda-1d57-4612-bf58-e477819dfffc>, /* 0 entries */, 32768) = 0 close(4</tmp/qtreproducer/df0d6eda-1d57-4612-bf58-e477819dfffc>) = 0
Bug: the program attempted to access df0d6eda-1d57-4612-bf58-e477819dfff in the current working directory.
Expected behavior: the program only attempted to read system directories like /etc/ssl/certificates, but not directories below the current working directory.
Additionally, if the symlink is removed, the issue disappears:
/tmp/qtreproducer % sudo rm /etc/ssl/certs/ffff.pem /tmp/qtreproducer % strace -yy -s 1000 ./build/foo |& grep df0d6eda-1d57-4612-bf58-e477819dfffc
This proves that the broken symlink is a cause of the bug.