Serenity Operating System
at master 441 lines 16 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/ByteBuffer.h> 8#include <Kernel/FileSystem/OpenFileDescription.h> 9#include <Kernel/Net/LocalSocket.h> 10#include <Kernel/Process.h> 11#include <Kernel/UnixTypes.h> 12 13namespace Kernel { 14 15#define REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain) \ 16 do { \ 17 if (domain == AF_INET) \ 18 TRY(require_promise(Pledge::inet)); \ 19 else if (domain == AF_LOCAL) \ 20 TRY(require_promise(Pledge::unix)); \ 21 } while (0) 22 23static void setup_socket_fd(Process::OpenFileDescriptions& fds, int fd, NonnullRefPtr<OpenFileDescription> description, int type) 24{ 25 description->set_readable(true); 26 description->set_writable(true); 27 unsigned flags = 0; 28 if (type & SOCK_CLOEXEC) 29 flags |= FD_CLOEXEC; 30 if (type & SOCK_NONBLOCK) 31 description->set_blocking(false); 32 fds[fd].set(*description, flags); 33} 34 35ErrorOr<FlatPtr> Process::sys$socket(int domain, int type, int protocol) 36{ 37 VERIFY_NO_PROCESS_BIG_LOCK(this); 38 REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain); 39 40 auto credentials = this->credentials(); 41 if ((type & SOCK_TYPE_MASK) == SOCK_RAW && !credentials->is_superuser()) 42 return EACCES; 43 44 return m_fds.with_exclusive([&](auto& fds) -> ErrorOr<FlatPtr> { 45 auto fd_allocation = TRY(fds.allocate()); 46 auto socket = TRY(Socket::create(domain, type, protocol)); 47 auto description = TRY(OpenFileDescription::try_create(socket)); 48 setup_socket_fd(fds, fd_allocation.fd, move(description), type); 49 return fd_allocation.fd; 50 }); 51} 52 53ErrorOr<FlatPtr> Process::sys$bind(int sockfd, Userspace<sockaddr const*> address, socklen_t address_length) 54{ 55 VERIFY_NO_PROCESS_BIG_LOCK(this); 56 auto description = TRY(open_file_description(sockfd)); 57 if (!description->is_socket()) 58 return ENOTSOCK; 59 auto& socket = *description->socket(); 60 REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); 61 TRY(socket.bind(credentials(), address, address_length)); 62 return 0; 63} 64 65ErrorOr<FlatPtr> Process::sys$listen(int sockfd, int backlog) 66{ 67 VERIFY_NO_PROCESS_BIG_LOCK(this); 68 if (backlog < 0) 69 return EINVAL; 70 auto description = TRY(open_file_description(sockfd)); 71 if (!description->is_socket()) 72 return ENOTSOCK; 73 auto& socket = *description->socket(); 74 REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); 75 if (socket.is_connected()) 76 return EINVAL; 77 TRY(socket.listen(backlog)); 78 return 0; 79} 80 81ErrorOr<FlatPtr> Process::sys$accept4(Userspace<Syscall::SC_accept4_params const*> user_params) 82{ 83 VERIFY_NO_PROCESS_BIG_LOCK(this); 84 TRY(require_promise(Pledge::accept)); 85 auto params = TRY(copy_typed_from_user(user_params)); 86 87 int accepting_socket_fd = params.sockfd; 88 Userspace<sockaddr*> user_address((FlatPtr)params.addr); 89 Userspace<socklen_t*> user_address_size((FlatPtr)params.addrlen); 90 int flags = params.flags; 91 92 socklen_t address_size = 0; 93 if (user_address) 94 TRY(copy_from_user(&address_size, static_ptr_cast<socklen_t const*>(user_address_size))); 95 96 ScopedDescriptionAllocation fd_allocation; 97 RefPtr<OpenFileDescription> accepting_socket_description; 98 99 TRY(m_fds.with_exclusive([&](auto& fds) -> ErrorOr<void> { 100 fd_allocation = TRY(fds.allocate()); 101 accepting_socket_description = TRY(fds.open_file_description(accepting_socket_fd)); 102 return {}; 103 })); 104 if (!accepting_socket_description->is_socket()) 105 return ENOTSOCK; 106 auto& socket = *accepting_socket_description->socket(); 107 108 LockRefPtr<Socket> accepted_socket; 109 for (;;) { 110 accepted_socket = socket.accept(); 111 if (accepted_socket) 112 break; 113 if (!accepting_socket_description->is_blocking()) 114 return EAGAIN; 115 auto unblock_flags = Thread::FileBlocker::BlockFlags::None; 116 if (Thread::current()->block<Thread::AcceptBlocker>({}, *accepting_socket_description, unblock_flags).was_interrupted()) 117 return EINTR; 118 } 119 120 if (user_address) { 121 sockaddr_un address_buffer {}; 122 address_size = min(sizeof(sockaddr_un), static_cast<size_t>(address_size)); 123 accepted_socket->get_peer_address((sockaddr*)&address_buffer, &address_size); 124 TRY(copy_to_user(user_address, &address_buffer, address_size)); 125 TRY(copy_to_user(user_address_size, &address_size)); 126 } 127 128 auto accepted_socket_description = TRY(OpenFileDescription::try_create(*accepted_socket)); 129 130 accepted_socket_description->set_readable(true); 131 accepted_socket_description->set_writable(true); 132 if (flags & SOCK_NONBLOCK) 133 accepted_socket_description->set_blocking(false); 134 int fd_flags = 0; 135 if (flags & SOCK_CLOEXEC) 136 fd_flags |= FD_CLOEXEC; 137 138 TRY(m_fds.with_exclusive([&](auto& fds) -> ErrorOr<void> { 139 fds[fd_allocation.fd].set(move(accepted_socket_description), fd_flags); 140 return {}; 141 })); 142 143 // NOTE: Moving this state to Completed is what causes connect() to unblock on the client side. 144 accepted_socket->set_setup_state(Socket::SetupState::Completed); 145 return fd_allocation.fd; 146} 147 148ErrorOr<FlatPtr> Process::sys$connect(int sockfd, Userspace<sockaddr const*> user_address, socklen_t user_address_size) 149{ 150 VERIFY_NO_PROCESS_BIG_LOCK(this); 151 152 auto description = TRY(open_file_description(sockfd)); 153 if (!description->is_socket()) 154 return ENOTSOCK; 155 auto& socket = *description->socket(); 156 REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); 157 TRY(socket.connect(credentials(), *description, user_address, user_address_size)); 158 return 0; 159} 160 161ErrorOr<FlatPtr> Process::sys$shutdown(int sockfd, int how) 162{ 163 VERIFY_NO_PROCESS_BIG_LOCK(this); 164 TRY(require_promise(Pledge::stdio)); 165 if (how != SHUT_RD && how != SHUT_WR && how != SHUT_RDWR) 166 return EINVAL; 167 auto description = TRY(open_file_description(sockfd)); 168 if (!description->is_socket()) 169 return ENOTSOCK; 170 auto& socket = *description->socket(); 171 REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); 172 TRY(socket.shutdown(how)); 173 return 0; 174} 175 176ErrorOr<FlatPtr> Process::sys$sendmsg(int sockfd, Userspace<const struct msghdr*> user_msg, int flags) 177{ 178 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 179 TRY(require_promise(Pledge::stdio)); 180 auto msg = TRY(copy_typed_from_user(user_msg)); 181 182 if (msg.msg_iovlen != 1) 183 return ENOTSUP; // FIXME: Support this :) 184 Vector<iovec, 1> iovs; 185 TRY(iovs.try_resize(msg.msg_iovlen)); 186 TRY(copy_n_from_user(iovs.data(), msg.msg_iov, msg.msg_iovlen)); 187 if (iovs[0].iov_len > NumericLimits<ssize_t>::max()) 188 return EINVAL; 189 190 Userspace<sockaddr const*> user_addr((FlatPtr)msg.msg_name); 191 socklen_t addr_length = msg.msg_namelen; 192 193 auto description = TRY(open_file_description(sockfd)); 194 if (!description->is_socket()) 195 return ENOTSOCK; 196 197 auto& socket = *description->socket(); 198 if (socket.is_shut_down_for_writing()) { 199 if ((flags & MSG_NOSIGNAL) == 0) 200 Thread::current()->send_signal(SIGPIPE, &Process::current()); 201 return EPIPE; 202 } 203 204 if (msg.msg_controllen > 0) { 205 // Handle command messages. 206 auto cmsg_buffer = TRY(ByteBuffer::create_uninitialized(msg.msg_controllen)); 207 TRY(copy_from_user(cmsg_buffer.data(), msg.msg_control, msg.msg_controllen)); 208 msg.msg_control = cmsg_buffer.data(); 209 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 210 if (socket.is_local() && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { 211 auto& local_socket = static_cast<LocalSocket&>(socket); 212 int* fds = (int*)CMSG_DATA(cmsg); 213 size_t nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) / sizeof(int); 214 for (size_t i = 0; i < nfds; ++i) { 215 TRY(local_socket.sendfd(*description, TRY(open_file_description(fds[i])))); 216 } 217 } 218 } 219 } 220 221 auto data_buffer = TRY(UserOrKernelBuffer::for_user_buffer((u8*)iovs[0].iov_base, iovs[0].iov_len)); 222 223 while (true) { 224 while (!description->can_write()) { 225 if (!description->is_blocking()) { 226 return EAGAIN; 227 } 228 229 auto unblock_flags = Thread::FileBlocker::BlockFlags::None; 230 if (Thread::current()->block<Thread::WriteBlocker>({}, *description, unblock_flags).was_interrupted()) { 231 return EINTR; 232 } 233 // TODO: handle exceptions in unblock_flags 234 } 235 236 auto bytes_sent_or_error = socket.sendto(*description, data_buffer, iovs[0].iov_len, flags, user_addr, addr_length); 237 if (bytes_sent_or_error.is_error()) { 238 if ((flags & MSG_NOSIGNAL) == 0 && bytes_sent_or_error.error().code() == EPIPE) 239 Thread::current()->send_signal(SIGPIPE, &Process::current()); 240 return bytes_sent_or_error.release_error(); 241 } 242 243 auto bytes_sent = bytes_sent_or_error.release_value(); 244 if (bytes_sent > 0) 245 return bytes_sent; 246 } 247} 248 249ErrorOr<FlatPtr> Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user_msg, int flags) 250{ 251 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 252 TRY(require_promise(Pledge::stdio)); 253 254 struct msghdr msg; 255 TRY(copy_from_user(&msg, user_msg)); 256 257 if (msg.msg_iovlen != 1) 258 return ENOTSUP; // FIXME: Support this :) 259 Vector<iovec, 1> iovs; 260 TRY(iovs.try_resize(msg.msg_iovlen)); 261 TRY(copy_n_from_user(iovs.data(), msg.msg_iov, msg.msg_iovlen)); 262 263 Userspace<sockaddr*> user_addr((FlatPtr)msg.msg_name); 264 Userspace<socklen_t*> user_addr_length(msg.msg_name ? (FlatPtr)&user_msg.unsafe_userspace_ptr()->msg_namelen : 0); 265 266 auto description = TRY(open_file_description(sockfd)); 267 if (!description->is_socket()) 268 return ENOTSOCK; 269 auto& socket = *description->socket(); 270 271 if (socket.is_shut_down_for_reading()) 272 return 0; 273 274 auto data_buffer = TRY(UserOrKernelBuffer::for_user_buffer((u8*)iovs[0].iov_base, iovs[0].iov_len)); 275 Time timestamp {}; 276 bool blocking = (flags & MSG_DONTWAIT) ? false : description->is_blocking(); 277 auto result = socket.recvfrom(*description, data_buffer, iovs[0].iov_len, flags, user_addr, user_addr_length, timestamp, blocking); 278 279 if (result.is_error()) 280 return result.release_error(); 281 282 int msg_flags = 0; 283 284 if (result.value() > iovs[0].iov_len) { 285 VERIFY(socket.type() != SOCK_STREAM); 286 msg_flags |= MSG_TRUNC; 287 } 288 289 socklen_t current_cmsg_len = 0; 290 auto try_add_cmsg = [&](int level, int type, void const* data, socklen_t len) -> ErrorOr<bool> { 291 if (current_cmsg_len + len > msg.msg_controllen) { 292 msg_flags |= MSG_CTRUNC; 293 return false; 294 } 295 296 cmsghdr cmsg = { (socklen_t)CMSG_LEN(len), level, type }; 297 cmsghdr* target = (cmsghdr*)(((char*)msg.msg_control) + current_cmsg_len); 298 TRY(copy_to_user(target, &cmsg)); 299 TRY(copy_to_user(CMSG_DATA(target), data, len)); 300 current_cmsg_len += CMSG_ALIGN(cmsg.cmsg_len); 301 return true; 302 }; 303 304 if (socket.wants_timestamp()) { 305 timeval time = timestamp.to_timeval(); 306 TRY(try_add_cmsg(SOL_SOCKET, SCM_TIMESTAMP, &time, sizeof(time))); 307 } 308 309 int space_for_fds = (msg.msg_controllen - current_cmsg_len - sizeof(struct cmsghdr)) / sizeof(int); 310 if (space_for_fds > 0 && socket.is_local()) { 311 auto& local_socket = static_cast<LocalSocket&>(socket); 312 auto descriptions = TRY(local_socket.recvfds(description, space_for_fds)); 313 Vector<int> fdnums; 314 for (auto& description : descriptions) { 315 auto fd_allocation = TRY(m_fds.with_exclusive([](auto& fds) { return fds.allocate(); })); 316 m_fds.with_exclusive([&](auto& fds) { fds[fd_allocation.fd].set(*description, 0); }); 317 fdnums.append(fd_allocation.fd); 318 } 319 TRY(try_add_cmsg(SOL_SOCKET, SCM_RIGHTS, fdnums.data(), fdnums.size() * sizeof(int))); 320 } 321 322 TRY(copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_controllen, &current_cmsg_len)); 323 324 TRY(copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_flags, &msg_flags)); 325 return result.value(); 326} 327 328template<bool sockname, typename Params> 329ErrorOr<void> Process::get_sock_or_peer_name(Params const& params) 330{ 331 socklen_t addrlen_value; 332 TRY(copy_from_user(&addrlen_value, params.addrlen, sizeof(socklen_t))); 333 334 if (addrlen_value <= 0) 335 return EINVAL; 336 337 auto description = TRY(open_file_description(params.sockfd)); 338 if (!description->is_socket()) 339 return ENOTSOCK; 340 341 auto& socket = *description->socket(); 342 REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); 343 344 sockaddr_un address_buffer {}; 345 addrlen_value = min(sizeof(sockaddr_un), static_cast<size_t>(addrlen_value)); 346 if constexpr (sockname) 347 socket.get_local_address((sockaddr*)&address_buffer, &addrlen_value); 348 else 349 socket.get_peer_address((sockaddr*)&address_buffer, &addrlen_value); 350 TRY(copy_to_user(params.addr, &address_buffer, addrlen_value)); 351 return copy_to_user(params.addrlen, &addrlen_value); 352} 353 354ErrorOr<FlatPtr> Process::sys$getsockname(Userspace<Syscall::SC_getsockname_params const*> user_params) 355{ 356 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 357 auto params = TRY(copy_typed_from_user(user_params)); 358 TRY(get_sock_or_peer_name<true>(params)); 359 return 0; 360} 361 362ErrorOr<FlatPtr> Process::sys$getpeername(Userspace<Syscall::SC_getpeername_params const*> user_params) 363{ 364 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 365 auto params = TRY(copy_typed_from_user(user_params)); 366 TRY(get_sock_or_peer_name<false>(params)); 367 return 0; 368} 369 370ErrorOr<FlatPtr> Process::sys$getsockopt(Userspace<Syscall::SC_getsockopt_params const*> user_params) 371{ 372 VERIFY_NO_PROCESS_BIG_LOCK(this); 373 auto params = TRY(copy_typed_from_user(user_params)); 374 375 int sockfd = params.sockfd; 376 int level = params.level; 377 int option = params.option; 378 Userspace<void*> user_value((FlatPtr)params.value); 379 Userspace<socklen_t*> user_value_size((FlatPtr)params.value_size); 380 381 socklen_t value_size; 382 TRY(copy_from_user(&value_size, params.value_size, sizeof(socklen_t))); 383 384 auto description = TRY(open_file_description(sockfd)); 385 if (!description->is_socket()) 386 return ENOTSOCK; 387 auto& socket = *description->socket(); 388 REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); 389 TRY(socket.getsockopt(*description, level, option, user_value, user_value_size)); 390 return 0; 391} 392 393ErrorOr<FlatPtr> Process::sys$setsockopt(Userspace<Syscall::SC_setsockopt_params const*> user_params) 394{ 395 VERIFY_NO_PROCESS_BIG_LOCK(this); 396 auto params = TRY(copy_typed_from_user(user_params)); 397 398 Userspace<void const*> user_value((FlatPtr)params.value); 399 auto description = TRY(open_file_description(params.sockfd)); 400 if (!description->is_socket()) 401 return ENOTSOCK; 402 auto& socket = *description->socket(); 403 REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); 404 TRY(socket.setsockopt(params.level, params.option, user_value, params.value_size)); 405 return 0; 406} 407 408ErrorOr<FlatPtr> Process::sys$socketpair(Userspace<Syscall::SC_socketpair_params const*> user_params) 409{ 410 VERIFY_NO_PROCESS_BIG_LOCK(this); 411 auto params = TRY(copy_typed_from_user(user_params)); 412 413 if (params.domain != AF_LOCAL) 414 return EINVAL; 415 416 if (params.protocol != 0 && params.protocol != PF_LOCAL) 417 return EINVAL; 418 419 auto pair = TRY(LocalSocket::try_create_connected_pair(params.type & SOCK_TYPE_MASK)); 420 421 return m_fds.with_exclusive([&](auto& fds) -> ErrorOr<FlatPtr> { 422 auto fd_allocation0 = TRY(fds.allocate()); 423 auto fd_allocation1 = TRY(fds.allocate()); 424 425 int allocated_fds[2]; 426 allocated_fds[0] = fd_allocation0.fd; 427 allocated_fds[1] = fd_allocation1.fd; 428 setup_socket_fd(fds, allocated_fds[0], pair.description0, params.type); 429 setup_socket_fd(fds, allocated_fds[1], pair.description1, params.type); 430 431 if (copy_to_user(params.sv, allocated_fds, sizeof(allocated_fds)).is_error()) { 432 // Avoid leaking both file descriptors on error. 433 fds[allocated_fds[0]] = {}; 434 fds[allocated_fds[1]] = {}; 435 return EFAULT; 436 } 437 return 0; 438 }); 439} 440 441}