File indexing completed on 2024-04-14 15:32:45

0001 /*
0002     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0003     SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org>
0004 */
0005 
0006 #include <QTest>
0007 
0008 #include <limits>
0009 
0010 #include <sys/stat.h>
0011 #include <sys/types.h>
0012 #include <unistd.h>
0013 
0014 #include <linuxprocmapsparser.h>
0015 
0016 class LinuxProcMapsParserTest : public QObject
0017 {
0018     Q_OBJECT
0019     qulonglong m_linuxProcfsMapsInInode = 0;
0020 
0021     QByteArray generateData(const QString &templatePath, qulonglong inode)
0022     {
0023         QFile f(templatePath);
0024         if (!f.open(QFile::ReadOnly)) {
0025             return {};
0026         }
0027         QByteArray data = f.readAll();
0028         data.replace("/__FILE_PATH__", qUtf8Printable(templatePath));
0029         data.replace("__INODE__", QByteArray::number(inode));
0030         return data;
0031     }
0032 
0033 private Q_SLOTS:
0034     void initTestCase()
0035     {
0036         struct stat st {
0037         };
0038         QVERIFY(stat(QFile::encodeName(QFINDTESTDATA("data/linux-procfs-maps.so")).constData(), &st) != -1);
0039         m_linuxProcfsMapsInInode = st.st_ino;
0040     }
0041 
0042     void testHasDeletedStat()
0043     {
0044         // Has definitely missing files because of "(deleted)" suffix.
0045         // The exe is not actually in the fixture to prevent the function from returning early when not finding the exe.
0046         // Should this need changing in the future this needs routing through generateData().
0047         QFile f(QFINDTESTDATA("data/linux-procfs-maps-with-missing-files"));
0048         QVERIFY(f.open(QFile::ReadOnly));
0049         QVERIFY(LinuxProc::hasMapsDeletedFiles("/usr/bin/kwrite", f.readAll(), LinuxProc::Check::DeletedMarker));
0050     }
0051 
0052     void testNoDeletedStat()
0053     {
0054         // fixture also includes a /memfd:... path which we expect to not get reported as deleted. We do need
0055         // to substitute valid data in to get past the inode verification though.
0056         const QString templatePath = QFINDTESTDATA("data/linux-procfs-maps.so");
0057         const QByteArray data = generateData(templatePath, m_linuxProcfsMapsInInode);
0058         QVERIFY(!LinuxProc::hasMapsDeletedFiles(templatePath, data, LinuxProc::Check::Stat));
0059     }
0060 
0061     void testBadInode()
0062     {
0063         const QString templatePath = QFINDTESTDATA("data/linux-procfs-maps.so");
0064         const QByteArray data = generateData(templatePath, m_linuxProcfsMapsInInode - 1 /* random mutation */);
0065         QVERIFY(LinuxProc::hasMapsDeletedFiles(templatePath, data, LinuxProc::Check::Stat));
0066     }
0067 
0068     void testExecMarker()
0069     {
0070         QFile f(QFINDTESTDATA("data/linux-procfs-maps-with-deleted-exe"));
0071         QVERIFY(f.open(QFile::ReadOnly));
0072         QVERIFY(LinuxProc::hasMapsDeletedFiles("/usr/bin/kwrite", f.readAll(), LinuxProc::Check::DeletedMarker));
0073     }
0074 
0075     void testSOMarker()
0076     {
0077         QFile f(QFINDTESTDATA("data/linux-procfs-maps-with-deleted-exe"));
0078         QVERIFY(f.open(QFile::ReadOnly));
0079         QVERIFY(LinuxProc::hasMapsDeletedFiles("/usr/bin/kwrite", f.readAll(), LinuxProc::Check::DeletedMarker));
0080     }
0081 
0082     void testIsLibraryPath()
0083     {
0084         QVERIFY(!LinuxProc::isLibraryPath("/bin/a"));
0085         QVERIFY(!LinuxProc::isLibraryPath("/bin/a."));
0086 
0087         QVERIFY(LinuxProc::isLibraryPath("/bin/a.so"));
0088         QVERIFY(LinuxProc::isLibraryPath("/bin/a.so.0.1"));
0089         // we expect deleted modifiers to match, it keeps the regex simpler
0090         QVERIFY(LinuxProc::isLibraryPath("/bin/a.so.0.1 (deleted)"));
0091         // A bit silly but what if .so appears as a dirname
0092         QVERIFY(!LinuxProc::isLibraryPath("/bin/a.so.0/abc/foo"));
0093 
0094         // Drkonqi also has some python handling for some reason :shrug:
0095         QVERIFY(LinuxProc::isLibraryPath("/bin/a.py"));
0096         QVERIFY(LinuxProc::isLibraryPath("/bin/a.pyc"));
0097         QVERIFY(LinuxProc::isLibraryPath("/bin/a.py (deleted)"));
0098     }
0099 };
0100 
0101 QTEST_GUILESS_MAIN(LinuxProcMapsParserTest)
0102 
0103 #include "linuxprocmapsparsertest.moc"