lxcpp: Command implementation
[platform/core/security/vasum.git] / libs / lxcpp / commands / attach.cpp
1 /*
2  *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License version 2.1 as published by the Free Software Foundation.
7  *
8  *  This library is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  *  Lesser General Public License for more details.
12  *
13  *  You should have received a copy of the GNU Lesser General Public
14  *  License along with this library; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17
18 /**
19  * @file
20  * @author  Jan Olszak (j.olszak@samsung.com)
21  * @brief   Implementation of attaching to a container
22  */
23
24 #include "lxcpp/commands/attach.hpp"
25 #include "lxcpp/exception.hpp"
26 #include "lxcpp/process.hpp"
27 #include "lxcpp/filesystem.hpp"
28 #include "lxcpp/namespace.hpp"
29 #include "lxcpp/capability.hpp"
30 #include "lxcpp/environment.hpp"
31
32 #include "utils/exception.hpp"
33
34 #include <unistd.h>
35 #include <sys/mount.h>
36
37 #include <functional>
38
39 namespace lxcpp {
40
41 namespace {
42
43 void setupMountPoints()
44 {
45     /* TODO: Uncomment when preparing the final attach() version
46
47     // TODO: This unshare should be optional only if we attach to PID/NET namespace, but not MNT.
48     // Otherwise container already has remounted /proc /sys
49     lxcpp::unshare(Namespace::MNT);
50
51     if (isMountPointShared("/")) {
52         // TODO: Handle case when the container rootfs or mount location is MS_SHARED, but not '/'
53         lxcpp::mount(nullptr, "/", nullptr, MS_SLAVE | MS_REC, nullptr);
54     }
55
56     if(isMountPoint("/proc")) {
57         lxcpp::umount("/proc", MNT_DETACH);
58         lxcpp::mount("none", "/proc", "proc", 0, nullptr);
59     }
60
61     if(isMountPoint("/sys")) {
62         lxcpp::umount("/sys", MNT_DETACH);
63         lxcpp::mount("none", "/sys", "sysfs", 0, nullptr);
64     }
65
66     */
67 }
68
69 int execFunction(void* call)
70 {
71     try {
72         return (*static_cast<Attach::Call*>(call))();
73     } catch(...) {
74         return -1; // Non-zero on failure
75     }
76     return 0; // Success
77 }
78
79 } // namespace
80
81 Attach::Attach(lxcpp::ContainerImpl& container,
82                Container::AttachCall& userCall,
83                const int capsToKeep,
84                const std::string& workDirInContainer,
85                const std::vector<std::string>& envToKeep,
86                const std::vector<std::pair<std::string, std::string>>& envToSet)
87     : mContainer(container),
88       mUserCall(userCall),
89       mCapsToKeep(capsToKeep),
90       mWorkDirInContainer(workDirInContainer),
91       mEnvToKeep(envToKeep),
92       mEnvToSet(envToSet)
93 {
94 }
95
96 Attach::~Attach()
97 {
98 }
99
100 void Attach::execute()
101 {
102     // Channels for setup synchronization
103     utils::Channel intermChannel;
104
105     Call call = std::bind(&Attach::child,
106                           mUserCall,
107                           mCapsToKeep,
108                           mEnvToKeep,
109                           mEnvToSet);
110
111     const pid_t interPid = lxcpp::fork();
112     if (interPid > 0) {
113         intermChannel.setLeft();
114         parent(intermChannel, interPid);
115         intermChannel.shutdown();
116     } else {
117         intermChannel.setRight();
118         interm(intermChannel, call);
119         intermChannel.shutdown();
120         ::_exit(0);
121     }
122 }
123
124 int Attach::child(const Container::AttachCall& call,
125                   const int capsToKeep,
126                   const std::vector<std::string>& envToKeep,
127                   const std::vector<std::pair<std::string, std::string>>& envToSet)
128 {
129     // Setup capabilities
130     dropCapsFromBoundingExcept(capsToKeep);
131
132     // Setup /proc /sys mount
133     setupMountPoints();
134
135     // Setup environment variables
136     clearenvExcept(envToKeep);
137     setenv(envToSet);
138
139     // Run user's code
140     return call();
141 }
142
143 void Attach::parent(utils::Channel& intermChannel, const pid_t interPid)
144 {
145     // TODO: Setup cgroups etc
146     const pid_t childPid = intermChannel.read<pid_t>();
147
148     // Wait for all processes
149     lxcpp::waitpid(interPid);
150     lxcpp::waitpid(childPid);
151 }
152
153 void Attach::interm(utils::Channel& intermChannel, Call& call)
154 {
155     lxcpp::setns(mContainer.getInitPid(), mContainer.getNamespaces());
156
157     // Change the current work directory
158     // workDirInContainer is a path relative to the container's root
159     lxcpp::chdir(mWorkDirInContainer);
160
161     // PID namespace won't affect the returned pid
162     // CLONE_PARENT: Child's PPID == Caller's PID
163     const pid_t childPid = lxcpp::clone(execFunction,
164                                         &call,
165                                         CLONE_PARENT);
166     intermChannel.write(childPid);
167 }
168
169 } // namespace lxcpp