diff --git a/src/common/sailjail.c b/src/common/sailjail.c index cad0674..40b8957 100644 --- a/src/common/sailjail.c +++ b/src/common/sailjail.c @@ -26,6 +26,7 @@ #define SAILJAIL_KEY_ORGANIZATION_NAME "OrganizationName" #define SAILJAIL_KEY_APPLICATION_NAME "ApplicationName" #define SAILJAIL_KEY_PERMISSIONS "Permissions" +#define SAILJAIL_KEY_MODE "Mode" #define NEMO_KEY_APPLICATION_TYPE "X-Nemo-Application-Type" #define NEMO_KEY_SINGLE_INSTANCE "X-Nemo-Single-Instance" #define MAEMO_KEY_FIXED_ARGS "X-Maemo-Fixed-Args" @@ -49,6 +50,10 @@ #define PERMISSIONMGR_SIGNAL_APP_CHANGED "ApplicationChanged" #define PERMISSIONMGR_SIGNAL_APP_REMOVED "ApplicationRemoved" +/* Sailjaild errors */ +#define CODE_INVALID_ARGS "org.freedesktop.DBus.Error.InvalidArgs" +#define ERROR_INVALID_APPNAME "Invalid application name: " + static DBusConnection * sailjail_connect_bus(void) { @@ -121,7 +126,7 @@ iter_at(DBusMessageIter *iter, int type) static GHashTable * sailjail_application_info(DBusConnection *con, const char *desktop) { - GHashTable *info = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); + GHashTable *info = NULL; DBusError err = DBUS_ERROR_INIT; DBusMessage *req = NULL; DBusMessage *rsp = NULL; @@ -140,7 +145,10 @@ sailjail_application_info(DBusConnection *con, const char *desktop) } if (!(rsp = dbus_connection_send_with_reply_and_block(con, req, DBUS_TIMEOUT_INFINITE, &err))) { - error("method call failed: %s: %s", err.name, err.message); + if (strcmp(err.name, CODE_INVALID_ARGS) || + strncmp(err.message, ERROR_INVALID_APPNAME, strlen(ERROR_INVALID_APPNAME))) { + error("method call failed: %s: %s", err.name, err.message); + } goto EXIT; } @@ -160,6 +168,8 @@ sailjail_application_info(DBusConnection *con, const char *desktop) goto EXIT; } + info = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); + DBusMessageIter ArrayIter; dbus_message_iter_recurse(&bodyIter, &ArrayIter); while (!iter_at(&ArrayIter, DBUS_TYPE_INVALID)) { @@ -557,3 +567,29 @@ EXIT: return allowed; } + +bool sailjail_sandbox(const char *desktop) +{ + bool sandboxed = false; + DBusConnection *con = NULL; + GHashTable *info = NULL; + const char *mode; + + if (!(con = sailjail_connect_bus())) + goto EXIT; + + if (!(info = sailjail_application_info(con, desktop))) + goto EXIT; + + if ((mode = appinfo_string(info, SAILJAIL_KEY_MODE)) && g_strcmp0(mode, "None")) { + // Mode is either "Normal" or "Compatibility" + sandboxed = true; + } + +EXIT: + if (info) + g_hash_table_destroy(info); + sailjail_disconnect_bus(con); + + return sandboxed; +} diff --git a/src/common/sailjail.h b/src/common/sailjail.h index ae1d095..01ae508 100644 --- a/src/common/sailjail.h +++ b/src/common/sailjail.h @@ -6,8 +6,12 @@ G_BEGIN_DECLS +#define SAILJAIL_PATH "/usr/bin/sailjail" + bool sailjail_verify_launch(const char *desktop, const char **argv); +bool sailjail_sandbox(const char *desktop); + G_END_DECLS #endif // SAILJAIL_H_ diff --git a/src/launcherlib/appdata.cpp b/src/launcherlib/appdata.cpp index 4e9b8eb..a7535c7 100644 --- a/src/launcherlib/appdata.cpp +++ b/src/launcherlib/appdata.cpp @@ -19,6 +19,7 @@ #include "appdata.h" #include "protocol.h" +#include "sailjail.h" #include #include #include @@ -100,6 +101,16 @@ void AppData::setArgv(const char ** newArgv) } } +void AppData::prependArgv(const char * arg) +{ + char **oldArgv = m_argv; + m_argv = (char **)calloc(++m_argc + 1, sizeof *m_argv); + m_argv[0] = strdup(arg); + for (int i = 1; i < m_argc + 1; ++i) + m_argv[i] = oldArgv[i-1]; + free(oldArgv); +} + const char ** AppData::argv() const { return (const char **)m_argv; @@ -237,6 +248,16 @@ void AppData::checkPrivileges() And then, any file in /usr/share/mapplauncherd/privileges.d/ */ + + /* Sailjail does not use this system to gain privileged group. + * It is skipped to avoid unintended consequenses when launching + * other apps via sailjail. + */ + if (m_fileName == SAILJAIL_PATH) { + m_privileges.clear(); + return; + } + static const char *BOOSTER_APP_PRIVILEGES_LIST = "/usr/share/mapplauncherd/privileges"; static const char *BOOSTER_APP_PRIVILEGES_DIR = "/usr/share/mapplauncherd/privileges.d"; m_privileges = getPrivileges(BOOSTER_APP_PRIVILEGES_LIST); diff --git a/src/launcherlib/appdata.h b/src/launcherlib/appdata.h index 6a9ab08..855d668 100644 --- a/src/launcherlib/appdata.h +++ b/src/launcherlib/appdata.h @@ -72,6 +72,9 @@ public: //! Set address of the argument vector void setArgv(const char ** argv); + //! Prepend to argv + void prependArgv(const char *arg); + //! Return address of the argument vector const char ** argv() const; diff --git a/src/launcherlib/booster.cpp b/src/launcherlib/booster.cpp index 98e7436..e9ea568 100644 --- a/src/launcherlib/booster.cpp +++ b/src/launcherlib/booster.cpp @@ -57,6 +57,11 @@ #include "sailjail.h" +static std::string basename(const std::string &str) +{ + return str.substr(str.find_last_of("/") + 1); +} + Booster::Booster() : m_appData(new AppData), m_connection(NULL), @@ -287,6 +292,12 @@ int Booster::run(SocketManager * socketManager) if (boostedApplication() != "default") { if (!sailjail_verify_launch(boostedApplication().c_str(), m_appData->argv())) throw std::runtime_error("Booster: Binary doesn't have launch permissions\n"); + } else if (m_appData->fileName() != SAILJAIL_PATH && + sailjail_sandbox(basename(m_appData->fileName()).c_str())) { + Logger::logDebug("Sandboxing '%s'", m_appData->fileName()); + // Prepend sailjail to arguments + m_appData->prependArgv(SAILJAIL_PATH); + m_appData->setFileName(SAILJAIL_PATH); } return launchProcess(); @@ -701,7 +712,7 @@ void Booster::resetOomAdj() std::string Booster::getFinalName(const std::string &name) { - if (name == "/usr/bin/sailjail") { + if (name == SAILJAIL_PATH) { // This doesn't implement sailjail's parsing logic but instead // has some assumptions about the arguments: // - If there is --, then the application is