From 3cb9c45c4159e5079dd94f000c6cd6464b8ce490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomi=20Lepp=C3=A4nen?= Date: Wed, 24 Feb 2021 16:57:18 +0200 Subject: [PATCH] [launcherlib] Add checks for invoker. Fixes JB#52956 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that caller is from the same namespace as the booster and the calling binary is /usr/bin/invoker. Signed-off-by: Tomi Leppänen --- src/launcherlib/booster.cpp | 12 ++++- src/launcherlib/connection.cpp | 84 +++++++++++++++++++++++++++++++++- src/launcherlib/connection.h | 14 ++++++ 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/launcherlib/booster.cpp b/src/launcherlib/booster.cpp index 131fad8..aa049fe 100644 --- a/src/launcherlib/booster.cpp +++ b/src/launcherlib/booster.cpp @@ -1,6 +1,8 @@ /*************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2013 - 2021 Jolla Ltd. +** Copyright (C) 2018 - 2020 Open Mobile Platform LLC. ** All rights reserved. ** Contact: Nokia Corporation (directui@nokia.com) ** @@ -58,6 +60,7 @@ Booster::Booster() : m_spaceAvailable(0), m_bootMode(false) { + Connection::setMountNamespace(Connection::getMountNamespace(getpid())); } Booster::~Booster() @@ -236,8 +239,15 @@ bool Booster::receiveDataFromInvoker(int socketFd) // Accept a new invocation. if (m_connection->accept(m_appData)) { + // Check that the caller is allowed to invoke apps + if (!m_connection->isPermitted()) + { + m_connection->close(); + return false; + } + // Receive application data from the invoker - if(!m_connection->receiveApplicationData(m_appData)) + if (!m_connection->receiveApplicationData(m_appData)) { m_connection->close(); return false; diff --git a/src/launcherlib/connection.cpp b/src/launcherlib/connection.cpp index 71bd405..7f08c03 100644 --- a/src/launcherlib/connection.cpp +++ b/src/launcherlib/connection.cpp @@ -1,6 +1,7 @@ /*************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2021 Jolla Ltd. ** All rights reserved. ** Contact: Nokia Corporation (directui@nokia.com) ** @@ -23,6 +24,8 @@ #include #include /* for getsockopt */ #include /* for chmod */ +#include +#include #include #include #include @@ -30,6 +33,10 @@ #include #include +#define INVOKER_PATH "/usr/bin/invoker" + +std::pair Connection::s_mntNS = std::pair(); + Connection::Connection(int socketFd, bool testMode) : m_testMode(testMode), m_fd(-1), @@ -71,7 +78,7 @@ int Connection::getFd() const return m_fd; } -bool Connection::accept(AppData* appData) +bool Connection::accept(AppData*) { if (!m_testMode) { @@ -105,6 +112,47 @@ void Connection::close() } } + +bool Connection::isPermitted() +{ + // Check that caller is in the same namespace and it is invoker + // and not something else. This is done to avoid sandboxed app + // that sees the socket from escaping the sandbox through booster + if (m_fd != -1) + { + pid_t pid = peerPid(); + if (pid == 0) + { + Logger::logError("Connection: %s: getting peer pid failed", __FUNCTION__); + } + else + { + // There is a possibility for a race here: if caller can exit + // and then invoke a process with the correct binary path and + // pid at the right time they could fool us + + if (!s_mntNS.first || getMountNamespace(pid) != s_mntNS) + { + Logger::logWarning("Connection: %s: invocation from %s (%d) came from different namespace", __FUNCTION__, getExecutablePath(pid), pid); + } + else + { + std::string executablePath = getExecutablePath(pid); + if (executablePath != INVOKER_PATH) + { + Logger::logWarning("Connection: %s: executable %s (%d) is not invoker", __FUNCTION__, executablePath, pid); + } + else + { + Logger::logDebug("Connection: %s: invoker (%d) called, allowing", __FUNCTION__, pid); + return true; + } + } + } + } + return false; +} + bool Connection::sendMsg(uint32_t msg) { if (!m_testMode) @@ -545,3 +593,37 @@ pid_t Connection::peerPid() return cr.pid; } + +void Connection::setMountNamespace(std::pair mntNS) +{ + s_mntNS = mntNS; +} + +std::pair Connection::getMountNamespace(pid_t pid) +{ + struct stat sb; + std::ostringstream path; + path << "/proc/" << pid << "/ns/mnt"; + if (stat(path.str().c_str(), &sb) == -1) + { + Logger::logError("Connection: %s: stat failed for pid %d: %s", __FUNCTION__, pid, strerror(errno)); + return std::pair(); + } + return std::pair(sb.st_dev, sb.st_ino); +} + +std::string Connection::getExecutablePath(pid_t pid) +{ + std::ostringstream path; + char exe[PATH_MAX]; + ssize_t len; + static_assert(sizeof(INVOKER_PATH) < sizeof(exe)); + path << "/proc/" << pid << "/exe"; + len = readlink(path.str().c_str(), exe, sizeof(exe)); + if (len < 0 || len >= sizeof(exe)) + { + Logger::logError("Connection: %s: readlink failed for pid %d: %s", __FUNCTION__, pid, strerror(errno)); + return std::string(); + } + return std::string(exe, len); +} diff --git a/src/launcherlib/connection.h b/src/launcherlib/connection.h index d22806b..2fcb49e 100644 --- a/src/launcherlib/connection.h +++ b/src/launcherlib/connection.h @@ -1,6 +1,7 @@ /*************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 - 2021 Jolla Ltd. ** All rights reserved. ** Contact: Nokia Corporation (directui@nokia.com) ** @@ -83,6 +84,15 @@ public: //! \brief Send application exit value bool sendExitValue(int value); + //! \brief Check if caller is permitted to invoke apps + bool isPermitted(); + + //! \brief Get device id and inode number pair of a mount namespace + static std::pair getMountNamespace(pid_t pid); + + //! \brief Set required mount namespace for invoker processes + static void setMountNamespace(std::pair mntNS); + private: /*! \brief Receive actions. @@ -132,6 +142,9 @@ private: //! Send process pid bool sendPid(pid_t pid); + //! Helper method: Get executable path for pid + static std::string getExecutablePath(pid_t pid); + //! Send message to a socket. This is a virtual to help unit testing. virtual bool sendMsg(uint32_t msg); @@ -160,6 +173,7 @@ private: gid_t m_gid; uid_t m_uid; + static std::pair s_mntNS; #ifdef UNIT_TEST friend class Ut_Connection;