diff options
-rw-r--r-- | src/corelib/configure.cmake | 4 | ||||
-rw-r--r-- | src/corelib/kernel/qcore_mac.mm | 6 | ||||
-rw-r--r-- | src/corelib/kernel/qcore_mac_p.h | 6 | ||||
-rw-r--r-- | src/corelib/kernel/qsharedmemory.cpp | 63 | ||||
-rw-r--r-- | src/corelib/kernel/qsharedmemory_posix.cpp | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qsystemsemaphore.cpp | 7 | ||||
-rw-r--r-- | src/corelib/kernel/qsystemsemaphore_systemv.cpp | 14 | ||||
-rw-r--r-- | src/corelib/kernel/qsystemsemaphore_unix.cpp | 6 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp | 22 |
9 files changed, 113 insertions, 17 deletions
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index e82ac8bf93..b10c99246f 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -567,8 +567,8 @@ qt_feature("inotify" PUBLIC PRIVATE qt_feature_definition("inotify" "QT_NO_INOTIFY" NEGATE VALUE "1") qt_feature("ipc_posix" LABEL "Using POSIX IPC" - AUTODETECT NOT WIN32 - CONDITION NOT TEST_ipc_sysv AND TEST_ipc_posix + AUTODETECT NOT WIN32 AND ( ( APPLE AND QT_FEATURE_appstore_compliant ) OR NOT TEST_ipc_sysv ) + CONDITION TEST_ipc_posix ) qt_feature_definition("ipc_posix" "QT_POSIX_IPC") qt_feature("journald" PRIVATE diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm index 6a8db38cc3..a4b8a4a628 100644 --- a/src/corelib/kernel/qcore_mac.mm +++ b/src/corelib/kernel/qcore_mac.mm @@ -396,9 +396,9 @@ AppleApplication *qt_apple_sharedApplication() } #endif -#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED) bool qt_apple_isSandboxed() { +#if defined(Q_OS_MACOS) static bool isSandboxed = []() { QCFType<SecStaticCodeRef> staticCode = nullptr; NSURL *executableUrl = NSBundle.mainBundle.executableURL; @@ -418,8 +418,12 @@ bool qt_apple_isSandboxed() return true; }(); return isSandboxed; +#else + return true; // All other Apple platforms +#endif } +#if !defined(QT_BOOTSTRAPPED) QT_END_NAMESPACE @implementation NSObject (QtSandboxHelpers) - (id)qt_valueForPrivateKey:(NSString *)key diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 953e9ed6d7..7634ffb221 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -196,16 +196,14 @@ Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QCFString &string); #endif Q_CORE_EXPORT bool qt_apple_isApplicationExtension(); - -#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED) Q_CORE_EXPORT bool qt_apple_isSandboxed(); -# ifdef __OBJC__ + +#if !defined(QT_BOOTSTRAPPED) && defined(__OBJC__) QT_END_NAMESPACE @interface NSObject (QtSandboxHelpers) - (id)qt_valueForPrivateKey:(NSString *)key; @end QT_BEGIN_NAMESPACE -# endif #endif #if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS) diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp index 57f3d29077..3dbbe75fc4 100644 --- a/src/corelib/kernel/qsharedmemory.cpp +++ b/src/corelib/kernel/qsharedmemory.cpp @@ -47,6 +47,17 @@ # include <qt_windows.h> #endif +#if defined(Q_OS_DARWIN) +# include "qcore_mac_p.h" +# if !defined(SHM_NAME_MAX) + // Based on PSEMNAMLEN in XNU's posix_sem.c, which would + // indicate the max length is 31, _excluding_ the zero + // terminator. But in practice (possibly due to an off- + // by-one bug in the kernel) the usable bytes are only 30. +# define SHM_NAME_MAX 30 +# endif +#endif + QT_BEGIN_NAMESPACE #if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE)) @@ -65,16 +76,32 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, if (key.isEmpty()) return QString(); - QString result = prefix; + QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex(); +#if defined(Q_OS_DARWIN) && defined(QT_POSIX_IPC) + if (qt_apple_isSandboxed()) { + // Sandboxed applications on Apple platforms require the shared memory name + // to be in the form <application group identifier>/<custom identifier>. + // Since we don't know which application group identifier the user wants + // to apply, we instead document that requirement, and use the key directly. + return key; + } else { + // The shared memory name limit on Apple platforms is very low (30 characters), + // so we can't use the logic below of combining the prefix, key, and a hash, + // to ensure a unique and valid name. Instead we use the first part of the + // hash, which should still long enough to avoid collisions in practice. + return QLatin1Char('/') + hex.left(SHM_NAME_MAX - 1); + } +#endif + + QString result = prefix; for (QChar ch : key) { if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z')) || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))) result += ch; } - - QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex(); result.append(QLatin1String(hex)); + #ifdef Q_OS_WIN return result; #elif defined(QT_POSIX_IPC) @@ -121,6 +148,36 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, process. This means that QSharedMemory should not be used across multiple threads in the same process in HP-UX. + \li Apple platforms: Sandboxed applications (including apps + shipped through the Apple App Store) require the use of POSIX + shared memory (instead of System V shared memory), which adds + a number of limitations, including: + + \list + + \li The key must be in the form \c {<application group identifier>/<custom identifier>}, + as documented \l {https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24} + {here} and \l {https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups} + {here}. + + \li The key length is limited to 30 characters. + + \li On process exit, the named shared memory entries are not + cleaned up, so restarting the application and re-creating the + shared memory under the same name will fail. To work around this, + fall back to attaching to the existing shared memory entry: + + \code + + QSharedMemory shm("DEVTEAMID.app-group/shared"); + if (!shm.create(42) && shm.error() == QSharedMemory::AlreadyExists) + shm.attach(); + + \endcode + + + \endlist + \endlist Remember to lock the shared memory with lock() before reading from diff --git a/src/corelib/kernel/qsharedmemory_posix.cpp b/src/corelib/kernel/qsharedmemory_posix.cpp index d83ff4cb92..9406e200be 100644 --- a/src/corelib/kernel/qsharedmemory_posix.cpp +++ b/src/corelib/kernel/qsharedmemory_posix.cpp @@ -102,7 +102,6 @@ bool QSharedMemoryPrivate::create(qsizetype size) const int errorNumber = errno; const QLatin1String function("QSharedMemory::attach (shm_open)"); switch (errorNumber) { - case ENAMETOOLONG: case EINVAL: errorString = QSharedMemory::tr("%1: bad name").arg(function); error = QSharedMemory::KeyError; @@ -146,7 +145,6 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) const int errorNumber = errno; const QLatin1String function("QSharedMemory::attach (shm_open)"); switch (errorNumber) { - case ENAMETOOLONG: case EINVAL: errorString = QSharedMemory::tr("%1: bad name").arg(function); error = QSharedMemory::KeyError; diff --git a/src/corelib/kernel/qsystemsemaphore.cpp b/src/corelib/kernel/qsystemsemaphore.cpp index 011a673d69..063363189d 100644 --- a/src/corelib/kernel/qsystemsemaphore.cpp +++ b/src/corelib/kernel/qsystemsemaphore.cpp @@ -124,6 +124,13 @@ QT_BEGIN_NAMESPACE \endlist + \b{Apple platforms:} Sandboxed applications (including apps + shipped through the Apple App Store) require the key to + be in the form \c {<application group identifier>/<custom identifier>}, + as documented \l {https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24} + {here} and \l {https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups} + {here}, and the key length is limited to 30 characters. + \sa QSharedMemory, QSemaphore */ diff --git a/src/corelib/kernel/qsystemsemaphore_systemv.cpp b/src/corelib/kernel/qsystemsemaphore_systemv.cpp index d861a35358..1c9fc1f2f7 100644 --- a/src/corelib/kernel/qsystemsemaphore_systemv.cpp +++ b/src/corelib/kernel/qsystemsemaphore_systemv.cpp @@ -54,6 +54,10 @@ #include <fcntl.h> #include <errno.h> +#if defined(Q_OS_DARWIN) +#include "qcore_mac_p.h" +#endif + #include "private/qcore_unix_p.h" // OpenBSD 4.2 doesn't define EIDRM, see BUGS section: @@ -71,6 +75,16 @@ QT_BEGIN_NAMESPACE */ key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) { +#if defined(Q_OS_DARWIN) + if (qt_apple_isSandboxed()) { + errorString = QSystemSemaphore::tr("%1: System V semaphores are not available " \ + "for sandboxed applications. Please build Qt with -feature-ipc_posix") + .arg(QLatin1String("QSystemSemaphore::handle:")); + error = QSystemSemaphore::PermissionDenied; + return -1; + } +#endif + if (key.isEmpty()){ errorString = QSystemSemaphore::tr("%1: key is empty") .arg(QLatin1String("QSystemSemaphore::handle:")); diff --git a/src/corelib/kernel/qsystemsemaphore_unix.cpp b/src/corelib/kernel/qsystemsemaphore_unix.cpp index 25da6eb333..dad2249270 100644 --- a/src/corelib/kernel/qsystemsemaphore_unix.cpp +++ b/src/corelib/kernel/qsystemsemaphore_unix.cpp @@ -89,6 +89,12 @@ void QSystemSemaphorePrivate::setErrorString(const QString &function) errorString = QSystemSemaphore::tr("%1: out of resources").arg(function); error = QSystemSemaphore::OutOfResources; break; +#if defined(QT_POSIX_IPC) + case ENAMETOOLONG: + errorString = QSystemSemaphore::tr("%1: key too long").arg(function); + error = QSystemSemaphore::KeyError; + break; +#endif default: errorString = QSystemSemaphore::tr("%1: unknown error %2").arg(function).arg(errno); error = QSystemSemaphore::UnknownError; diff --git a/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp b/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp index 31b9c9740a..81a7dcf36f 100644 --- a/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp +++ b/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp @@ -182,14 +182,15 @@ int tst_QSharedMemory::remove(const QString &key) if (key.isEmpty()) return -1; - // ftok requires that an actual file exists somewhere QString fileName = QSharedMemoryPrivate::makePlatformSafeKey(key); + +#ifndef QT_POSIX_IPC + // ftok requires that an actual file exists somewhere if (!QFile::exists(fileName)) { //qDebug() << "exits failed"; return -2; } -#ifndef QT_POSIX_IPC int unix_key = ftok(fileName.toLatin1().constData(), 'Q'); if (-1 == unix_key) { qDebug() << "ftok failed"; @@ -209,8 +210,10 @@ int tst_QSharedMemory::remove(const QString &key) } #else if (shm_unlink(QFile::encodeName(fileName).constData()) == -1) { - qDebug() << "shm_unlink failed"; - return -5; + if (errno != ENOENT) { + qDebug() << "shm_unlink failed"; + return -5; + } } #endif // QT_POSIX_IPC @@ -374,7 +377,7 @@ void tst_QSharedMemory::lock() QVERIFY(!shm.lock()); QCOMPARE(shm.error(), QSharedMemory::LockError); - shm.setKey(QLatin1String("qsharedmemory")); + shm.setKey(rememberKey(QLatin1String("qsharedmemory"))); QVERIFY(!shm.lock()); QCOMPARE(shm.error(), QSharedMemory::LockError); @@ -411,6 +414,11 @@ void tst_QSharedMemory::removeWhileAttached() delete smOne; delete smTwo; +#ifdef QT_POSIX_IPC + // POSIX IPC doesn't guarantee that the shared memory is removed + remove("one"); +#endif + // three shouldn't be able to attach QSharedMemory smThree(QLatin1String("one")); QVERIFY(!smThree.attach()); @@ -580,6 +588,10 @@ void tst_QSharedMemory::simpleDoubleProducerConsumer() int size = 512; QVERIFY(producer.create(size)); QVERIFY(producer.detach()); +#ifdef QT_POSIX_IPC + // POSIX IPC doesn't guarantee that the shared memory is removed + remove("market"); +#endif QVERIFY(producer.create(size)); { |