diff --git a/src/greeter/greeterproxy.cpp b/src/greeter/greeterproxy.cpp index 60fa1e87c..22a4b5713 100644 --- a/src/greeter/greeterproxy.cpp +++ b/src/greeter/greeterproxy.cpp @@ -318,8 +318,9 @@ void GreeterProxy::onSessionNew(const QString &id, [[maybe_unused]] const QDBusO QString user = QString::fromLocal8Bit(username); qCInfo(lcTlGreeter) << "New session added: id=" << id << ", user=" << user; userModel()->updateUserLoginState(user, true); + // userLoggedIn signal is connected with Helper::updateActiveUserSession - Q_EMIT userModel()->userLoggedIn(user, id.toInt()); + Q_EMIT userModel()->userLoggedIn(user, id); // Connect to Lock/Unlock signals auto conn = QDBusConnection::systemBus(); @@ -362,7 +363,7 @@ void GreeterProxy::onSessionRemoved(const QString &id, [[maybe_unused]] const QD this, SLOT(onSessionUnlock())); - auto session = Helper::instance()->sessionManager()->sessionForId(id.toInt()); + auto session = Helper::instance()->sessionManager()->sessionForId(id); if (session) { QString username = session->username(); qCInfo(lcTlGreeter) << "Session removed: id=" << id << ", user=" << username; @@ -385,7 +386,7 @@ void GreeterProxy::onSessionLock() OrgFreedesktopLogin1SessionInterface session("org.freedesktop.login1", path, QDBusConnection::systemBus()); - int id = session.id().toInt(); + QString id = session.id(); qCInfo(lcTlGreeter) << "Lock signal received for session id:" << id; auto activeSession = Helper::instance()->sessionManager()->activeSession().lock(); if (!activeSession) @@ -408,7 +409,7 @@ void GreeterProxy::onSessionUnlock() OrgFreedesktopLogin1SessionInterface session("org.freedesktop.login1", path, QDBusConnection::systemBus()); - int id = session.id().toInt(); + QString id = session.id(); const QString username = session.name(); qCInfo(lcTlGreeter) << "Unlock signal received for session id:" << id; auto activeSession = Helper::instance()->sessionManager()->activeSession().lock(); @@ -419,7 +420,7 @@ void GreeterProxy::onSessionUnlock() qCWarning(lcTlGreeter) << "Unlock signal received for non-active session id:" << id << ", lock it back."; QMetaObject::invokeMethod(this, [this, id] { - SocketWriter(m_socket) << quint32(GreeterMessages::Lock) << QString::number(id); + SocketWriter(m_socket) << quint32(GreeterMessages::Lock) << id; }); } else { QMetaObject::invokeMethod(this, [this] { @@ -530,7 +531,7 @@ void GreeterProxy::readyRead() #endif case DaemonMessages::UserActivateMessage: { QString user; - int sessionId; + QString sessionId; input >> user >> sessionId; // NOTE: maybe DDM will active dde user. @@ -563,7 +564,7 @@ void GreeterProxy::readyRead() } break; case DaemonMessages::UserLoggedIn: { QString user; - int sessionId; + QString sessionId; input >> user >> sessionId; // This will happen after a crash recovery of treeland @@ -590,7 +591,7 @@ void GreeterProxy::readyRead() OrgFreedesktopLogin1ManagerInterface manager("org.freedesktop.login1", Logind::managerPath(), conn); - auto reply = manager.GetSession(QString::number(sessionId)); + auto reply = manager.GetSession(sessionId); reply.waitForFinished(); if (!reply.isValid()) { qCWarning(lcTlGreeter) << "Failed to get session path for session id:" << sessionId << ", error:" << reply.error().message(); diff --git a/src/greeter/usermodel.h b/src/greeter/usermodel.h index 1d787983e..194d76799 100644 --- a/src/greeter/usermodel.h +++ b/src/greeter/usermodel.h @@ -86,7 +86,7 @@ class UserModel : public QAbstractListModel void currentUserNameChanged(); void updateTranslations(const QLocale &locale); void countChanged(); - void userLoggedIn(const QString &username, int sessionId); + void userLoggedIn(const QString &username, const QString &sessionId); private Q_SLOTS: void onUserAdded(quint64 uid); diff --git a/src/seat/helper.cpp b/src/seat/helper.cpp index 02d9f5652..605fbf2b6 100644 --- a/src/seat/helper.cpp +++ b/src/seat/helper.cpp @@ -2289,8 +2289,8 @@ void Helper::init(Treeland::Treeland *treeland) this, updateXWaylandOutputScale); updateXWaylandOutputScale(); - // User dde does not has a real Logind session, so just pass 0 as id - m_sessionManager->updateActiveUserSession(QStringLiteral("dde"), 0); + // User dde does not has a real Logind session, so just pass "0" as id + m_sessionManager->updateActiveUserSession(QStringLiteral("dde"), QStringLiteral("0")); connect(m_userModel, &UserModel::userLoggedIn, m_sessionManager, &SessionManager::updateActiveUserSession); m_xdgDecorationManager = m_server->attach(); connect(m_xdgDecorationManager, @@ -3832,7 +3832,7 @@ DDMInterfaceV1 *Helper::ddmInterfaceV1() const { return m_ddmInterfaceV1; } -bool Helper::activateUserSession(const QString &username, int sessionId) +bool Helper::activateUserSession(const QString &username, const QString &sessionId) { if (!m_userModel->getUser(username)) return false; diff --git a/src/seat/helper.h b/src/seat/helper.h index 03a185acb..ee40be5ed 100644 --- a/src/seat/helper.h +++ b/src/seat/helper.h @@ -264,7 +264,7 @@ class Helper : public WSeatEventFilter, public WAYLIB_SERVER_NAMESPACE::WObject inline SessionModel *sessionModel() const { return m_sessionModel; }; DDMInterfaceV1 *ddmInterfaceV1() const; - bool activateUserSession(const QString &username, int sessionId); + bool activateUserSession(const QString &username, const QString &sessionId); void enableRender(); void disableRender(); diff --git a/src/session/session.cpp b/src/session/session.cpp index d0bdb58c7..ac52e295a 100644 --- a/src/session/session.cpp +++ b/src/session/session.cpp @@ -86,7 +86,7 @@ Session::~Session() } } -int Session::id() const +const QString &Session::id() const { return m_id; } @@ -227,10 +227,12 @@ bool SessionManager::activeSocketEnabled() const void SessionManager::setActiveSocketEnabled(bool newEnabled) { auto ptr = m_activeSession.lock(); - if (ptr && ptr->m_socket) - ptr->m_socket->setEnabled(newEnabled, globalSession()->socket()); - else + if (ptr && ptr->m_socket) { + const auto global = globalSession(); + ptr->m_socket->setEnabled(newEnabled, global ? global->socket() : nullptr); + } else { qCWarning(lcTlCore) << "Can't set enabled for empty socket!"; + } } /** @@ -264,7 +266,7 @@ void SessionManager::removeSession(std::shared_ptr session) * @param username Username to ensure session for * @returns Session for the given username, or nullptr on failure */ -std::shared_ptr SessionManager::ensureSession(int id, QString username) +std::shared_ptr SessionManager::ensureSession(const QString &id, QString username) { // Helper lambda to create WSocket and WXWayland auto createWSocket = [this]() { @@ -419,7 +421,7 @@ std::shared_ptr SessionManager::ensureSession(int id, QString username) * @param id Session ID to find session for * @returns Session for the given id, or nullptr if not found */ -std::shared_ptr SessionManager::sessionForId(int id) const +std::shared_ptr SessionManager::sessionForId(const QString &id) const { for (const auto &session : std::as_const(m_sessions)) { if (session && session->m_id == id) @@ -490,7 +492,15 @@ std::shared_ptr SessionManager::sessionForSocket(WSocket *socket) const bool SessionManager::isDDEUserClient(WClient *client) { - return client->socket() == globalSession()->socket(); + // The dde sentinel session is created at startup, but defensive null + // checks guard against it being absent (see issue #1464): dereferencing + // a null globalSession() here previously caused a SIGSEGV. + if (!client) + return false; + const auto global = globalSession(); + if (!global || !global->socket()) + return false; + return client->socket() == global->socket(); } void SessionManager::syncActiveSessionCursorSettings() @@ -526,13 +536,13 @@ void SessionManager::syncActiveSessionCursorSettings() * * @param username Username to set as active session */ -void SessionManager::updateActiveUserSession(const QString &username, int id) +void SessionManager::updateActiveUserSession(const QString &username, const QString &id) { commitActiveUserSession(prepareActiveUserSession(username, id)); } SessionManager::ActiveSessionUpdate SessionManager::prepareActiveUserSession(const QString &username, - int id) + const QString &id) { // Get previous active session auto previous = m_activeSession.lock(); @@ -551,8 +561,10 @@ SessionManager::ActiveSessionUpdate SessionManager::prepareActiveUserSession(con // TODO: Each Wayland socket's active surface needs to be cleaned up individually. Helper::instance()->activateSurface(nullptr); // Update socket enabled state before publishing activation notifications. - if (previous && previous->m_socket) - previous->m_socket->setEnabled(false, globalSession()->socket()); + if (previous && previous->m_socket) { + const auto global = globalSession(); + previous->m_socket->setEnabled(false, global ? global->socket() : nullptr); + } session->m_socket->setEnabled(true); } diff --git a/src/session/session.h b/src/session/session.h index 36a44c01e..4a8c02edc 100644 --- a/src/session/session.h +++ b/src/session/session.h @@ -22,7 +22,7 @@ class Session : public QObject { public: ~Session(); - int id() const; + const QString &id() const; uid_t uid() const; const QString &username() const; WSocket *socket() const; @@ -35,7 +35,10 @@ class Session : public QObject { private: friend class SessionManager; - int m_id = 0; + // The logind session id. Set once in ensureSession() and never mutated + // afterwards; it is read from QThreadPool workers (onSessionLock/Unlock), + // so it must not change after creation. + QString m_id; uid_t m_uid = 0; QString m_username = {}; WSocket *m_socket = nullptr; @@ -73,11 +76,11 @@ class SessionManager : public QObject { } }; - ActiveSessionUpdate prepareActiveUserSession(const QString &username, int id); + ActiveSessionUpdate prepareActiveUserSession(const QString &username, const QString &id); void commitActiveUserSession(const ActiveSessionUpdate &update); - void updateActiveUserSession(const QString &username, int id); + void updateActiveUserSession(const QString &username, const QString &id); void removeSession(std::shared_ptr session); - std::shared_ptr sessionForId(int id) const; + std::shared_ptr sessionForId(const QString &id) const; std::shared_ptr sessionForUid(uid_t uid) const; std::shared_ptr sessionForUser(const QString &username) const; std::shared_ptr sessionForXWayland(WXWayland *xwayland) const; @@ -92,7 +95,7 @@ class SessionManager : public QObject { void xwaylandAuthChanged(); private: - std::shared_ptr ensureSession(int id, QString username); + std::shared_ptr ensureSession(const QString &id, QString username); std::weak_ptr m_activeSession; QList> m_sessions;