diff options
author | bptato <nincsnevem662@gmail.com> | 2024-03-28 01:36:29 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-03-28 01:36:29 +0100 |
commit | b530ccc899a8cc8c63bad29abe1e479eb999b167 (patch) | |
tree | 07062947dfda3ac4356b0ce26de1cbe4e4c87ebd /src/io | |
parent | 52c415762fda7b9369ed4cf88783a6639574e3ea (diff) | |
download | chawan-b530ccc899a8cc8c63bad29abe1e479eb999b167.tar.gz |
Add capsicum support
It's the sandboxing system of FreeBSD. Quite pleasant to work with. (Just trying to figure out the basics with this one before tackling the abomination that is seccomp.) Indeed, the only non-trivial part was getting newSelector to work with Capsicum. Long story short it doesn't, so we use an ugly pointer cast + assignment. But even that is stdlib's "fault", not Capsicum's. This also gets rid of that ugly SocketPath global.
Diffstat (limited to 'src/io')
-rw-r--r-- | src/io/bind_unix.c | 16 | ||||
-rw-r--r-- | src/io/connect_unix.c | 16 | ||||
-rw-r--r-- | src/io/serversocket.nim | 38 | ||||
-rw-r--r-- | src/io/socketstream.nim | 30 |
4 files changed, 82 insertions, 18 deletions
diff --git a/src/io/bind_unix.c b/src/io/bind_unix.c index 02e86eed..398c2c9e 100644 --- a/src/io/bind_unix.c +++ b/src/io/bind_unix.c @@ -1,4 +1,5 @@ #include <stddef.h> +#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> @@ -12,3 +13,18 @@ int bind_unix_from_c(int socket, const char *path, int pathlen) memcpy(sa.sun_path, path, pathlen + 1); return bind(socket, (struct sockaddr *)&sa, len); } + +#ifdef __FreeBSD__ +#include <fcntl.h> + +int bindat_unix_from_c(int fd, int socket, const char *path, int pathlen) +{ + struct sockaddr_un sa = { + .sun_family = AF_UNIX + }; + int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1; + + memcpy(sa.sun_path, path, pathlen + 1); + return bindat(fd, socket, (struct sockaddr *)&sa, len); +} +#endif diff --git a/src/io/connect_unix.c b/src/io/connect_unix.c index 26b3d6db..41faab11 100644 --- a/src/io/connect_unix.c +++ b/src/io/connect_unix.c @@ -1,4 +1,5 @@ #include <stddef.h> +#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> @@ -12,3 +13,18 @@ int connect_unix_from_c(int socket, const char *path, int pathlen) memcpy(sa.sun_path, path, pathlen + 1); return connect(socket, (struct sockaddr *)&sa, len); } + +#ifdef __FreeBSD__ +#include <fcntl.h> + +int connectat_unix_from_c(int fd, int socket, const char *path, int pathlen) +{ + struct sockaddr_un sa = { + .sun_family = AF_UNIX + }; + int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1; + + memcpy(sa.sun_path, path, pathlen + 1); + return connectat(fd, socket, (struct sockaddr *)&sa, len); +} +#endif diff --git a/src/io/serversocket.nim b/src/io/serversocket.nim index a6acc555..ea5bc97d 100644 --- a/src/io/serversocket.nim +++ b/src/io/serversocket.nim @@ -9,26 +9,44 @@ type ServerSocket* = object sock*: Socket path*: string -var SocketDirectory* = "/tmp/cha" const SocketPathPrefix = "cha_sock_" -proc getSocketPath*(pid: int): string = - SocketDirectory / SocketPathPrefix & $pid +proc getSocketName*(pid: int): string = + SocketPathPrefix & $pid + +proc getSocketPath*(socketDir: string; pid: int): string = + socketDir / getSocketName(pid) # The way stdlib does bindUnix is utterly broken at least on FreeBSD. # It seems that just writing it in C is the easiest solution. {.compile: "bind_unix.c".} -proc bind_unix_from_c(fd: cint, path: cstring, pathlen: cint): cint {.importc.} +proc bind_unix_from_c(fd: cint; path: cstring; pathlen: cint): cint + {.importc.} + +when defined(freebsd): + # capsicum stuff + proc unlinkat(dfd: cint; path: cstring; flag: cint): cint + {.importc, header: "<unistd.h>".} + proc bindat_unix_from_c(dfd, sock: cint; path: cstring; pathlen: cint): cint + {.importc.} -proc initServerSocket*(pid: int; blocking = true): ServerSocket = - createDir(SocketDirectory) +proc initServerSocket*(sockDir: string; sockDirFd, pid: int; blocking = true): + ServerSocket = let sock = newSocket(Domain.AF_UNIX, SockType.SOCK_STREAM, Protocol.IPPROTO_IP, buffered = false) if not blocking: sock.getFd().setBlocking(false) - let path = getSocketPath(pid) - discard unlink(cstring(path)) - if bind_unix_from_c(cint(sock.getFd()), cstring(path), cint(path.len)) != 0: - raiseOSError(osLastError()) + let path = getSocketPath(sockDir, pid) + if sockDirFd == -1: + discard unlink(cstring(path)) + if bind_unix_from_c(cint(sock.getFd()), cstring(path), cint(path.len)) != 0: + raiseOSError(osLastError()) + else: + when defined(freebsd): + let name = getSocketName(pid) + discard unlinkat(cint(sockDirFd), cstring(name), 0) + if bindat_unix_from_c(cint(sockDirFd), cint(sock.getFd()), cstring(name), + cint(name.len)) != 0: + raiseOSError(osLastError()) listen(sock) return ServerSocket(sock: sock, path: path) diff --git a/src/io/socketstream.nim b/src/io/socketstream.nim index 3c8e6fa6..32aff96d 100644 --- a/src/io/socketstream.nim +++ b/src/io/socketstream.nim @@ -58,27 +58,41 @@ method sclose*(s: SocketStream) = # see serversocket.nim for an explanation {.compile: "connect_unix.c".} -proc connect_unix_from_c(fd: cint, path: cstring, pathlen: cint): cint +proc connect_unix_from_c(fd: cint; path: cstring; pathlen: cint): cint {.importc.} +when defined(freebsd): + # for FreeBSD/capsicum + proc connectat_unix_from_c(baseFd, sockFd: cint; rel_path: cstring; + rel_pathlen: cint): cint {.importc.} -proc connectSocketStream*(path: string; blocking = true): SocketStream = +proc connectAtSocketStream0(socketDir: string; baseFd, pid: int; + blocking = true): SocketStream = let sock = newSocket(Domain.AF_UNIX, SockType.SOCK_STREAM, Protocol.IPPROTO_IP, buffered = false) if not blocking: sock.getFd().setBlocking(false) - if connect_unix_from_c(cint(sock.getFd()), cstring(path), - cint(path.len)) != 0: - raiseOSError(osLastError()) + let path = getSocketPath(socketDir, pid) + if baseFd == -1: + if connect_unix_from_c(cint(sock.getFd()), cstring(path), + cint(path.len)) != 0: + raiseOSError(osLastError()) + else: + when defined(freebsd): + doAssert baseFd != -1 + let name = getSocketName(pid) + if connectat_unix_from_c(cint(baseFd), cint(sock.getFd()), cstring(name), + cint(name.len)) != 0: + raiseOSError(osLastError()) return SocketStream( source: sock, fd: cint(sock.getFd()), blocking: blocking ) -proc connectSocketStream*(pid: int; blocking = true): - SocketStream = +proc connectSocketStream*(socketDir: string; baseFd, pid: int; + blocking = true): SocketStream = try: - return connectSocketStream(getSocketPath(pid), blocking) + return connectAtSocketStream0(socketDir, baseFd, pid, blocking) except OSError: return nil |