Implement switchingSequenceMonitorNotify and add VT switching support 74/28174/3
authorLukasz Kostyra <l.kostyra@samsung.com>
Thu, 25 Sep 2014 09:59:58 +0000 (11:59 +0200)
committerJan Olszak <j.olszak@samsung.com>
Thu, 2 Oct 2014 11:15:17 +0000 (04:15 -0700)
[Feature]       switchingSequenceMonitorNotify function implementation and module to handle VT
                switching
[Cause]         Nothing happened when user provided input sequence to Input Monitor
[Solution]      Implemented switchingSequenceMonitorNotify and added VT switching to function
                ContainersManager::focus.
[Verification]  Build, install, run unit tests. Tests (especially FocusTest) should pass.

Change-Id: Ie4aa7d1679bfaa5a0fdfaf238ebc14a3b8150006

38 files changed:
CMakeLists.txt
common/utils/img.cpp
common/utils/img.hpp
common/utils/vt.cpp [new file with mode: 0644]
common/utils/vt.hpp [new file with mode: 0644]
packaging/security-containers.spec
server/CMakeLists.txt
server/configs/containers/business.conf
server/configs/containers/private.conf
server/container-config.hpp
server/container.cpp
server/container.hpp
server/containers-manager.cpp
server/containers-manager.hpp
server/server.cpp
tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf
tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf
tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf
tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in
tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf
tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in
tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in
tests/unit_tests/server/configs/ut-container/containers/buggy.conf
tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf
tests/unit_tests/server/configs/ut-container/containers/test.conf
tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf
tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf
tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf
tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf
tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf
tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf
tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf
tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in
tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf
tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in
tests/unit_tests/server/configs/ut-server/containers/container1.conf
tests/unit_tests/server/configs/ut-server/containers/container2.conf
tests/unit_tests/server/configs/ut-server/containers/container3.conf

index 9cb880a..c8e74c6 100644 (file)
@@ -72,11 +72,15 @@ ENDIF(NOT DEFINED INPUT_EVENT_GROUP)
 IF(NOT DEFINED DISK_GROUP)
     SET(DISK_GROUP "disk")
 ENDIF(NOT DEFINED DISK_GROUP)
+IF(NOT DEFINED TTY_GROUP)
+    SET(TTY_GROUP "tty")
+ENDIF(NOT DEFINED TTY_GROUP)
 
 ADD_DEFINITIONS(-DSECURITY_CONTAINERS_USER="${SECURITY_CONTAINERS_USER}")
 ADD_DEFINITIONS(-DLIBVIRT_GROUP="${LIBVIRT_GROUP}")
 ADD_DEFINITIONS(-DINPUT_EVENT_GROUP="${INPUT_EVENT_GROUP}")
 ADD_DEFINITIONS(-DDISK_GROUP="${DISK_GROUP}")
+ADD_DEFINITIONS(-DTTY_GROUP="${TTY_GROUP}")
 
 ## Python packages directory ###################################################
 
index 4d7de88..bc77491 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 /**
- * @file    img.hpp
+ * @file
  * @author  Lukasz Kostyra (l.kostyra@samsung.com)
  * @brief   Image utility functions declaration
  */
index d42300e..db47cc6 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 /**
- * @file    img.hpp
+ * @file
  * @author  Lukasz Kostyra (l.kostyra@samsung.com)
  * @brief   Image utility functions declaration
  */
diff --git a/common/utils/vt.cpp b/common/utils/vt.cpp
new file mode 100644 (file)
index 0000000..22a697e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Kostyra <l.kostyra@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Lukasz Kostyra (l.kostyra@samsung.com)
+ * @brief   VT-related utility functions
+ */
+
+#include "config.hpp"
+#include "utils/vt.hpp"
+#include "logger/logger.hpp"
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+namespace {
+
+const std::string TTY_DEV = "/dev/tty0";
+
+} // namespace
+
+namespace security_containers {
+namespace utils {
+
+bool activateVT(const int& vt)
+{
+    int consoleFD = ::open(TTY_DEV.c_str(), O_WRONLY);
+    if (consoleFD < 0) {
+        LOGE("console open failed: " << errno << " (" << strerror(errno) << ")");
+        return false;
+    }
+
+    struct vt_stat vtstat;
+    vtstat.v_active = 0;
+    if (::ioctl(consoleFD, VT_GETSTATE, &vtstat)) {
+        LOGE("Failed to get vt state: " << errno << " (" << strerror(errno) << ")");
+        ::close(consoleFD);
+        return false;
+    }
+
+    if (vtstat.v_active == vt) {
+        LOGW("vt" << vt << " is already active.");
+        ::close(consoleFD);
+        return true;
+    }
+
+    // activate vt
+    if (::ioctl(consoleFD, VT_ACTIVATE, vt)) {
+        LOGE("Failed to activate vt" << vt << ": " << errno << " (" << strerror(errno) << ")");
+        ::close(consoleFD);
+        return false;
+    }
+
+    // wait until activation is finished
+    if (::ioctl(consoleFD, VT_WAITACTIVE, vt)) {
+        LOGE("Failed to wait for vt" << vt << " activation: " << errno << " (" << strerror(errno) << ")");
+        ::close(consoleFD);
+        return false;
+    }
+
+    ::close(consoleFD);
+    return true;
+}
+
+} // namespace utils
+} // namespace security_containers
diff --git a/common/utils/vt.hpp b/common/utils/vt.hpp
new file mode 100644 (file)
index 0000000..d285806
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Kostyra <l.kostyra@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Lukasz Kostyra (l.kostyra@samsung.com)
+ * @brief   VT-related utility functions
+ */
+
+#ifndef COMMON_UTILS_VT_HPP
+#define COMMON_UTILS_VT_HPP
+
+namespace security_containers {
+namespace utils {
+
+bool activateVT(const int& vt);
+
+} // namespace utils
+} // namespace security_containers
+
+#endif // COMMON_UTILS_VT_HPP
index 97bf4d5..fc1c806 100644 (file)
@@ -7,6 +7,8 @@
 %define input_event_group video
 # The group has access to /dev/loop* devices.
 %define disk_group disk
+# The group that has write access to /dev/tty* devices.
+%define tty_group tty
 
 Name:           security-containers
 Version:        0.1.1
@@ -71,7 +73,8 @@ between them. A process from inside a container can request a switch of context
          -DSECURITY_CONTAINERS_USER=%{scs_user} \
          -DLIBVIRT_GROUP=%{libvirt_group} \
          -DINPUT_EVENT_GROUP=%{input_event_group} \
-         -DDISK_GROUP=%{disk_group}
+         -DDISK_GROUP=%{disk_group} \
+         -DTTY_GROUP=%{tty_group}
 make -k %{?jobs:-j%jobs}
 
 %install
@@ -88,7 +91,7 @@ if [ $1 == 1 ]; then
     systemctl daemon-reload || :
 fi
 # set needed caps on the binary to allow restart without loosing them
-setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE+ei %{_bindir}/security-containers-server
+setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE,CAP_SYS_TTY_CONFIG+ei %{_bindir}/security-containers-server
 
 %preun
 # Stop the service before uninstall
index 3293307..2237f52 100644 (file)
@@ -45,4 +45,4 @@ ADD_SUBDIRECTORY(configs)
 INSTALL(TARGETS ${SERVER_CODENAME} DESTINATION bin)
 
 ## Set capabilities on server executable #######################################
-INSTALL(CODE "EXECUTE_PROCESS(COMMAND setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE+ei \$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/bin/${SERVER_CODENAME})")
+INSTALL(CODE "EXECUTE_PROCESS(COMMAND setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE,CAP_SYS_TTY_CONFIG+ei \$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/bin/${SERVER_CODENAME})")
index 1b3502a..600edb1 100644 (file)
@@ -1,8 +1,9 @@
 {
     "cpuQuotaForeground" : -1,
-    "cpuQuotaBackground" : 1000,
+    "cpuQuotaBackground" : 10000,
     "enableDbusIntegration" : true,
     "privilege" : 1,
+    "vt" : 3,
     "switchToDefaultAfterTimeout" : true,
     "config" : "../libvirt-config/business.xml",
     "networkConfig" : "../libvirt-config/business-network.xml",
index 62c0f18..71d4bcb 100644 (file)
@@ -1,8 +1,9 @@
 {
     "cpuQuotaForeground" : -1,
-    "cpuQuotaBackground" : 1000,
+    "cpuQuotaBackground" : 10000,
     "enableDbusIntegration" : true,
     "privilege" : 10,
+    "vt" : 2,
     "switchToDefaultAfterTimeout" : true,
     "config" : "../libvirt-config/private.xml",
     "networkConfig" : "../libvirt-config/private-network.xml",
index b506770..e0c6760 100644 (file)
@@ -43,6 +43,11 @@ struct ContainerConfig {
     int privilege;
 
     /**
+     * Number of virtual terminal used by xserver inside container
+     */
+    int vt;
+
+    /**
      * Allow switching to default container after timeout.
      * Setting this to false will disable switching to default container after timeout.
      */
@@ -101,6 +106,7 @@ struct ContainerConfig {
     CONFIG_REGISTER
     (
         privilege,
+        vt,
         switchToDefaultAfterTimeout,
         enableDbusIntegration,
         config,
index 494b0ae..59328db 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "logger/logger.hpp"
 #include "utils/paths.hpp"
+#include "utils/vt.hpp"
 #include "config/manager.hpp"
 
 #include <boost/filesystem.hpp>
@@ -210,6 +211,17 @@ std::string Container::getDbusAddress()
     return mDbusAddress;
 }
 
+bool Container::activateVT()
+{
+    Lock lock(mReconnectMutex);
+
+    if (mConfig.vt >= 0) {
+        return utils::activateVT(mConfig.vt);
+    }
+
+    return true;
+}
+
 void Container::goForeground()
 {
     Lock lock(mReconnectMutex);
index f741464..6800f7a 100644 (file)
@@ -101,6 +101,13 @@ public:
     void stop();
 
     /**
+     * Activate this container's VT
+     *
+     * @return Was activation successful?
+     */
+    bool activateVT();
+
+    /**
      * Setup this container to be put in the foreground.
      * I.e. set appropriate scheduler level.
      */
index 5dc909b..d8858ab 100644 (file)
@@ -183,6 +183,11 @@ void ContainersManager::focus(const std::string& containerId)
     /* try to access the object first to throw immediately if it doesn't exist */
     ContainerMap::mapped_type& foregroundContainer = mContainers.at(containerId);
 
+    if (!foregroundContainer->activateVT()) {
+        LOGE("Failed to activate containers VT. Aborting focus.");
+        return;
+    }
+
     for (auto& container : mContainers) {
         LOGD(container.second->getId() << ": being sent to background");
         container.second->goBackground();
@@ -240,10 +245,31 @@ std::string ContainersManager::getRunningForegroundContainerId()
     return std::string();
 }
 
+std::string ContainersManager::getNextToForegroundContainerId()
+{
+    // handles case where there is no next container
+    if (mContainers.size() < 2) {
+        return std::string();
+    }
+
+    for (auto it = mContainers.begin(); it != mContainers.end(); ++it) {
+        if (it->first == mConfig.foregroundId &&
+            it->second->isRunning()) {
+            auto nextIt = std::next(it);
+            if (nextIt != mContainers.end()) {
+                return nextIt->first;
+            }
+        }
+    }
+    return mContainers.begin()->first;
+}
+
 void ContainersManager::switchingSequenceMonitorNotify()
 {
     LOGI("switchingSequenceMonitorNotify() called");
-    // TODO: implement
+
+    auto nextContainerId = getNextToForegroundContainerId();
+    focus(nextContainerId);
 }
 
 
index cd1194d..3cbf833 100644 (file)
@@ -78,6 +78,12 @@ public:
     std::string getRunningForegroundContainerId();
 
     /**
+     * @return id of next to currently focused/foreground container. If currently focused container
+     *         is last in container map, id of fisrt container from map is returned.
+     */
+    std::string getNextToForegroundContainerId();
+
+    /**
      * Set whether ContainersManager should detach containers on exit
      */
     void setContainersDetachOnExit();
index 547d023..a9ad444 100644 (file)
 #error "DISK_GROUP must be defined!"
 #endif
 
+#ifndef TTY_GROUP
+#error "TTY_GROUP must be defined!"
+#endif
+
 extern char** environ;
 
 namespace security_containers {
@@ -189,7 +193,7 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot)
     // INPUT_EVENT_GROUP provides access to /dev/input/event* devices used by InputMonitor.
     // DISK_GROUP provides access to /dev/loop* devices, needed when adding new container to copy
     //            containers image
-    if (!utils::setSuppGroups({LIBVIRT_GROUP, INPUT_EVENT_GROUP, DISK_GROUP})) {
+    if (!utils::setSuppGroups({LIBVIRT_GROUP, INPUT_EVENT_GROUP, DISK_GROUP, TTY_GROUP})) {
         return false;
     }
 
@@ -197,7 +201,10 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot)
     // NOTE: CAP_MAC_OVERRIDE is temporary and must be removed when "smack namespace"
     // is introduced. The capability is needed to allow modify SMACK labels of
     // "/var/run/containers/<container>/run" mount point.
-    return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN, CAP_MAC_OVERRIDE}));
+    // CAP_SYS_TTY_CONFIG is needed to activate virtual terminals through ioctl calls
+    return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN,
+                                                    CAP_MAC_OVERRIDE,
+                                                    CAP_SYS_TTY_CONFIG}));
 }
 
 
index e16f7d6..b32dd81 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : true,
     "config" : "../libvirt-config/console1-dbus.xml",
index 9aa8e51..3dda658 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : false,
     "enableDbusIntegration" : true,
     "config" : "../libvirt-config/console2-dbus.xml",
index 09ef262..0128c09 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : true,
     "config" : "../libvirt-config/console3-dbus.xml",
index 6a0ba2d..f9f553e 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/buggy.xml",
index 4184401..8312204 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "/this/is/a/missing/file/path/missing.xml",
index 995f5ff..135654c 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test-no-shutdown.xml",
index a1d3d53..de566ea 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test.xml",
index 5992433..d0a307e 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "/missing/file/path/libvirt.xml",
index 6301a5a..a272aa1 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : true,
     "config" : "../libvirt-config/test-dbus.xml",
index 111d9ee..bed56de 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "../libvirt-config/test.xml",
index e16f7d6..b32dd81 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : true,
     "config" : "../libvirt-config/console1-dbus.xml",
index be47df6..884e56d 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "../libvirt-config/console1.xml",
index 9aa8e51..3dda658 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : false,
     "enableDbusIntegration" : true,
     "config" : "../libvirt-config/console2-dbus.xml",
index 4c88170..9928914 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "../libvirt-config/console2.xml",
index 09ef262..0128c09 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : true,
     "config" : "../libvirt-config/console3-dbus.xml",
index d6bc429..8a31b50 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 15,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "../libvirt-config/console3.xml",
index 40dcacc..aeed716 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "config" : "../libvirt-config/~NAME~.xml",
     "networkConfig" : "../libvirt-config/~NAME~-network.xml",
index 414b920..695ed15 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "",
index 13ccc44..76492bb 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "",
index be65ee2..990da9a 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "",
index 21fb52a..984e973 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 20,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "../libvirt-config/container1.xml",
index 6302a39..d340530 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 10,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "../libvirt-config/container2.xml",
index b445156..a9d9e97 100644 (file)
@@ -1,5 +1,6 @@
 {
     "privilege" : 15,
+    "vt" : -1,
     "switchToDefaultAfterTimeout" : true,
     "enableDbusIntegration" : false,
     "config" : "../libvirt-config/container3.xml",