Projects such as capsicumizer[1] try to offer oblivious sandboxing for capsicum. To that end, they override libc functions that deal with ambient authority and redirect their implementation. Many of such libc functions offer aliases prefixed on `__sys_`. I've been making use of these aliases successfully so far to get access to the original implementation of many libc functions. So, in my process, I fork and only put the child in a capsicum sandbox. In the non-sandboxed parent, I need access to the original libc implementations. In the child, I use my functions that just forward the request to the parent over an UNIX socket. To achieve that, my libc interposers conditionally call a function pointer or the original implementation. An example: int connect(int s, const struct sockaddr* name, socklen_t namelen) { if (emilua::ambient_authority.connect) { return (*emilua::ambient_authority.connect)( __sys_connect, s, name, namelen); } else { return __sys_connect(s, name, namelen); } } The whole file is just a lot of stubs very similar to the above one: https://gitlab.com/emilua/emilua/-/blob/a8c3e089d641c47c5234746e6f9206d27538be74/src/freebsd/libc_service.cpp Unfortunately, I've had a few problems to perform that for getaddrinfo(). First, I need an alias to access the original getaddrinfo(). This alias doesn't exist (neither on FreeBSD nor on Linux). On Linux, I was able to get access to the original behavior anyway by calling getaddrinfo_a(): static int real_getaddrinfo( const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res ) { struct gaicb cb; std::memset(&cb, 0, sizeof(struct gaicb)); cb.ar_name = node; cb.ar_service = service; cb.ar_request = hints; cb.ar_result = NULL; struct gaicb* cbs = &cb; auto ret = getaddrinfo_a(GAI_WAIT, &cbs, 1, NULL); *res = cb.ar_result; return ret; }; On FreeBSD, getaddrinfo_a() doesn't exist. I need an alias symbol just like other libc functions such as __sys_open(), __sys_connect(), and __sys_bind(). Can we have __sys_getaddrinfo()? The second problem I've had: getaddrinfo() isn't a weak symbol, so builds against static libc will fail. This problem also exists on Linux. On Linux, this is what I've did: [[gnu::weak, gnu::alias("emilua_getaddrinfo")]] int getaddrinfo( const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res); On Linux, it works on builds against dynamic libc. On builds against static libc, the build will still succeed, but then my function won't override the libc's one (that's why the build succeed). On FreeBSD, this approach fails. FreeBSD's dynamic linker seems to take gnu::weak into account so the original (non-weak) getaddrinfo() is chosen anyways. If I remove the gnu::weak attribute, my interposer will be chosen (which is what I want), but then builds against static libc will fail (multiple non-weak definitions for the same symbol). So what I also want is: can the symbol getaddrinfo() be made weak (just like many other libc symbols)? In summary: * Currently getaddrinfo() is a problem for capsicum-based oblivious sandboxing. * Can we have __sys_getaddrinfo() as an alias for getaddrinfo()? * Can the symbol getaddrinfo() be made weak (just like many other libc symbols)? [1] https://github.com/valpackett/capsicumizer
If you have an object a.so that interposes symbol A, the usual way to access the symbol A from beneath a.so is using dlsym(RTLD_NEXT, "A"). To get guaranteed results for symbols exported from libc, like "getaddrinfo", ensure that your interposer is linked to libc.