labelsys.c revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
static tsol_tpc_t *tpc_unlab;
/*
* tnrhc_table and tnrhc_table_v6 are similar to the IP forwarding tables
* in organization and search. The tnrhc_table[_v6] is an array of 33/129
* pointers to the 33/129 tnrhc tables indexed by the prefix length.
* A largest prefix match search is done by find_rhc_v[46] and it walks the
* tables from the most specific to the least specific table. Table 0
* corresponds to the single entry for 0.0.0.0/0 or ::0/0.
*/
static void tsol_create_i_tmpls(void);
static void tsol_create_i_tnrh(const tnaddr_t *);
/* List of MLPs on valid on shared addresses */
static tsol_mlp_list_t shared_mlps;
/*
* Convert length for a mask to the mask.
*/
static ipaddr_t
{
}
/*
* Convert a prefix length to the mask for that prefix.
* Returns the argument bitmask.
*/
static void
{
while (plen >= 32) {
*ptr++ = 0xffffffffU;
plen -= 32;
}
if (plen > 0)
*ptr++ = 0;
}
{
int i;
return (B_FALSE);
}
for (i = 0; i < TNRHC_SIZE; i++) {
NULL, MUTEX_DEFAULT, 0);
}
}
return (B_TRUE);
}
void
tcache_init(void)
{
/*
* Note: unable to use mod_hash_create_strhash here, since it's
* assymetric. It assumes that the user has allocated exactly
* strlen(key) + 1 bytes for the key when inserted, and attempts to
* kmem_free that memory on a delete.
*/
/* label_init always called before tcache_init */
/* Initialize the zeroth table prior to loading the 0.0.0.0 entry */
/*
* create an internal host template called "_unlab"
*/
/*
* create a host entry, 0.0.0.0 = _unlab
*/
/*
* create a host entry, ::0 = _unlab
*/
}
/* Called only by the TNRHC_RELE macro when the refcount goes to zero. */
void
{
/*
* We assert rhc_invalid here to make sure that no new thread could
* possibly end up finding this entry. If it could, then the
* mutex_destroy would panic.
*/
}
/* Called only by the TPC_RELE macro when the refcount goes to zero. */
void
{
}
/*
* Find and hold a reference to a template entry by name. Ignores entries that
* are being deleted.
*/
static tsol_tpc_t *
{
if (tpc->tpc_invalid)
else
}
return (tpc);
}
static int
{
return (EINVAL);
return (ENOENT);
tmpmask, TNRHC_SIZE)];
return (EINVAL);
return (ENOENT);
tmpmask_v6, TNRHC_SIZE)];
} else {
return (EAFNOSUPPORT);
}
/* search for existing entry */
break;
}
}
}
/*
* Flush all remote host entries from the database.
*
* Note that the htable arrays themselves do not have reference counters, so,
* unlike the remote host entries, they cannot be freed.
*/
static void
{
while (--nbits >= 0) {
continue;
/*
* List walkers hold this lock during the walk. It
* protects tnrh_list and rhc_next.
*/
/*
* There may still be users of the rhcs at this point,
* but not of the list or its next pointer. Thus, the
* only thing that would need to be done under a lock
* is setting the invalid bit, but that's atomic
* anyway, so no locks needed here.
*/
}
hent++;
}
}
}
/*
* Load a remote host entry into kernel cache. Create a new one if a matching
* entry isn't found, otherwise replace the contents of the previous one by
* deleting it and recreating it. (Delete and recreate is used to avoid
* allowing other threads to see an unstable data structure.)
*
* A "matching" entry is the one whose address matches that of the one
* being loaded.
*
* Return 0 for success, error code for failure.
*/
int
{
tsol_tnrhc_t **rhp;
/* Find the existing entry, if any, leaving the hash locked */
return (EINVAL);
return (ENOMEM);
tmpmask, TNRHC_SIZE)];
0)
break;
}
return (EINVAL);
return (ENOMEM);
tmpmask_v6, TNRHC_SIZE)];
break;
}
} else {
return (EAFNOSUPPORT);
}
return (ENOMEM);
}
/* Find and bump the reference count on the named template */
return (EINVAL);
}
/* Clobber the old remote host entry. */
TNRHC_RELE(rh);
}
/* Initialize the new entry. */
/* The rhc now owns this tpc reference, so no TPC_RELE past here */
return (0);
}
static int
{
case AF_INET:
B_TRUE);
break;
case AF_INET6:
B_TRUE);
break;
default:
return (EINVAL);
}
return (ENOENT);
sizeof (rhent->rh_template));
return (0);
}
static boolean_t
template_name_ok(const char *name)
{
if (*name == '\0')
break;
name++;
}
}
static int
{
int retv;
/* Make sure user has sufficient privilege */
/*
* Get arguments
*/
if (cmd != TNDB_FLUSH &&
}
switch (cmd) {
case TNDB_LOAD:
} else {
}
break;
case TNDB_DELETE:
break;
case TNDB_GET:
break;
}
if (retv != 0)
break;
/*
* Copy out result
*/
}
break;
case TNDB_FLUSH:
break;
default:
int, cmd);
retv = EOPNOTSUPP;
break;
}
if (retv != 0)
else
return (retv);
}
static tsol_tpc_t *
{
/*
* We intentionally allocate a new entry before taking the lock on the
* entire database.
*/
return (NULL);
&hv) == 0) {
(void) mod_hash_destroy(tpc_name_hash,
}
/* tsol_tpent_t is the same on LP64 and ILP32 */
return (tpc);
}
static int
tnrhtp_delete(const char *tname)
{
(void) mod_hash_destroy(tpc_name_hash,
retv = 0;
}
return (retv);
}
/* ARGSUSED */
static uint_t
{
return (MH_WALK_CONTINUE);
}
static void
tnrhtp_flush(void)
{
}
static int
{
int retv;
int type;
/* Make sure user has sufficient privilege */
/*
* Get argument. Note that tsol_tpent_t is the same on LP64 and ILP32,
* so no special handling is required.
*/
if (cmd != TNDB_FLUSH) {
}
/*
* Don't let the user give us a bogus (unterminated) template
* name.
*/
}
switch (cmd) {
case TNDB_LOAD:
break;
}
else
retv = 0;
break;
case TNDB_GET:
break;
}
/* Copy out result */
} else {
retv = 0;
}
break;
case TNDB_DELETE:
break;
case TNDB_FLUSH:
tnrhtp_flush();
retv = 0;
break;
default:
cmd);
retv = EOPNOTSUPP;
break;
}
if (retv != 0)
else
return (retv);
}
/*
* MLP entry ordering logic
*
* There are two loops in this routine. The first loop finds the entry that
* either logically follows the new entry to be inserted, or is the entry that
* precedes and overlaps the new entry, or is NULL to mean end-of-list. This
* is 'tme.' The second loop scans ahead from that point to find any overlap
* on the front or back of this new entry.
*
* For the first loop, we can have the following cases in the list (note that
* the port-portmax range is inclusive):
*
* port portmax
* +--------+
* 1: +------+ ................... precedes; skip to next
* 2: +------+ ............. overlaps; stop here if same protocol
* 3: +------+ ......... overlaps; stop if same or higher protocol
* 4: +-------+ .... overlaps or succeeds; stop here
*
* For the second loop, we can have the following cases (note that we need not
* care about other protocol entries at this point, because we're only looking
* for overlap, not an insertion point):
*
* port portmax
* +--------+
* 5: +------+ ............. overlaps; stop if same protocol
* 6: +------+ ......... overlaps; stop if same protocol
* 7: +-------+ .... overlaps; stop if same protocol
* 8: +---+ . follows; search is done
*
* In other words, this second search needs to consider only whether the entry
* has a starting port number that's greater than the end point of the new
* entry. All others are overlaps.
*/
static int
{
int retv;
if (addflag) {
NULL)
return (ENOMEM);
} else {
}
/*
* First loop: find logical insertion point or overlap. Table is kept
* in order of port number first, and then, within that, by protocol
* number.
*/
/* logically next (case 4) */
break;
/* if this is logically next or overlap, then stop (case 3) */
break;
/* earlier or same port sequence; check for overlap (case 2) */
break;
/* otherwise, loop again (case 1) */
}
/* Second loop: scan ahead for overlap */
/* check if entry follows; no overlap (case 8) */
break;
}
/* only exact protocol matches at this point (cases 5-7) */
break;
}
retv = 0;
if (addflag) {
} else {
} else {
}
else
}
} else {
} else {
else
else
}
}
return (retv);
}
/*
* Add or remove an MLP entry from the database so that the classifier can find
* it.
*
* Note: port number is in host byte order.
*/
int
{
int retv = 0;
}
return (retv);
}
static void
{
else
else
}
}
}
/*
* Note: user supplies port numbers in host byte order.
*/
static int
{
int retv;
/* Make sure user has sufficient privilege */
/*
* Get argument. Note that tsol_mlpent_t is the same on LP64 and
* ILP32, so no special handling is required.
*/
}
/* MLPs on shared IP addresses */
mlpl = &shared_mlps;
} else {
}
switch (cmd) {
case TNDB_LOAD:
tsol_mlpent_t *, &tsme);
break;
}
break;
case TNDB_GET:
tsol_mlpent_t *, &tsme);
/*
* Search for the requested element or, failing that, the one
* that's logically next in the sequence.
*/
continue;
break;
break;
}
} else {
retv = 0;
}
break;
case TNDB_DELETE:
tsol_mlpent_t *, &tsme);
break;
case TNDB_FLUSH:
tsol_mlpent_t *, &tsme);
retv = 0;
break;
default:
cmd);
retv = EOPNOTSUPP;
break;
}
/* Copy out result */
}
}
if (retv != 0)
else
return (retv);
}
/*
* Returns a tnrhc matching the addr address.
* The returned rhc's refcnt is incremented.
*/
{
int i;
for (i = (TSOL_MASK_TABLE_SIZE - 1); i >= 0; i--) {
if ((tnrhc_table[i]) == NULL)
continue;
tmpmask = tsol_plen_to_mask(i);
tnrhc_hash = &tnrhc_table[i][
TNRHC_HOLD(rh);
return (rh);
}
}
}
return (NULL);
}
/*
* Returns a tnrhc matching the addr address.
* The returned rhc's refcnt is incremented.
*/
{
int i;
if (IN6_IS_ADDR_V4MAPPED(in6)) {
return (find_rhc_v4(&in4));
}
for (i = (TSOL_MASK_TABLE_SIZE_V6 - 1); i >= 0; i--) {
if ((tnrhc_table_v6[i]) == NULL)
continue;
tsol_plen_to_mask_v6(i, &tmpmask);
tnrhc_hash = &tnrhc_table_v6[i][
*in6)) {
TNRHC_HOLD(rh);
return (rh);
}
}
}
return (NULL);
}
{
if (version == IPV4_VERSION)
else
/*
* This should not happen unless the user deletes
* templates without recreating them. Try to find the
* new version of template. If there is none, then
* just give up.
*/
}
}
return (tpc);
}
return (NULL);
}
/*
* create an internal template called "_unlab":
*
* _unlab;\
* host_type = unlabeled;\
* def_label = ADMIN_LOW[ADMIN_LOW];\
* min_sl = ADMIN_LOW;\
* max_sl = ADMIN_HIGH;
*/
static void
tsol_create_i_tmpls(void)
{
/* create _unlab */
}
/*
* set up internal host template, called from kernel only.
*/
static void
{
/* Allocate a new entry before taking the lock */
&tnrhc_table_v6[0][0];
/* We're keeping the new entry. */
TNRHC_HOLD(rh);
}
/*
* Link the entry to internal_unlab
*/
}
}
/*
* Returns 0 if the port is known to be SLP. Returns next possible port number
* (wrapping through 1) if port is MLP on shared or global. Administrator
* should not make all ports MLP. If that's done, then we'll just pretend
* everything is SLP to avoid looping forever.
*
* Note: port is in host byte order.
*/
{
for (;;) {
}
}
}
}
break;
if (loop)
return (0);
}
}
/*
* tsol_mlp_port_type will check if the given (zone, proto, port) is a
* multilevel port. If it is, return the type (shared, private, or both), or
* indicate that it's single-level.
*
* Note: port is given in host byte order, not network byte order.
*/
{
break;
}
}
else if (mlptype == mlptPrivate)
}
}
break;
}
}
else if (mlptype == mlptShared)
}
}
return (mlptype);
}
/*
* tsol_mlp_findzone will check if the given (proto, port) is a multilevel port
* on a shared address. If it is, return the owning zone.
*
* Note: lport is in network byte order, unlike the other MLP functions,
* because the callers of this function are all dealing with packets off the
* wire.
*/
{
return (ALL_ZONES);
break;
}
return (zoneid);
}
/* Debug routine */
void
{
/* We really support only sensitivity labels */
}
/*
* Name: labelsys()
*
* Normal: Routes TSOL syscalls.
*
* Output: As defined for each TSOL syscall.
* Returns ENOSYS for unrecognized calls.
*/
/* ARGSUSED */
int
{
switch (op) {
case TSOL_SYSLABELING:
return (sys_labeling);
case TSOL_TNRH:
case TSOL_TNRHTP:
case TSOL_TNMLP:
case TSOL_GETLABEL:
case TSOL_FGETLABEL:
default:
}
/* NOTREACHED */
}