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 <cstring>
22 #include <string>
23 
24 #include <absl/status/statusor.h>
25 
26 #include "host/commands/process_sandboxer/unique_fd.h"
27 
28 namespace cuttlefish::process_sandboxer {
29 
CredentialedUnixServer(UniqueFd fd)30 CredentialedUnixServer::CredentialedUnixServer(UniqueFd fd)
31     : fd_(std::move(fd)) {}
32 
Open(const std::string & path)33 absl::StatusOr<CredentialedUnixServer> CredentialedUnixServer::Open(
34     const std::string& path) {
35   UniqueFd fd(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
36 
37   if (fd.Get() < 0) {
38     return absl::ErrnoToStatus(errno, "`socket` failed");
39   }
40   sockaddr_un socket_name = {
41       .sun_family = AF_UNIX,
42   };
43   std::snprintf(socket_name.sun_path, sizeof(socket_name.sun_path), "%s",
44                 path.c_str());
45   sockaddr* sockname_ptr = reinterpret_cast<sockaddr*>(&socket_name);
46   if (bind(fd.Get(), sockname_ptr, sizeof(socket_name)) < 0) {
47     return absl::ErrnoToStatus(errno, "`bind` failed");
48   }
49 
50   int enable_passcred = 1;
51   if (setsockopt(fd.Get(), SOL_SOCKET, SO_PASSCRED, &enable_passcred,
52                  sizeof(enable_passcred)) < 0) {
53     static constexpr char kErr[] = "`setsockopt(..., SO_PASSCRED, ...)` failed";
54     return absl::ErrnoToStatus(errno, kErr);
55   }
56 
57   if (listen(fd.Get(), 10) < 0) {
58     return absl::ErrnoToStatus(errno, "`listen` failed");
59   }
60 
61   return CredentialedUnixServer(std::move(fd));
62 }
63 
AcceptClient()64 absl::StatusOr<UniqueFd> CredentialedUnixServer::AcceptClient() {
65   UniqueFd client(accept4(fd_.Get(), nullptr, nullptr, SOCK_CLOEXEC));
66   if (client.Get() < 0) {
67     return absl::ErrnoToStatus(errno, "`accept` failed");
68   }
69   return client;
70 }
71 
Fd() const72 int CredentialedUnixServer::Fd() const { return fd_.Get(); }
73 
74 }  // namespace cuttlefish::process_sandboxer
75