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) return 0;
222 tizen_base::Parcel parcel;
223 Request request(pid, b);
224 request.WriteToParcel(&parcel);
226 _W("Send mount request");
227 int ret = Write(parcel);
228 if (ret != 0) return ret;
232 if (ret!= 0) return ret;
234 _W("receive result");
235 Reply reply(&parcel);
236 return reply.GetResult();
239 void LoaderMount::OnExecution() {
241 char** args = LaunchpadArgs::GetInst().GetArgs();
242 size_t length = strlen(args[0]);
243 memset(args[0], '\0', length);
244 snprintf(args[0], length, "/usr/bin/loader-mount");
246 std::vector<int> except_fds = GetExceptableFds();
247 except_fds.push_back(read_socket_->GetFd());
248 except_fds.push_back(write_socket_->GetFd());
249 Util::CloseAllFds(except_fds);
250 int ret = ProcessRequests();
255 int LoaderMount::CreatePipe(int (*pipe_fd)[2]) {
259 if (pipe(*pipe_fd) == -1) {
260 _E("pipe() is failed. errno(%d)", errno);
264 if (fcntl(*pipe_fd[0], F_SETPIPE_SZ, Socket::kSocketMaxBufferSize) == -1)
265 _E("Failed to set pipe size. errno(%d)", errno);
267 if (fcntl(*pipe_fd[1], F_SETPIPE_SZ, Socket::kSocketMaxBufferSize) == -1)
268 _E("Failed to set pipe size. errno(%d)", errno);
273 int LoaderMount::Write(const tizen_base::Parcel& parcel) {
274 size_t data_size = parcel.GetDataSize();
276 write_socket_->Write(static_cast<void*>(&data_size), sizeof(data_size));
278 _E("Write() is failed. error(%d)", ret);
282 return write_socket_->Write(parcel.GetData(), parcel.GetDataSize());
285 int LoaderMount::Read(tizen_base::Parcel* parcel) {
286 size_t data_size = 0;
288 read_socket_->Read(static_cast<void*>(&data_size), sizeof(data_size));
290 _E("Read() is failed. error(%d)", ret);
294 std::vector<uint8_t> data(data_size);
295 ret = read_socket_->Read(data.data(), data.size());
297 _E("Read() is failed. error(%d)", ret);
301 parcel->Write(data.data(), data.size());
305 int LoaderMount::ProcessRequests() {
306 tizen_base::Parcel parcel;
309 int ret = Read(&parcel);
310 if (ret != 0) continue;
312 _W("Request received");
313 Request request(&parcel);
314 ret = ChangeMountNamespace(request.GetPid());
316 ret = Util::MountGadgetDirectories(request.GetBundle());
317 ChangeMountNamespace(launchpad_ppid_);
322 reply.WriteToParcel(&parcel);
329 } // namespace launchpad