1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16 #include "host/commands/process_sandboxer/credentialed_unix_server.h"
17
18 #include <sys/socket.h>
19 #include <sys/un.h>
20
21 #include <cerrno>
22 #include <cstdio>
23 #include <string>
24 #include <utility>
25
26 #include <absl/status/status.h>
27 #include <absl/status/statusor.h>
28 #include <sandboxed_api/util/fileops.h>
29
30 namespace cuttlefish::process_sandboxer {
31
32 using sapi::file_util::fileops::FDCloser;
33
CredentialedUnixServer(FDCloser fd)34 CredentialedUnixServer::CredentialedUnixServer(FDCloser fd)
35 : fd_(std::move(fd)) {}
36
Open(const std::string & path)37 absl::StatusOr<CredentialedUnixServer> CredentialedUnixServer::Open(
38 const std::string& path) {
39 FDCloser fd(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
40
41 if (fd.get() < 0) {
42 return absl::ErrnoToStatus(errno, "`socket` failed");
43 }
44 sockaddr_un socket_name = {
45 .sun_family = AF_UNIX,
46 };
47 std::snprintf(socket_name.sun_path, sizeof(socket_name.sun_path), "%s",
48 path.c_str());
49 sockaddr* sockname_ptr = reinterpret_cast<sockaddr*>(&socket_name);
50 if (bind(fd.get(), sockname_ptr, sizeof(socket_name)) < 0) {
51 return absl::ErrnoToStatus(errno, "`bind` failed");
52 }
53
54 int enable_passcred = 1;
55 if (setsockopt(fd.get(), SOL_SOCKET, SO_PASSCRED, &enable_passcred,
56 sizeof(enable_passcred)) < 0) {
57 static constexpr char kErr[] = "`setsockopt(..., SO_PASSCRED, ...)` failed";
58 return absl::ErrnoToStatus(errno, kErr);
59 }
60
61 if (listen(fd.get(), 10) < 0) {
62 return absl::ErrnoToStatus(errno, "`listen` failed");
63 }
64
65 return CredentialedUnixServer(std::move(fd));
66 }
67
AcceptClient()68 absl::StatusOr<FDCloser> CredentialedUnixServer::AcceptClient() {
69 FDCloser client(accept4(fd_.get(), nullptr, nullptr, SOCK_CLOEXEC));
70 if (client.get() < 0) {
71 return absl::ErrnoToStatus(errno, "`accept` failed");
72 }
73 return client;
74 }
75
Fd() const76 int CredentialedUnixServer::Fd() const { return fd_.get(); }
77
78 } // namespace cuttlefish::process_sandboxer
79