1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "SandboxFilterUtil.h"
8 
9 #ifndef ANDROID
10 #  include <linux/ipc.h>
11 #endif
12 #include <linux/net.h>
13 #include <sys/socket.h>
14 #include <sys/syscall.h>
15 #include <unistd.h>
16 
17 #include "mozilla/UniquePtr.h"
18 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
19 
20 // Older kernel headers (mostly Android, but also some older desktop
21 // distributions) are missing some or all of these:
22 #ifndef SYS_ACCEPT4
23 #  define SYS_ACCEPT4 18
24 #endif
25 #ifndef SYS_RECVMMSG
26 #  define SYS_RECVMMSG 19
27 #endif
28 #ifndef SYS_SENDMMSG
29 #  define SYS_SENDMMSG 20
30 #endif
31 
32 using namespace sandbox::bpf_dsl;
33 #define CASES SANDBOX_BPF_DSL_CASES
34 
35 namespace mozilla {
36 
EvaluateSyscall(int aSysno) const37 sandbox::bpf_dsl::ResultExpr SandboxPolicyBase::EvaluateSyscall(
38     int aSysno) const {
39   switch (aSysno) {
40 #ifdef __NR_socketcall
41     case __NR_socketcall: {
42       Arg<int> call(0);
43       UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
44       for (int i = SYS_SOCKET; i <= SYS_SENDMMSG; ++i) {
45         auto thisCase = EvaluateSocketCall(i, false);
46         // Optimize out cases that are equal to the default.
47         if (thisCase) {
48           acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
49         }
50       }
51       return acc->Default(InvalidSyscall());
52     }
53 #  ifndef ANDROID
54     case __NR_ipc: {
55       Arg<int> callAndVersion(0);
56       auto call = callAndVersion & 0xFFFF;
57       UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
58       for (int i = SEMOP; i <= DIPC; ++i) {
59         auto thisCase = EvaluateIpcCall(i);
60         // Optimize out cases that are equal to the default.
61         if (thisCase) {
62           acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
63         }
64       }
65       return acc->Default(InvalidSyscall());
66     }
67 #  endif  // ANDROID
68 #endif    // __NR_socketcall
69           // clang-format off
70 #define DISPATCH_SOCKETCALL(sysnum, socketnum) \
71   case sysnum:                                 \
72     return EvaluateSocketCall(socketnum, true).valueOr(InvalidSyscall())
73 #ifdef __NR_socket
74       DISPATCH_SOCKETCALL(__NR_socket,      SYS_SOCKET);
75       DISPATCH_SOCKETCALL(__NR_bind,        SYS_BIND);
76       DISPATCH_SOCKETCALL(__NR_connect,     SYS_CONNECT);
77       DISPATCH_SOCKETCALL(__NR_listen,      SYS_LISTEN);
78 #ifdef __NR_accept
79       DISPATCH_SOCKETCALL(__NR_accept,      SYS_ACCEPT);
80 #endif
81       DISPATCH_SOCKETCALL(__NR_getsockname, SYS_GETSOCKNAME);
82       DISPATCH_SOCKETCALL(__NR_getpeername, SYS_GETPEERNAME);
83       DISPATCH_SOCKETCALL(__NR_socketpair,  SYS_SOCKETPAIR);
84 #ifdef __NR_send
85       DISPATCH_SOCKETCALL(__NR_send,        SYS_SEND);
86       DISPATCH_SOCKETCALL(__NR_recv,        SYS_RECV);
87 #endif  // __NR_send
88       DISPATCH_SOCKETCALL(__NR_sendto,      SYS_SENDTO);
89       DISPATCH_SOCKETCALL(__NR_recvfrom,    SYS_RECVFROM);
90       DISPATCH_SOCKETCALL(__NR_shutdown,    SYS_SHUTDOWN);
91       DISPATCH_SOCKETCALL(__NR_setsockopt,  SYS_SETSOCKOPT);
92       DISPATCH_SOCKETCALL(__NR_getsockopt,  SYS_GETSOCKOPT);
93       DISPATCH_SOCKETCALL(__NR_sendmsg,     SYS_SENDMSG);
94       DISPATCH_SOCKETCALL(__NR_recvmsg,     SYS_RECVMSG);
95       DISPATCH_SOCKETCALL(__NR_accept4,     SYS_ACCEPT4);
96       DISPATCH_SOCKETCALL(__NR_recvmmsg,    SYS_RECVMMSG);
97       DISPATCH_SOCKETCALL(__NR_sendmmsg,    SYS_SENDMMSG);
98 #endif  // __NR_socket
99 #undef DISPATCH_SOCKETCALL
100 #ifndef __NR_socketcall
101 #ifndef ANDROID
102 #define DISPATCH_SYSVCALL(sysnum, ipcnum) \
103   case sysnum:                            \
104     return EvaluateIpcCall(ipcnum).valueOr(InvalidSyscall())
105       DISPATCH_SYSVCALL(__NR_semop,       SEMOP);
106       DISPATCH_SYSVCALL(__NR_semget,      SEMGET);
107       DISPATCH_SYSVCALL(__NR_semctl,      SEMCTL);
108       DISPATCH_SYSVCALL(__NR_semtimedop,  SEMTIMEDOP);
109       DISPATCH_SYSVCALL(__NR_msgsnd,      MSGSND);
110       DISPATCH_SYSVCALL(__NR_msgrcv,      MSGRCV);
111       DISPATCH_SYSVCALL(__NR_msgget,      MSGGET);
112       DISPATCH_SYSVCALL(__NR_msgctl,      MSGCTL);
113       DISPATCH_SYSVCALL(__NR_shmat,       SHMAT);
114       DISPATCH_SYSVCALL(__NR_shmdt,       SHMDT);
115       DISPATCH_SYSVCALL(__NR_shmget,      SHMGET);
116       DISPATCH_SYSVCALL(__NR_shmctl,      SHMCTL);
117 #undef DISPATCH_SYSVCALL
118 #endif  // ANDROID
119 #endif  // __NR_socketcall
120           // clang-format on
121     default:
122       return InvalidSyscall();
123   }
124 }
125 
HasSeparateSocketCalls()126 /* static */ bool SandboxPolicyBase::HasSeparateSocketCalls() {
127 #ifdef __NR_socket
128   // If there's no socketcall, then obviously there are separate syscalls.
129 #  ifdef __NR_socketcall
130   // This could be memoized, but currently it's called at most once
131   // per process.
132   int fd = syscall(__NR_socket, AF_LOCAL, SOCK_STREAM, 0);
133   if (fd < 0) {
134     MOZ_DIAGNOSTIC_ASSERT(errno == ENOSYS);
135     return false;
136   }
137   close(fd);
138 #  endif  // __NR_socketcall
139   return true;
140 #else   // ifndef __NR_socket
141   return false;
142 #endif  // __NR_socket
143 }
144 
145 }  // namespace mozilla
146