Skip to content

Commit

Permalink
[launcherlib] Add checks for invoker. Fixes JB#52956
Browse files Browse the repository at this point in the history
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 <tomi.leppanen@jolla.com>
  • Loading branch information
Tomin1 committed Mar 23, 2021
1 parent 92d182d commit 3cb9c45
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 2 deletions.
12 changes: 11 additions & 1 deletion 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)
**
Expand Down Expand Up @@ -58,6 +60,7 @@ Booster::Booster() :
m_spaceAvailable(0),
m_bootMode(false)
{
Connection::setMountNamespace(Connection::getMountNamespace(getpid()));
}

Booster::~Booster()
Expand Down Expand Up @@ -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;
Expand Down
84 changes: 83 additions & 1 deletion 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)
**
Expand All @@ -23,13 +24,19 @@
#include <sys/socket.h>
#include <sys/un.h> /* for getsockopt */
#include <sys/stat.h> /* for chmod */
#include <limits.h>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <unistd.h>
#include <stdexcept>
#include <sys/syslog.h>

#define INVOKER_PATH "/usr/bin/invoker"

std::pair<dev_t, ino_t> Connection::s_mntNS = std::pair<dev_t, ino_t>();

Connection::Connection(int socketFd, bool testMode) :
m_testMode(testMode),
m_fd(-1),
Expand Down Expand Up @@ -71,7 +78,7 @@ int Connection::getFd() const
return m_fd;
}

bool Connection::accept(AppData* appData)
bool Connection::accept(AppData*)
{
if (!m_testMode)
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -545,3 +593,37 @@ pid_t Connection::peerPid()
return cr.pid;

}

void Connection::setMountNamespace(std::pair<dev_t, ino_t> mntNS)
{
s_mntNS = mntNS;
}

std::pair<dev_t, ino_t> 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<dev_t, ino_t>();
}
return std::pair<dev_t, ino_t>(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);
}
14 changes: 14 additions & 0 deletions 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)
**
Expand Down Expand Up @@ -83,6 +84,15 @@ class DECL_EXPORT Connection
//! \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<dev_t, ino_t> getMountNamespace(pid_t pid);

//! \brief Set required mount namespace for invoker processes
static void setMountNamespace(std::pair<dev_t, ino_t> mntNS);

private:

/*! \brief Receive actions.
Expand Down Expand Up @@ -132,6 +142,9 @@ class DECL_EXPORT Connection
//! 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);

Expand Down Expand Up @@ -160,6 +173,7 @@ class DECL_EXPORT Connection
gid_t m_gid;
uid_t m_uid;

static std::pair<dev_t, ino_t> s_mntNS;

#ifdef UNIT_TEST
friend class Ut_Connection;
Expand Down

0 comments on commit 3cb9c45

Please sign in to comment.