Accessing Lower-Level Untrusted Servers
Sometimes a client needs to be able to access a server on
an unlabeled system. An unlabeled system is a system that does not run
the Trusted Extensions software. In such a case, you cannot use multilevel
ports because they are restricted to privileged servers that run in the
global zone or in labeled zones.
For example, suppose your browser is running in the INTERNAL zone. You
want to access a web server that runs on a single-level network
that has been assigned the PUBLIC sensitivity label by means of the
tnrhdb database. Such access is not permitted by default. However, you could
write a privileged proxy server to forward the HTTP request to the
PUBLIC web server. The proxy should use a special Trusted Extensions socket
option called SO_MAC_EXEMPT. This socket option permits a request to be sent
to an untrusted lower-level service, and permits the reply from that service
to be returned to the requester.
Note - The use of the SO_MAC_EXEMPT option represents an unprotected downgrade channel and
should be used very carefully. The SO_MAC_EXEMPT option cannot be set unless the
calling process has the PRIV_NET_MAC_AWARE privilege in its effective set. Such a
process must enforce its own data filtering policy to prevent leaking higher-level
data to the lower-level service. For example, the proxy should sanitize URLs
to restrict words from being used as values.
The following code excerpt demonstrates the use of SO_MAC_EXEMPT in a modified
version of the wget command's connect_to_ip() routine in connect.c. The call to
setsockopt() has been added to show how to set the SO_MAC_EXEMPT option.
int
connect_to_ip (const ip_address *ip, int port, const char *print)
{
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss;
int sock;
int on = 1;
/* If PRINT is non-NULL, print the "Connecting to..." line, with
PRINT being the host name we're connecting to. */
if (print)
{
const char *txt_addr = pretty_print_address (ip);
if (print && 0 != strcmp (print, txt_addr))
logprintf (LOG_VERBOSE, _("Connecting to %s|%s|:%d... "),
escnonprint (print), txt_addr, port);
else
logprintf (LOG_VERBOSE, _("Connecting to %s:%d... "), txt_addr, port);
}
/* Store the sockaddr info to SA. */
sockaddr_set_data (sa, ip, port);
/* Create the socket of the family appropriate for the address. */
sock = socket (sa->sa_family, SOCK_STREAM, 0);
if (sock < 0)
goto err;
if (setsockopt (sock, SOL_SOCKET, SO_MAC_EXEMPT, &on, sizeof (on)) == -1) {
perror("setsockopt SO_MAC_EXEMPT");
}
#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY)
if (opt.ipv6_only) {
/* In case of error, we will go on anyway... */
int err = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on));
}
#endif