lxcpp: Removed Namespace enum
[platform/core/security/vasum.git] / libs / lxcpp / process.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   process handling routines
22  */
23
24 #include "lxcpp/process.hpp"
25 #include "lxcpp/exception.hpp"
26
27 #include "logger/logger.hpp"
28 #include "utils/fd-utils.hpp"
29 #include "utils/exception.hpp"
30
31 #include <alloca.h>
32 #include <sched.h>
33 #include <unistd.h>
34 #include <sys/wait.h>
35 #include <fcntl.h>
36
37 #include <array>
38
39 namespace lxcpp {
40
41 pid_t fork()
42 {
43     pid_t pid = ::fork();
44     if (pid < 0) {
45         const std::string msg = "fork() failed: " +
46                                 utils::getSystemErrorMessage();
47         LOGE(msg);
48         throw ProcessSetupException(msg);
49     }
50     return pid;
51 }
52
53 pid_t clone(int (*function)(void *),
54             void *args,
55             const int flags)
56 {
57     // Won't fail, well known resource name
58     size_t stackSize = ::sysconf(_SC_PAGESIZE);
59
60     // PAGESIZE is enough, it'll exec after this
61     char *stack = static_cast<char*>(::alloca(stackSize));
62
63     pid_t pid = ::clone(function, stack  + stackSize, flags | SIGCHLD, args);
64     if (pid < 0) {
65         const std::string msg = "clone() failed: " +
66                                 utils::getSystemErrorMessage();
67         LOGE(msg);
68         throw ProcessSetupException(msg);
69     }
70
71     return pid;
72 }
73
74 void setns(const pid_t pid, int requestedNamespaces)
75 {
76     int dirFD = utils::open(getNsPath(pid), O_DIRECTORY | O_CLOEXEC);
77
78     static const std::array<int, 6> NAMESPACES {{
79             CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWNET
80         }};
81
82     // Open FDs connected with the requested namespaces
83     std::vector<int> fds;
84     for(const int ns: NAMESPACES) {
85         if (!(ns & requestedNamespaces)) {
86             // This namespace wasn't requested
87             continue;
88         }
89
90         int fd = ::openat(dirFD,
91                           nsToString(ns).c_str(),
92                           O_RDONLY | O_CLOEXEC);
93         if(fd < 0) {
94             const std::string msg = "openat() failed: " + utils::getSystemErrorMessage();
95
96             // Cleanup file descriptors
97             for (const int d: fds) {
98                 utils::close(d);
99             }
100             utils::close(dirFD);
101
102             LOGE(msg);
103             throw ProcessSetupException(msg);
104         }
105
106         fds.push_back(fd);
107     }
108
109     // Setns to every requested namespace
110     for(size_t i = 0; i < fds.size(); ++i) {
111         if(-1 == ::setns(fds[i], 0 /* we're sure it's a fd of the right namespace*/)) {
112             const std::string msg = "setns() failed: " + utils::getSystemErrorMessage();
113
114             for (size_t j = i; j < fds.size(); ++j) {
115                 utils::close(fds[j]);
116             }
117             utils::close(dirFD);
118
119             LOGE(msg);
120             throw ProcessSetupException(msg);
121         }
122         utils::close(fds[i]);
123     }
124
125     utils::close(dirFD);
126 }
127
128 int waitpid(const pid_t pid)
129 {
130     int status;
131     while (-1 == ::waitpid(pid, &status, 0)) {
132         if (errno == EINTR) {
133             LOGT("waitpid() interrupted, retrying");
134             continue;
135         }
136         const std::string msg = "waitpid() failed: " + utils::getSystemErrorMessage();
137         LOGE(msg);
138         throw ProcessSetupException(msg);
139     }
140
141     // Return child's return status if everything is OK
142     if (WIFEXITED(status)) {
143         return WEXITSTATUS(status);
144     }
145
146     // Something went wrong in the child
147     std::string msg;
148     if (WIFSIGNALED(status)) {
149         msg = "Child killed by signal " + std::to_string(WTERMSIG(status));
150     } else {
151         msg = "Unknown eror in child process";
152     }
153     LOGE(msg);
154     throw ProcessSetupException(msg);
155 }
156
157 void unshare(const int ns)
158 {
159     if(-1 == ::unshare(ns)) {
160         const std::string msg = "unshare() failed: " + utils::getSystemErrorMessage();
161         LOGE(msg);
162         throw ProcessSetupException(msg);
163     }
164 }
165
166 void execve(const std::vector<std::string>& argv)
167 {
168     // Prepare the arguments
169     std::vector<char const *> tmpArgv;
170     tmpArgv.reserve(argv.size() + 1);
171
172     for (auto const &str : argv) {
173         tmpArgv.push_back(str.c_str());
174     }
175     tmpArgv.push_back(nullptr);
176
177     // Run user's binary
178     ::execve(tmpArgv[0], const_cast<char *const*>(tmpArgv.data()), nullptr);
179 }
180
181 } // namespace lxcpp