Communication Endpoints
The Trusted Extensions software supports IPC over communication endpoints by using the
following socket-based mechanisms:
This section summarizes the socket communication mechanisms and the related security policy.
See the appropriate man page for specific information about the security policy
and applicable privileges.
In addition to these mechanisms, Trusted Extensions also supports multilevel ports. See
Multilevel Port Information.
Berkeley Sockets and TLI
The Trusted Extensions software supports network communication by using Berkeley sockets and
the TLI over single-level ports and multilevel ports. The AF_UNIX family of
system calls establishes interprocess connections in the same labeled zone by means
of a special file that is specified by using a fully resolved
path name. The AF_INET family of system calls establishes interprocess connections across
the network by using IP addresses and port numbers.
AF_UNIX Family
In the AF_UNIX family of interfaces, only one server bind can be
established to a single special file, which is a UNIX®
domain socket.
The AF_UNIX family does not support multilevel ports.
Like UNIX domain sockets, doors and named pipes use special files for
rendezvous purposes.
The default policy for all Trusted Extensions IPC mechanisms is that they
are all constrained to work within a single labeled zone. The following
are exceptions to this policy:
The global zone administrator can make a named pipe (FIFO) available to a zone whose label dominates the owning zone. The administrator does this by loopback-mounting the directory that contains the FIFO.
A process that runs in the higher-level zone is permitted to open the FIFO in read-only mode. A process is not permitted to use the FIFO to write down.
A labeled zone can access global zone door servers if the global zone rendezvous file is loopback-mounted into the labeled zone.
The Trusted Extensions software depends on the door policy to support the labeld and nscd doors-based services. The default zonecfg template specifies that the /var/tsol/doors directory in the global zone is loopback-mounted into each labeled zone.
AF_INET Family
In the AF_INET family, the process can establish a single-label connection or
a multilabel connection to privileged or unprivileged port numbers. To connect to
privileged port numbers, the net_priv_addr privilege is required. If a multilevel port
connection is sought, the net_bindmlp privilege is also required.
The server process needs the net_bindmlp privilege in its effective set for
a multilevel port connection. If a single-level port connection is made instead,
the server process needs mandatory read-equal access to the socket, and the
client process needs mandatory write-equal access. Both processes need mandatory and discretionary
access to the file. If access to the file is denied, any
process that is denied access needs the appropriate file privilege in its
effective set to gain access.
The following code example shows how a multilevel server can obtain the
labels of its connected clients. The standard C library function getpeerucred() obtains
a connected socket or a STREAM peer's credentials. In the context of
Trusted Extensions, when the listening socket of a multilevel port server accepts
a connection request, the first argument is typically a client socket file
descriptor. The Trusted Extensions application uses the getpeerucred() function in exactly the
same way a normal application program does. The Trusted Extensions addition is
ucred_getlabel(), which returns a label. For more information, see the ucred_get(3C) man
page.
/*
* This example shows how a multilevel server can
* get the label of its connected clients.
*/
void
remote_client_label(int svr_fd)
{
ucred_t *uc = NULL;
m_label_t *sl;
struct sockaddr_in6 remote_addr;
bzero((void *)&remote_addr, sizeof (struct sockaddr_in6));
while (1) {
int clnt_fd;
clnt_fd = accept(svr_fd, (struct sockaddr *)&remote_addr,
&sizeof (struct sockaddr_in6));
/*
* Get client attributes from the socket
*/
if (getpeerucred(clnt_fd, &uc) == -1) {
return;
}
/*
* Extract individual fields from the ucred structure
*/
sl = ucred_getlabel(uc);
/*
* Security label usage here
* .....
*/
ucred_free(uc);
close(clnt_fd);
}
}
RPC Mechanism
The Trusted Extensions software provides multilevel port support for remote procedure calls
(RPCs). A client application can send inquiries to a server's PORTMAPPER service
(port 111) whether or not a particular service is available. If the
requested service is registered with the PORTMAPPER on the server, the server
will dynamically allocate an anonymous port and return this port to the
client.
On a Solaris Trusted Extensions system, an administrator can configure the PORTMAPPER
port as a multilevel port so that multiple single-level applications can use
this service. If the PORTMAPPER port is made a multilevel port, all
anonymous ports allocated by the PORTMAPPER service are also multilevel ports. There
are no other programmable interfaces or administrative interfaces to control anonymous multilevel
ports.
Using Multilevel Ports With UDP
The PORTMAPPER service described in the previous section is implemented by using
UDP. Unlike TCP, UDP sockets are not connection oriented, so some ambiguity
might arise about which credentials to use when replying to a client
on a multilevel port. Therefore, the client's request socket must be explicitly
associated with the server's reply packet. To make this association, use the
SO_RECVUCRED socket option.
When SO_RECVUCRED is set on a UDP socket, the kernel UDP module
can pass a label in a ucred structure as ancillary data to
an application. The level and type values of the ucred are SOL_SOCKET
and SCM_UCRED, respectively.
An application can handle this ucred structure in one of these ways:
The following code excerpt shows the reuse case.
/*
* Find the SCM_UCRED in src and place a pointer to that
* option alone in dest. Note that these two 'netbuf'
* structures might be the same one, so the code has to
* be careful about referring to src after changing dest.
*/
static void
extract_cred(const struct netbuf *src, struct netbuf *dest)
{
char *cp = src->buf;
unsigned int len = src->len;
const struct T_opthdr *opt;
unsigned int olen;
while (len >= sizeof (*opt)) {
/* LINTED: pointer alignment */
opt = (const struct T_opthdr *)cp;
olen = opt->len;
if (olen > len || olen < sizeof (*opt) ||
!IS_P2ALIGNED(olen, sizeof (t_uscalar_t)))
break;
if (opt->level == SOL_SOCKET &&
opt->name == SCM_UCRED) {
dest->buf = cp;
dest->len = olen;
return;
}
cp += olen;
len -= olen;
}
dest->len = 0;
}
The following code excerpt shows how to access the user credential from
the receiving buffer:
void
examine_udp_label()
{
struct msghdr recv_msg;
struct cmsghdr *cmsgp;
char message[MAX_MSGLEN+1];
char inmsg[MAX_MSGLEN+1];
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_RECVUCRED, (void *)&on,
sizeof (int));
[...]
while (1) {
if (recvmsg(sockfd, &recv_msg, 0) < 0) {
(void) fprintf(stderr, "recvmsg_errno: %d\n", errno);
exit(1);
}
/*
* Check ucred in ancillary data
*/
ucred = NULL;
for (cmsgp = CMSG_FIRSTHDR(&recv_msg); cmsgp;
cmsgp = CMSG_NXTHDR(&recv_msg, cmsgp)) {
if (cmsgp->cmsg_level == SOL_SOCKET &&
cmsgp->cmsg_type == SCM_UCRED) {
ucred = (ucred_t *)CMSG_DATA(cmsgp);
break;
}
if (ucred == NULL) {
(void) sprintf(&message[0],
"No ucred info in ancillary data with UDP");
} else {
/*
* You might want to extract the label from the
* ucred by using ucred_getlabel(3C) here.
*/
}
}
[...]
if (message != NULL)
(void) strlcpy(&inmsg[0], message, MAX_MSGLEN);
/*
* Use the received message so that it will contain
* the correct label
*/
iov.iov_len = strlen(inmsg);
ret = sendmsg(sockfd, &recv_msg, 0);
}
}