Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // Copyright (C) 2022 Intel Corporation.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qsystemsemaphore.h"
++ #include "qsystemsemaphore_p.h"
++
++ #include <qdebug.h>
++ #include <qfile.h>
++ #include <qcoreapplication.h>
++
++ #if QT_CONFIG(sysv_sem)
++
++ #include <sys/types.h>
++ #include <sys/ipc.h>
++ #include <sys/sem.h>
++ #include <fcntl.h>
++ #include <errno.h>
++
++ #if defined(Q_OS_DARWIN)
++ #include "private/qcore_mac_p.h"
++ #endif
++
++ #include "private/qcore_unix_p.h"
++
++ // OpenBSD 4.2 doesn't define EIDRM, see BUGS section:
++ #if defined(Q_OS_OPENBSD) && !defined(EIDRM)
++ #define EIDRM EINVAL
++ #endif
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace Qt::StringLiterals;
++
++ bool QSystemSemaphoreSystemV::runtimeSupportCheck()
++ {
++ #if defined(Q_OS_DARWIN)
++ if (qt_apple_isSandboxed())
++ return false;
++ #endif
++ static const bool result = []() {
++ (void)semget(IPC_PRIVATE, -1, 0); // this will fail
++ return errno != ENOSYS;
++ }();
++ return result;
++ }
++
++ /*!
++ \internal
++
++ Setup unix_key
++ */
++ key_t QSystemSemaphoreSystemV::handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode)
++ {
++ if (unix_key != -1)
++ return unix_key; // we already have a semaphore
++
++ #if defined(Q_OS_DARWIN)
++ if (qt_apple_isSandboxed()) {
++ // attempting to use System V semaphores will get us a SIGSYS
++ self->setError(QSystemSemaphore::PermissionDenied,
++ QSystemSemaphore::tr("%1: System V semaphores are not available for "
++ "sandboxed applications. Please build Qt with "
++ "-feature-ipc_posix")
++ .arg("QSystemSemaphore::handle:"_L1));
++ return -1;
++ }
++ #endif
++
++ nativeKeyFile = QFile::encodeName(self->nativeKey.nativeKey());
++ if (nativeKeyFile.isEmpty()) {
++ self->setError(QSystemSemaphore::KeyError,
++ QSystemSemaphore::tr("%1: key is empty")
++ .arg("QSystemSemaphore::handle:"_L1));
++ return -1;
++ }
++
++ // ftok requires that an actual file exists somewhere
++ int built = QtIpcCommon::createUnixKeyFile(nativeKeyFile);
++ if (-1 == built) {
++ self->setError(QSystemSemaphore::KeyError,
++ QSystemSemaphore::tr("%1: unable to make key")
++ .arg("QSystemSemaphore::handle:"_L1));
++
++ return -1;
++ }
++ createdFile = (1 == built);
++
++ // Get the unix key for the created file
++ unix_key = ftok(nativeKeyFile, int(self->nativeKey.type()));
++ if (-1 == unix_key) {
++ self->setError(QSystemSemaphore::KeyError,
++ QSystemSemaphore::tr("%1: ftok failed")
++ .arg("QSystemSemaphore::handle:"_L1));
++ return -1;
++ }
++
++ // Get semaphore
++ semaphore = semget(unix_key, 1, 0600 | IPC_CREAT | IPC_EXCL);
++ if (-1 == semaphore) {
++ if (errno == EEXIST)
++ semaphore = semget(unix_key, 1, 0600 | IPC_CREAT);
++ if (-1 == semaphore) {
++ self->setUnixErrorString("QSystemSemaphore::handle"_L1);
++ cleanHandle(self);
++ return -1;
++ }
++ } else {
++ createdSemaphore = true;
++ // Force cleanup of file, it is possible that it can be left over from a crash
++ createdFile = true;
++ }
++
++ if (mode == QSystemSemaphore::Create) {
++ createdSemaphore = true;
++ createdFile = true;
++ }
++
++ // Created semaphore so initialize its value.
++ if (createdSemaphore && self->initialValue >= 0) {
++ qt_semun init_op;
++ init_op.val = self->initialValue;
++ if (-1 == semctl(semaphore, 0, SETVAL, init_op)) {
++ self->setUnixErrorString("QSystemSemaphore::handle"_L1);
++ cleanHandle(self);
++ return -1;
++ }
++ }
++
++ return unix_key;
++ }
++
++ /*!
++ \internal
++
++ Cleanup the unix_key
++ */
++ void QSystemSemaphoreSystemV::cleanHandle(QSystemSemaphorePrivate *self)
++ {
++ unix_key = -1;
++
++ // remove the file if we made it
++ if (createdFile) {
++ unlink(nativeKeyFile.constData());
++ createdFile = false;
++ }
++
++ if (createdSemaphore) {
++ if (-1 != semaphore) {
++ if (-1 == semctl(semaphore, 0, IPC_RMID, 0)) {
++ self->setUnixErrorString("QSystemSemaphore::cleanHandle"_L1);
++ #if defined QSYSTEMSEMAPHORE_DEBUG
++ qDebug("QSystemSemaphoreSystemV::cleanHandle semctl failed.");
++ #endif
++ }
++ semaphore = -1;
++ }
++ createdSemaphore = false;
++ }
++ }
++
++ /*!
++ \internal
++ */
++ bool QSystemSemaphoreSystemV::modifySemaphore(QSystemSemaphorePrivate *self, int count)
++ {
++ if (handle(self, QSystemSemaphore::Open) == -1)
++ return false;
++
++ struct sembuf operation;
++ operation.sem_num = 0;
++ operation.sem_op = count;
++ operation.sem_flg = SEM_UNDO;
++
++ int res;
++ QT_EINTR_LOOP(res, semop(semaphore, &operation, 1));
++ if (-1 == res) {
++ // If the semaphore was removed be nice and create it and then modifySemaphore again
++ if (errno == EINVAL || errno == EIDRM) {
++ semaphore = -1;
++ cleanHandle(self);
++ handle(self, QSystemSemaphore::Open);
++ return modifySemaphore(self, count);
++ }
++ self->setUnixErrorString("QSystemSemaphore::modifySemaphore"_L1);
++ #if defined QSYSTEMSEMAPHORE_DEBUG
++ qDebug("QSystemSemaphoreSystemV::modify failed %d %d %d %d %d",
++ count, int(semctl(semaphore, 0, GETVAL)), int(errno), int(EIDRM), int(EINVAL);
++ #endif
++ return false;
++ }
++
++ self->clearError();
++ return true;
++ }
++
++
++ QT_END_NAMESPACE
++
++ #endif // QT_CONFIG(sysv_sem)