==== //depot/user/pjd/zfs/sys/security/mac_portacl/mac_portacl.c#2 - /home/pjd/zfs/sys/security/mac_portacl/mac_portacl.c ==== @@ -61,15 +61,16 @@ #include #include +#include #include #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -115,20 +116,29 @@ #define RULE_GID 1 #define RULE_UID 2 +#define RULE_JID 3 +#define RULE_JHOST 4 #define RULE_PROTO_TCP 1 #define RULE_PROTO_UDP 2 struct rule { - id_t r_id; + union { + id_t ur_numid; + char ur_strid[256]; + } __rule_id; int r_idtype; u_int16_t r_port; int r_protocol; TAILQ_ENTRY(rule) r_entries; }; +#define r_numid __rule_id.ur_numid +#define r_strid __rule_id.ur_strid #define GID_STRING "gid" +#define UID_STRING "uid" +#define JID_STRING "jid" +#define JHOST_STRING "jhost" #define TCP_STRING "tcp" -#define UID_STRING "uid" #define UDP_STRING "udp" /* @@ -138,7 +148,7 @@ * for the specified binding. */ -static struct mtx rule_mtx; +static struct rwlock rule_lock; static TAILQ_HEAD(rulehead, rule) rule_head; static char rule_string[MAC_RULE_STRING_LEN]; @@ -161,7 +171,7 @@ destroy(struct mac_policy_conf *mpc) { - mtx_destroy(&rule_mtx); + rw_destroy(&rule_lock); toast_rules(&rule_head); } @@ -169,7 +179,7 @@ init(struct mac_policy_conf *mpc) { - mtx_init(&rule_mtx, "rule_mtx", NULL, MTX_DEF); + rw_init(&rule_lock, "rule_lock"); TAILQ_INIT(&rule_head); } @@ -191,23 +201,39 @@ error = EINVAL; goto out; } - id = strsep(&element, ":"); - if (id == NULL) { + if (strcmp(idtype, UID_STRING) == 0) + new->r_idtype = RULE_UID; + else if (strcmp(idtype, GID_STRING) == 0) + new->r_idtype = RULE_GID; + else if (strcmp(idtype, JID_STRING) == 0) + new->r_idtype = RULE_JID; + else if (strcmp(idtype, JHOST_STRING) == 0) { + if (jail_set_hostname_allowed) { + printf("MAC_PORTACL ERROR: To use idtype 'jhost', " + "sysctl security.jail.set_hostname_allowed has " + "to be set to 0.\n"); + error = EOPNOTSUPP; + goto out; + } + new->r_idtype = RULE_JHOST; + } else { error = EINVAL; goto out; } - new->r_id = strtol(id, &p, 10); - if (*p != '\0') { + + id = strsep(&element, ":"); + if (id == NULL) { error = EINVAL; goto out; } - if (strcmp(idtype, UID_STRING) == 0) - new->r_idtype = RULE_UID; - else if (strcmp(idtype, GID_STRING) == 0) - new->r_idtype = RULE_GID; + if (new->r_idtype == RULE_JHOST) + strlcpy(new->r_strid, id, sizeof(new->r_strid)); else { - error = EINVAL; - goto out; + new->r_numid = strtol(id, &p, 10); + if (*p != '\0') { + error = EINVAL; + goto out; + } } protocol = strsep(&element, ":"); if (protocol == NULL) { @@ -283,6 +309,12 @@ case RULE_UID: idtype = UID_STRING; break; + case RULE_JID: + idtype = JID_STRING; + break; + case RULE_JHOST: + idtype = JHOST_STRING; + break; default: panic("rule_printf: unknown idtype (%d)\n", rule->r_idtype); } @@ -298,8 +330,14 @@ panic("rule_printf: unknown protocol (%d)\n", rule->r_protocol); } - sbuf_printf(sb, "%s:%jd:%s:%d", idtype, (intmax_t)rule->r_id, - protocol, rule->r_port); + + if (rule->r_idtype == RULE_JHOST) { + sbuf_printf(sb, "%s:%s:%s:%u", idtype, rule->r_strid, protocol, + (u_int)rule->r_port); + } else { + sbuf_printf(sb, "%s:%jd:%s:%u", idtype, (intmax_t)rule->r_numid, + protocol, (u_int)rule->r_port); + } } static char * @@ -312,16 +350,15 @@ sb = sbuf_new_auto(); needcomma = 0; - mtx_lock(&rule_mtx); - for (rule = TAILQ_FIRST(&rule_head); rule != NULL; - rule = TAILQ_NEXT(rule, r_entries)) { + rw_rlock(&rule_lock); + TAILQ_FOREACH(rule, &rule_head, r_entries) { if (!needcomma) needcomma = 1; else sbuf_printf(sb, ","); rule_printf(sb, rule); } - mtx_unlock(&rule_mtx); + rw_runlock(&rule_lock); sbuf_finish(sb); temp = strdup(sbuf_data(sb), M_PORTACL); sbuf_delete(sb); @@ -362,11 +399,11 @@ goto out; TAILQ_INIT(&save_head); - mtx_lock(&rule_mtx); + rw_wlock(&rule_lock); TAILQ_CONCAT(&save_head, &rule_head, r_entries); TAILQ_CONCAT(&rule_head, &head, r_entries); strcpy(rule_string, string); - mtx_unlock(&rule_mtx); + rw_wunlock(&rule_lock); toast_rules(&save_head); } out: @@ -376,7 +413,7 @@ } SYSCTL_PROC(_security_mac_portacl, OID_AUTO, rules, - CTLTYPE_STRING|CTLFLAG_RW, 0, 0, sysctl_rules, "A", "Rules"); + CTLTYPE_STRING|CTLFLAG_RW, 0, 0, sysctl_rules, "A", "Rules"); static int rules_check(struct ucred *cred, int family, int type, u_int16_t port) @@ -393,37 +430,64 @@ return (0); error = EPERM; - mtx_lock(&rule_mtx); - for (rule = TAILQ_FIRST(&rule_head); - rule != NULL; - rule = TAILQ_NEXT(rule, r_entries)) { + rw_rlock(&rule_lock); + TAILQ_FOREACH(rule, &rule_head, r_entries) { if (type == SOCK_DGRAM && rule->r_protocol != RULE_PROTO_UDP) continue; if (type == SOCK_STREAM && rule->r_protocol != RULE_PROTO_TCP) continue; if (port != rule->r_port) continue; - if (rule->r_idtype == RULE_UID) { - if (cred->cr_uid == rule->r_id) { + switch (rule->r_idtype) { + case RULE_UID: + if (cred->cr_uid == rule->r_numid) + error = 0; + break; + case RULE_GID: + if (cred->cr_gid == rule->r_numid) + error = 0; + else if (groupmember(rule->r_numid, cred)) error = 0; - break; - } - } else if (rule->r_idtype == RULE_GID) { - if (cred->cr_gid == rule->r_id) { + break; + case RULE_JID: + /* JID==0 means outside a jail. */ + if (!jailed(cred) && rule->r_numid == 0) error = 0; - break; - } else if (groupmember(rule->r_id, cred)) { + else if (jailed(cred) && + cred->cr_prison->pr_id == rule->r_numid) error = 0; + break; + case RULE_JHOST: + if (jail_set_hostname_allowed) { + printf("MAC_PORTACL WARNING: jhost:%s:%s:%u " + "rule ignored, sysctl " + "security.jail.set_hostname_allowed has " + "to be set to 0.\n", rule->r_strid, + rule->r_protocol == RULE_PROTO_TCP ? + TCP_STRING : UDP_STRING, + (u_int)rule->r_port); break; } - } else + if (jailed(cred) && + strcmp(cred->cr_prison->pr_host, rule->r_strid) == 0) + error = 0; + break; + default: panic("rules_check: unknown rule type %d", rule->r_idtype); + } + if (error == 0) + break; } - mtx_unlock(&rule_mtx); + rw_runlock(&rule_lock); + + if (error == 0 || portacl_suser_exempt == 0) + return (error); - if (error != 0 && portacl_suser_exempt != 0) + if (portacl_suser_exempt == 1 || + (portacl_suser_exempt == 2 && !jailed(cred))) { error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0); + } return (error); } @@ -434,7 +498,7 @@ * the source port is left up to the IP stack to determine automatically. */ static int -socket_check_bind(struct ucred *cred, struct socket *so, +portacl_socket_check_bind(struct ucred *cred, struct socket *so, struct label *solabel, struct sockaddr *sa) { struct sockaddr_in *sin; @@ -486,7 +550,7 @@ { .mpo_destroy = destroy, .mpo_init = init, - .mpo_socket_check_bind = socket_check_bind, + .mpo_socket_check_bind = portacl_socket_check_bind, }; MAC_POLICY_SET(&portacl_ops, mac_portacl, "TrustedBSD MAC/portacl",