2 * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "launchpad-process-pool/loader_mount.hh"
19 #include <bundle_cpp.h>
20 #include <bundle_internal.h>
21 #include <dlog-redirect-stdout.h>
24 #include <linux/limits.h>
28 #include <sys/types.h>
37 #include <aul_keys.hh>
38 #include <exception.hh>
39 #include <parcelable.hh>
42 #include "launchpad-process-pool/launchpad_args.hh"
43 #include "launchpad-process-pool/log_private.hh"
45 namespace fs = std::filesystem;
48 bool IsExceptable(const std::string& path) {
49 static char buf[PATH_MAX];
50 ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
52 _E("readlink() is failed. errno: %d", errno);
57 if (strstr(buf, "log") != nullptr ||
58 strstr(buf, "trace") != nullptr ||
59 strstr(buf, "dev") != nullptr)
65 std::vector<int> GetExceptableFds() {
68 fs::path proc_path("/proc/self/fd");
69 for (const auto& entry : fs::directory_iterator(proc_path)) {
70 if (!isdigit(entry.path().filename().string()[0]))
73 int fd = std::stoi(entry.path().filename().string());
74 if (dlog_is_log_fd(fd) || IsExceptable(entry.path().string()))
77 } catch (const fs::filesystem_error& e) {
78 _E("Exception occurs. error(%s)", e.what());
84 int ChangeMountNamespace(pid_t pid) {
85 std::string mnt_path = "/proc/" + std::to_string(pid) + "/ns/mnt";
86 int fd = open(mnt_path.c_str(), O_RDONLY);
88 _E("open() is failed. path(%s), errno(%d)", mnt_path.c_str(), errno);
92 int ret = ::setns(fd, 0);
95 _E("setns() is failed. path(%s), errno(%d)", mnt_path.c_str(), errno);
99 _D("setns() is successful. pid(%d)", pid);
103 class Request : public tizen_base::Parcelable {
105 explicit Request(tizen_base::Parcel* parcel) { ReadFromParcel(parcel); }
107 Request(pid_t pid, tizen_base::Bundle b) : pid_(pid), b_(std::move(b)) {}
109 pid_t GetPid() const { return pid_; }
111 const tizen_base::Bundle& GetBundle() const { return b_; }
113 void WriteToParcel(tizen_base::Parcel* parcel) const override {
114 parcel->WriteInt32(pid_);
115 bundle_raw* raw = nullptr;
117 bundle_encode(b_.GetHandle(), &raw, &len);
118 parcel->WriteInt32(len);
119 parcel->Write(reinterpret_cast<unsigned char*>(raw), len);
120 bundle_free_encoded_rawdata(&raw);
123 void ReadFromParcel(tizen_base::Parcel* parcel) override {
124 parcel->ReadInt32(&pid_);
126 parcel->ReadInt32(&len);
128 std::vector<uint8_t> data(len);
129 parcel->Read(data.data(), data.size());
130 b_ = tizen_base::Bundle(
131 bundle_decode(reinterpret_cast<bundle_raw*>(data.data()), len), false,
138 tizen_base::Bundle b_;
141 class Reply : public tizen_base::Parcelable {
143 explicit Reply(tizen_base::Parcel* parcel) { ReadFromParcel(parcel); }
145 explicit Reply(int result) : result_(result) {}
147 int GetResult() const { return result_; }
149 void WriteToParcel(tizen_base::Parcel* parcel) const override {
150 parcel->WriteInt32(result_);
153 void ReadFromParcel(tizen_base::Parcel* parcel) override {
154 parcel->ReadInt32(&result_);
163 namespace launchpad {
165 LoaderMount::LoaderMount() : Executor(this), launchpad_ppid_(getppid()) {
169 LoaderMount::~LoaderMount() { Dispose(); }
171 void LoaderMount::Prepare() {
172 if (pid_ > 0) return;
175 if (CreatePipe(&pipe_fd) != 0) return;
177 read_socket_.reset(new Socket(pipe_fd[0]));
178 int write_fd = pipe_fd[1];
180 if (CreatePipe(&pipe_fd) != 0) return;
182 int read_fd = pipe_fd[0];
183 write_socket_.reset(new Socket(pipe_fd[1]));
185 _W("read_socket=%d, write_socket=%d",
186 read_socket_->GetFd(), write_socket_->GetFd());
187 pid_ = Executor::Execute();
189 _E("Failed to fork process. errno(%d)", errno);
195 read_socket_.reset(new Socket(read_fd));
196 write_socket_.reset(new Socket(write_fd));
199 void LoaderMount::Dispose() {
200 read_socket_.reset();
201 write_socket_.reset();
203 if (kill(pid_, SIGKILL) == -1)
204 _E("Failed to send kill signal. pid(%d), errno(%d)", pid_, errno);
210 void LoaderMount::HandleSigchld(pid_t pid) {
211 if (pid_ != pid) return;
218 int LoaderMount::Mount(pid_t pid, const AppInfo* app_info) {
219 auto& b = app_info->GetBundle();
220 if (b.GetType(kAulMountGadgetPaths) == BUNDLE_TYPE_NONE &&
221 b.GetType(kAulMountLibDir) == BUNDLE_TYPE_NONE) return 0;
223 tizen_base::Parcel parcel;
224 Request request(pid, b);
225 request.WriteToParcel(&parcel);
227 _W("Send mount request");
228 int ret = Write(parcel);
229 if (ret != 0) return ret;
233 if (ret!= 0) return ret;
235 _W("receive result");
236 Reply reply(&parcel);
237 return reply.GetResult();
240 void LoaderMount::OnExecution() {
242 char** args = LaunchpadArgs::GetInst().GetArgs();
243 size_t length = strlen(args[0]);
244 memset(args[0], '\0', length);
245 snprintf(args[0], length, "/usr/bin/loader-mount");
247 std::vector<int> except_fds = GetExceptableFds();
248 except_fds.push_back(read_socket_->GetFd());
249 except_fds.push_back(write_socket_->GetFd());
250 Util::CloseAllFds(except_fds);
251 int ret = ProcessRequests();
256 int LoaderMount::CreatePipe(int (*pipe_fd)[2]) {
260 if (pipe(*pipe_fd) == -1) {
261 _E("pipe() is failed. errno(%d)", errno);
265 if (fcntl((*pipe_fd)[0], F_SETPIPE_SZ, Socket::kSocketMaxBufferSize) == -1)
266 _E("Failed to set pipe size. pipe_fd(%d), errno(%d)", (*pipe_fd)[0], errno);
268 if (fcntl((*pipe_fd)[1], F_SETPIPE_SZ, Socket::kSocketMaxBufferSize) == -1)
269 _E("Failed to set pipe size. pipe_fd(%d), errno(%d)", (*pipe_fd)[1], errno);
274 int LoaderMount::Write(const tizen_base::Parcel& parcel) {
275 size_t data_size = parcel.GetDataSize();
277 write_socket_->Write(static_cast<void*>(&data_size), sizeof(data_size));
279 _E("Write() is failed. error(%d)", ret);
283 return write_socket_->Write(parcel.GetData(), parcel.GetDataSize());
286 int LoaderMount::Read(tizen_base::Parcel* parcel) {
287 size_t data_size = 0;
289 read_socket_->Read(static_cast<void*>(&data_size), sizeof(data_size));
291 _E("Read() is failed. error(%d)", ret);
295 std::vector<uint8_t> data(data_size);
296 ret = read_socket_->Read(data.data(), data.size());
298 _E("Read() is failed. error(%d)", ret);
302 parcel->Write(data.data(), data.size());
306 int LoaderMount::ProcessRequests() {
307 tizen_base::Parcel parcel;
310 int ret = Read(&parcel);
311 if (ret != 0) continue;
313 _W("Request received");
314 Request request(&parcel);
315 ret = ChangeMountNamespace(request.GetPid());
317 auto& b = request.GetBundle();
318 if (b.GetType(kAulMountGadgetPaths) != BUNDLE_TYPE_NONE)
319 ret |= Util::MountGadgetDirectories(b);
320 if (b.GetType(kAulMountLibDir) != BUNDLE_TYPE_NONE)
321 ret |= Util::MountLibraryDirectories(b);
323 ChangeMountNamespace(launchpad_ppid_);
328 reply.WriteToParcel(&parcel);
335 } // namespace launchpad