[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
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 ###################################################
*/
/**
- * @file img.hpp
+ * @file
* @author Lukasz Kostyra (l.kostyra@samsung.com)
* @brief Image utility functions declaration
*/
*/
/**
- * @file img.hpp
+ * @file
* @author Lukasz Kostyra (l.kostyra@samsung.com)
* @brief Image utility functions declaration
*/
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
%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
-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
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
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})")
{
"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",
{
"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",
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.
*/
CONFIG_REGISTER
(
privilege,
+ vt,
switchToDefaultAfterTimeout,
enableDbusIntegration,
config,
#include "logger/logger.hpp"
#include "utils/paths.hpp"
+#include "utils/vt.hpp"
#include "config/manager.hpp"
#include <boost/filesystem.hpp>
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);
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.
*/
/* 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();
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);
}
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();
#error "DISK_GROUP must be defined!"
#endif
+#ifndef TTY_GROUP
+#error "TTY_GROUP must be defined!"
+#endif
+
extern char** environ;
namespace security_containers {
// 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;
}
// 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}));
}
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : true,
"config" : "../libvirt-config/console1-dbus.xml",
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : false,
"enableDbusIntegration" : true,
"config" : "../libvirt-config/console2-dbus.xml",
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : true,
"config" : "../libvirt-config/console3-dbus.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/buggy.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "/this/is/a/missing/file/path/missing.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test-no-shutdown.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "/missing/file/path/libvirt.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : true,
"config" : "../libvirt-config/test-dbus.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "../libvirt-config/test.xml",
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : true,
"config" : "../libvirt-config/console1-dbus.xml",
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "../libvirt-config/console1.xml",
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : false,
"enableDbusIntegration" : true,
"config" : "../libvirt-config/console2-dbus.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "../libvirt-config/console2.xml",
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : true,
"config" : "../libvirt-config/console3-dbus.xml",
{
"privilege" : 15,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "../libvirt-config/console3.xml",
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"config" : "../libvirt-config/~NAME~.xml",
"networkConfig" : "../libvirt-config/~NAME~-network.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "",
{
"privilege" : 20,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "../libvirt-config/container1.xml",
{
"privilege" : 10,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "../libvirt-config/container2.xml",
{
"privilege" : 15,
+ "vt" : -1,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : false,
"config" : "../libvirt-config/container3.xml",