Index: sys/modules/mac_ipacl/Makefile =================================================================== --- /dev/null +++ sys/modules/mac_ipacl/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/security/mac_ipacl + +KMOD=mac_ipacl +SRCS=mac_ipacl.c + +.include Index: sys/netinet/in.c =================================================================== --- sys/netinet/in.c +++ sys/netinet/in.c @@ -72,6 +72,7 @@ #include #include +#include static int in_aifaddr_ioctl(u_long, caddr_t, struct ifnet *, struct thread *); static int in_difaddr_ioctl(u_long, caddr_t, struct ifnet *, struct thread *); @@ -372,6 +373,18 @@ /* * See whether address already exist. */ + + /* + * for MAC policy check to block only + * jails from setting their IPv4 addr + */ +#ifdef MAC + error = mac_inet_check_SIOCAIFADDR(td->td_ucred, &addr->sin_addr, ifp); + if (error) { + return (error); + } +#endif + iaIsFirst = true; ia = NULL; NET_EPOCH_ENTER(et); Index: sys/netinet6/in6.c =================================================================== --- sys/netinet6/in6.c +++ sys/netinet6/in6.c @@ -112,6 +112,7 @@ #include #include +#include /* * struct in6_ifreq and struct ifreq must be type punnable for common members @@ -556,7 +557,17 @@ { struct nd_prefixctl pr0; struct nd_prefix *pr; - + + /* + *If MAC is defined, check the credentials + *only block jails from setting their IPv6 addr + */ +#ifdef MAC + error = mac_inet6_check_SIOCAIFADDR(td->td_ucred, &sa6->sin6_addr, ifp); + if (error) { + goto out; + } +#endif /* * first, make or update the interface address structure, * and link it to the list. Index: sys/security/mac/mac_framework.h =================================================================== --- sys/security/mac/mac_framework.h +++ sys/security/mac/mac_framework.h @@ -89,6 +89,9 @@ struct vnode; struct vop_setlabel_args; +struct in_addr; +struct in6_addr; + #include /* XXX acl_type_t */ #include /* accmode_t */ @@ -152,6 +155,13 @@ struct ifnet *ifp); int mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp); +/* + * checks if the IP address is allowed for interface + */ +int mac_inet_check_SIOCAIFADDR(struct ucred *cred, + const struct in_addr *ia, struct ifnet *ifp); +int mac_inet6_check_SIOCAIFADDR(struct ucred *cred, + const struct in6_addr *ia6, struct ifnet *ifp); int mac_inpcb_check_deliver(struct inpcb *inp, struct mbuf *m); int mac_inpcb_check_visible(struct ucred *cred, struct inpcb *inp); Index: sys/security/mac/mac_inet.c =================================================================== --- sys/security/mac/mac_inet.c +++ sys/security/mac/mac_inet.c @@ -108,6 +108,21 @@ return (0); } +/* + * return 0 if the IPv4 address is allowed for the jail + * if MAC policy doesn't allow that IP address throw error + */ + +int +mac_inet_check_SIOCAIFADDR(struct ucred *cred, const struct in_addr *ia, + struct ifnet *ifp) +{ + int error; + + MAC_POLICY_CHECK(ip4_check_jail, cred, ia, ifp); + return (error); +} + static struct label * mac_ipq_label_alloc(int flag) { Index: sys/security/mac/mac_inet6.c =================================================================== --- sys/security/mac/mac_inet6.c +++ sys/security/mac/mac_inet6.c @@ -173,6 +173,22 @@ q6->ip6q_label); } +/* + * return 0 if the IPv6 address is allowed for the jail + * if MAC policy doesn't allow that IP address throw error + * NOTE - SIOCAIFADDR_IN6 is corresponding call for IPV6 + */ + +int +mac_inet6_check_SIOCAIFADDR(struct ucred *cred, const struct in6_addr *ia6, + struct ifnet *ifp) +{ + int error; + + MAC_POLICY_CHECK(ip6_check_jail, cred, ia6, ifp); + return (error); + +} void mac_netinet6_nd6_send(struct ifnet *ifp, struct mbuf *m) { Index: sys/security/mac/mac_policy.h =================================================================== --- sys/security/mac/mac_policy.h +++ sys/security/mac/mac_policy.h @@ -100,6 +100,9 @@ struct vattr; struct vnode; +struct in_addr; +struct in6_addr; + /* * Policy module operations. */ @@ -238,6 +241,15 @@ typedef void (*mpo_ip6q_update_t)(struct mbuf *m, struct label *mlabel, struct ip6q *q6, struct label *q6label); +/* + * policy ops checking IPv4 and IPv6 address for ipacl + */ + +typedef int (*mpo_ip4_check_jail_t)(struct ucred *cred, const struct in_addr *ia, + struct ifnet *ifp); +typedef int (*mpo_ip6_check_jail_t)(struct ucred *cred, const struct in6_addr *ia6, + struct ifnet *ifp); + typedef void (*mpo_ipq_create_t)(struct mbuf *m, struct label *mlabel, struct ipq *q, struct label *qlabel); typedef void (*mpo_ipq_destroy_label_t)(struct label *label); @@ -746,6 +758,9 @@ mpo_inpcb_destroy_label_t mpo_inpcb_destroy_label; mpo_inpcb_init_label_t mpo_inpcb_init_label; mpo_inpcb_sosetlabel_t mpo_inpcb_sosetlabel; + + mpo_ip4_check_jail_t mpo_ip4_check_jail; + mpo_ip6_check_jail_t mpo_ip6_check_jail; mpo_ip6q_create_t mpo_ip6q_create; mpo_ip6q_destroy_label_t mpo_ip6q_destroy_label; Index: sys/security/mac_ipacl/Makefile =================================================================== --- /dev/null +++ sys/security/mac_ipacl/Makefile @@ -0,0 +1,5 @@ +KMOD=mac_ipacl +SRCS=mac_ipacl.c + +.include + Index: sys/security/mac_ipacl/design_notes.txt =================================================================== --- /dev/null +++ sys/security/mac_ipacl/design_notes.txt @@ -0,0 +1,72 @@ +"Simplicity is the ultimate sophistication" +------------------------ +|mac_ipacl Design Notes| +------------------------ + +Design Goals - +------------ +1. Do we need to check the addresses per interface per vnet-jail or addresses per + vnet-jail? + + The first one gives more flexibilty but increases complexity of policy table. + The first is more prefered over the second since it gives ability to restrict + the particular interface of a jail. + +2. Another question which increses complexity here is- Should jails be allowed to + create new interface(intefaces created after the policy has been loaded? and, + if yes, then how our module will react to the new interface? + + I am not sure about this one. But the new interfaces shall not affect the host + until and unless they are connected to the host or other jail. So, they don't + have any effect but this issue should be dealt to prevent any design flaw/bugs. + + New interfaces, by default, should not have any rights to set the IP address, + new rules(about the new interface) have to be applied by the host to provide + those rights. + +3. Another important step is to decide whether to allow all IP addresses or reject + all IP address when the MAC module is loaded? + + I'm thinking to allow all address when the module is loaded and then tune it with + a sysctl variable to disallow all. The host can then specify IP address to allow + according to the Policy Table. + +4. The "Policy Table" may take- + a.) JID(or name of the jail) - the jail id/name for the jail for which the + restriction are to be applied, This identifies that jail. + b.) Network Interface - The network interface which are allowed to set the IP + address and/or which are not? + OR we can say, name of the interfaces that are allowed for setting their IP + c.) IP address/list of IP address which are allowed for particular interface. + d.) Network Prefix(A range of IP address) that is allowed to the jail. + e.) label to allow/reject? But depend on whether we started with all IP or NO IP. + f.) ? + +5. In policy, we may check the jail by passing the credential and where the thread is + and also if the thread's vnet and intefaces matches. + +6. How to name the jail in the policy? + + I am thinking of using jid to name the jail in the policy. But another question + arises is how to find that jail with that jid. Search for the function that find + your prison with given jid. check prison_find(int jid), this will solve this problem + +7. should we also check for subnet the jail is choosing? If yes, then we also have to pass + the prefix to the framework. + +Points +(To be kept in mind) - +-------------------- +1. ioctl check calls should be kept generic. Although, currently we are only interested + in VIMAGE JAILS, but in future might need to extend the MAC module to host system, + et cetera. + So, the MAC calls should run for all cases, and checks related to jails and VNET + should be handled later in the Policy Module + +3. vnet should be checked from socket or interface and not from the thread. This means + we'd probably have to pass one of those in the policy as well. + + Passing the interface ifnet to the policy will be more easy/appropriate, since only + it is available as arguement in in.c(in_aifaddr_ioctl) for our MAC checks. Alternatively + we could have moved our check to in_control() for ipv4 case like we have in IPv6 case, + for checking the vnet from socket. Index: sys/security/mac_ipacl/mac_ipacl.c =================================================================== --- /dev/null +++ sys/security/mac_ipacl/mac_ipacl.c @@ -0,0 +1,432 @@ +/* MAC policy module for limiting IP address to a VNET enabled jail */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +SYSCTL_DECL(_security_mac); + +static SYSCTL_NODE(_security_mac, OID_AUTO, ipacl, CTLFLAG_RW, 0, + "TrustedBSD mac_ipacl policy controls"); + +static int ipacl_ipv4 = 1; +SYSCTL_INT(_security_mac_ipacl, OID_AUTO, ipv4, CTLFLAG_RWTUN, + &ipacl_ipv4, 0, "Enforce mac_ipacl for IPv4 addresses"); + +static int ipacl_ipv6 = 1; +SYSCTL_INT(_security_mac_ipacl, OID_AUTO, ipv6, CTLFLAG_RWTUN, + &ipacl_ipv6, 0, "Enforce mac_ipacl for IPv6 addresses"); + +static MALLOC_DEFINE(M_IPACL, "ipacl_rule", "Rules for mac_ipacl"); + +#define MAC_RULE_STRING_LEN 1024 + +struct ipacl_addr { + union { + struct in_addr ipv4; + struct in6_addr ipv6; + u_int8_t addr8[16]; + u_int16_t addr16[8]; + u_int32_t addr32[4]; + } ipa; /* 128 bit address*/ +/*inspired from struct pf_addr*/ +#define v4 ipa.ipv4 +#define v6 ipa.ipv6 +#define addr8 ipa.addr8 +#define addr16 ipa.addr16 +#define addr32 ipa.addr32 +}; + + +struct ip_rule { + int jid; /* or name it int pr_id?*/ + bool allow; /*allow or deny */ + bool subnet_apply; /*make it applicable for whole subnet instead*/ + char if_name[IFNAMSIZ]; /*network interface name*/ + int af; /*address family, can be ipv4, ipv6 or hw_addr(later)*/ + struct ipacl_addr addr; + struct ipacl_addr mask; + TAILQ_ENTRY(ip_rule) r_entries; /* queue */ + +}; + +static struct mtx rule_mtx; +static TAILQ_HEAD(rulehead, ip_rule) rule_head; +static char rule_string[MAC_RULE_STRING_LEN]; + +static void +toast_rules(struct rulehead *head) +{ + struct ip_rule *rule; + + while ((rule = TAILQ_FIRST(head)) != NULL) { + TAILQ_REMOVE(head, rule, r_entries); + free(rule, M_IPACL); + } +} + +static void +ipacl_init(struct mac_policy_conf *conf) +{ + mtx_init(&rule_mtx, "rule_mtx", NULL, MTX_DEF); + TAILQ_INIT(&rule_head); +} + +static void +ipacl_destroy(struct mac_policy_conf *conf) +{ + mtx_destroy(&rule_mtx); + toast_rules(&rule_head); +} + +/* + * Note: parsing routines are destructive on the passed string. + */ + +static int +parse_rule_element(char *element, struct ip_rule **rule) +{ + char *jid, *allow, *if_name, *fam, *ip_addr, *mask, *p; + struct ip_rule *new; + int error, prefix, i; + + error = 0; + new = malloc(sizeof(*new), M_IPACL, M_ZERO | M_WAITOK); + + jid = strsep(&element, "@"); + if (jid == NULL) { + error = EINVAL; + goto out; + }/*jail wildcard?*/ + new->jid = strtol(jid, &p, 10); + if (*p != '\0') { + error = EINVAL; + goto out; + } + allow = strsep(&element, "@"); + if (allow == NULL) { + error = EINVAL; + goto out; + } + new->allow=strtol(allow, &p, 10); + if (*p != '\0') { + error = EINVAL; + goto out; + } + if_name = strsep(&element, "@"); + if (sizeof(if_name) > IF_NAMESIZE) { + error = EINVAL; + goto out; + } + /* empty = wildcard to all interfaces*/ + bzero(new->if_name, IF_NAMESIZE); + bcopy(if_name, new->if_name, strlen(if_name)); + fam = strsep(&element, "@"); + if (fam == NULL) { + error = EINVAL; + goto out; + } + + new->af = (strcmp(fam, "AF_INET") == 0) ? AF_INET : + (strcmp(fam, "AF_INET6") == 0) ? AF_INET6 : -1; + if (new->af == -1) { + error = EINVAL; + goto out; + } + + ip_addr = strsep(&element, "@"); + if (ip_addr == NULL) { + error = EINVAL; + goto out; + } + if (inet_pton(new->af, ip_addr, new->addr.addr32) != 1) { + error = EINVAL; + goto out; + } + mask = element; + if (mask == NULL) { + error = EINVAL; + goto out; + } + prefix = strtol(mask, &p, 10); + if (*p != '\0') { + error = EINVAL; + goto out; + } + /*prefix -1 make policy applicable to individual IP only*/ + if (prefix == -1) + new->subnet_apply = 0; + else { + new->subnet_apply = 1; + if (new->af == AF_INET) { + if (prefix < 0 || prefix > 32) { + error = EINVAL; + goto out; + } + if (prefix == 0) + new->mask.addr32[0] = htonl(0); + + else + new->mask.addr32[0] = htonl(~((1 << (32 - prefix)) - 1)); + } + else { + if (prefix < 0 || prefix > 128) { + error = EINVAL; + goto out; + } + for (i = 0; prefix > 0; prefix -= 8, i++) + new->mask.addr8[i] = prefix >= 8 ? 0xFF : + (unsigned long)((0xFFU << (8 - prefix)) & 0xFFU); + } + } + +out: + if (error != 0) { + free(new, M_IPACL); + *rule = NULL; + } else + *rule = new; + return (error); +} + +/* + * parsing rule- jid@allow@interface_name@addr_family@ip_addr@subnet_mask + * Eg:sysctl security.mac.ipacl.rules=1@1@epair0b@AF_INET@192.168.42.2@24,0@0@epair0b@AF_INET6@ff00::@8 + */ + +static int +parse_rules(char *string, struct rulehead *head) +{ + struct ip_rule *new; + char *element; + int error; + + error = 0; + while ((element = strsep(&string, ",")) != NULL) { + if (strlen(element) == 0) + continue; + error = parse_rule_element(element, &new); + if (error) + goto out; + TAILQ_INSERT_TAIL(head, new, r_entries); + } +out: + if (error != 0) + toast_rules(head); + return (error); +} + +static int +sysctl_rules(SYSCTL_HANDLER_ARGS) +{ + char *string, *copy_string, *new_string; + struct rulehead head, save_head; + int error; + + new_string = NULL; + if (req->newptr != NULL) { + new_string = malloc(MAC_RULE_STRING_LEN, M_IPACL, + M_WAITOK | M_ZERO); + mtx_lock(&rule_mtx); + strcpy(new_string, rule_string); + mtx_unlock(&rule_mtx); + string = new_string; + } else + string = rule_string; + + error = sysctl_handle_string(oidp, string, MAC_RULE_STRING_LEN, req); + if (error) + goto out; + + if (req->newptr != NULL) { + copy_string = strdup(string, M_IPACL); + TAILQ_INIT(&head); + error = parse_rules(copy_string, &head); + free(copy_string, M_IPACL); + if (error) + goto out; + + TAILQ_INIT(&save_head); + mtx_lock(&rule_mtx); + TAILQ_CONCAT(&save_head, &rule_head, r_entries); + TAILQ_CONCAT(&rule_head, &head, r_entries); + strcpy(rule_string, string); + mtx_unlock(&rule_mtx); + toast_rules(&save_head); + } +out: + if (new_string != NULL) + free(new_string, M_IPACL); + return (error); +} + +SYSCTL_PROC(_security_mac_ipacl, OID_AUTO, rules, + CTLTYPE_STRING|CTLFLAG_RW, 0, 0, sysctl_rules, "A", "IP ACL Rules"); + +/* + * rough printing rules for debugging purposes + */ +#ifdef _DEBUG +static int +rule_printf(){ + struct ip_rule *rule; + char buf[32]; + char buf6[128]; + + for (rule = TAILQ_FIRST(&rule_head); + rule != NULL; + rule = TAILQ_NEXT(rule, r_entries)) { + printf("jid=%d allow=%d family=%d\n",rule->jid, rule->allow, rule->af); + if (rule->af == AF_INET) { + if (inet_ntop(AF_INET, &(rule->addr.v4), buf, sizeof(buf)) != NULL) + printf("inet addr: %s\n", buf); + if (inet_ntop(AF_INET, &(rule->mask.v4), buf, sizeof(buf)) != NULL) + printf("mask addr: %s\n", buf); + } + else if (rule->af == AF_INET6) { + if (inet_ntop(AF_INET6, &(rule->addr.v6), buf6, sizeof(buf6)) != NULL) + printf("inet6 addr: %s\n", buf6); + if (inet_ntop(AF_INET6, &(rule->mask.v6), buf6, sizeof(buf6)) != NULL) + printf("mask addr: %s\n", buf6); + } + } + return 0; +} +#endif + +static int +rules_check(struct ucred *cred, + struct ipacl_addr *ip_addr, struct ifnet *ifp) +{ + struct ip_rule *rule; + int error, i, j; + struct ipacl_addr subnet; + + error = EPERM; + + mtx_lock(&rule_mtx); + + for (rule = TAILQ_FIRST(&rule_head); + rule != NULL; + rule = TAILQ_NEXT(rule, r_entries)) { + + /*skip if current rule is for different jail*/ + if(cred->cr_prison->pr_id != rule->jid) + continue; + if (strcmp(rule->if_name, "\0") && strcmp(rule->if_name, ifp->if_xname)) + continue; + + switch (rule->af) { + case AF_INET: + if (rule->subnet_apply) { + subnet.v4.s_addr = (rule->addr.v4.s_addr & rule->mask.v4.s_addr); + if (subnet.v4.s_addr != (ip_addr->v4.s_addr & rule->mask.v4.s_addr)) + continue; + } + else { + if (ip_addr->v4.s_addr != rule->addr.v4.s_addr) + continue; + } + break; + + case AF_INET6: + if (rule->subnet_apply) { + for ( i=0 ; i<16 ; i++ ) { + subnet.v6.s6_addr[i] = (rule->addr.v6.s6_addr[i] & rule->mask.v6.s6_addr[i]); + } + j=0; + for ( i=0 ; i<16 ; i++ ) + if (subnet.v6.s6_addr[i] != (ip_addr->v6.s6_addr[i] & rule->mask.v6.s6_addr[i])) { + j=1; + break; + } + if(j) + continue; + + } + else { + if (bcmp(&rule->addr, ip_addr, sizeof(*ip_addr))) /*as called in pf.c:685*/ + continue; + } + break; + + default: + error = EINVAL; + } + if (rule->allow) + error = 0; + else + error = EPERM; + } + + mtx_unlock(&rule_mtx); + + return (error); +} + +static int +ipacl_ip4_check_jail(struct ucred *cred, + const struct in_addr *ia, struct ifnet *ifp) +{ + struct ipacl_addr ip4_addr; + ip4_addr.v4 = *ia; + + /*function only when requested by a jail*/ + if (!jailed(cred)) + return 0; + + /*check with the policy only when it is enforced for ipv4*/ + if (ipacl_ipv4) + return rules_check(cred, &ip4_addr, ifp); + + return 0; +} + +static int +ipacl_ip6_check_jail(struct ucred *cred, + const struct in6_addr *ia6, struct ifnet *ifp) +{ + struct ipacl_addr ip6_addr; + ip6_addr.v6 = *ia6; /*make copy to not alter the original*/ + in6_clearscope(&ip6_addr.v6);/* clear scope id*/ + + /*function only when requested by a jail*/ + if (!jailed(cred)) + return 0; + + /*check with the policy when it is enforced for ipv6*/ + if (ipacl_ipv6) + return rules_check(cred, &ip6_addr, ifp); + + return 0; +} + +static struct mac_policy_ops ipacl_ops = +{ + .mpo_init = ipacl_init, + .mpo_destroy = ipacl_destroy, + .mpo_ip4_check_jail = ipacl_ip4_check_jail, + .mpo_ip6_check_jail = ipacl_ip6_check_jail, +}; + +MAC_POLICY_SET(&ipacl_ops, mac_ipacl, "TrustedBSD MAC/ipacl", + MPC_LOADTIME_FLAG_UNLOADOK, NULL); Index: sys/security/mac_ipacl/notes.txt =================================================================== --- /dev/null +++ sys/security/mac_ipacl/notes.txt @@ -0,0 +1,90 @@ +----------------------------------- +Documentation Notes- +IP Address access control policy + +1. mac_ipacl allows the root of the host to limit the VNET jail's privileges + of setting IPv4 and IPv6 addresses via sysctl(8) interface. So, the host + can define rules for jails and their interfaces about IP addresses. + +2. Its default behaviour is to deny all IP addresses if policy is enforced and allow/deny + IP(or subnets) according to rules specified with sysctl + + Runtime Configuration-sysctl(8) MIB + + security.mac.ipacl.ipv4: enforce the mac_ipacl for ipv4 addresses (default:1) + + security.mac.ipacl.ipv6: enforce the mac_ipacl for ipv6 addresses (default:1) + + security.mac.ipacl.rules: + jail_id@allow@interface@address_family@IP_addr@prefix_length[,jail_id@...] + + jail_id: Describe the jail id of the jail for which the rule is written + + allow: 1 for allow and 0 for deny. action to perform for the rule + + interface: name of the interface the rule is enforced for. Interface is + left empty(ie, NULL) then it is a wildcard to enforce rule + for all interfaces. + + address_family: Address family of the IP_addr. give input as AF_INET + or AF_INET6 string only + + IP_addr: IP address(or subnet) to be allowed/deny. Action depend on the + prefix length + + prefix_length: Prefix length of the subnet to be enforced by the policy. + -1 implies the policy is enforced for individual IP address. + For non-negative value, a range of IP address(present in subnet) + which calculated as subnet = IP_addr & mask +3. Example- + a.) + sysctl security.mac.ipacl.ipv4=1 + sysctl security.mac.ipacl.ipv6=0 + sysctl security.mac.ipacl.rules=1@1@@AF_INET@169.254.123.123@-1 + It allows only 169.254.123.123 IPv4 address for all interfaces(wildcard) of jail 1. + It allows all IPv6 address since policy is not enforced for IPv6. + + b.) + sysctl security.mac.ipacl.ipv4=1 + sysctl security.mac.ipacl.ipv6=1 + sysctl security.mac.ipacl.rules=1@1@epair0b@AF_INET6@fe80::@32,1@0@epair0b@AF_INET6@fe80::abcd@-1 + It deny all IPv4 address as policy is enforced but no rules are specified about it. + It allow all IPv6 address in the subnet- fe80::/32 except fe80::abcd for interface epair0b only + c.) + sysctl security.mac.ipacl.ipv4=1 + sysctl security.mac.ipacl.ipv6=1 + sysctl security.mac.ipacl.rules=2@1@@AF_INET6@fc00::@7,2@0@@AF_INET6@fc00::1111:2200@120,2@1@@AF_INET6@fc00::1111:2299@-1,1@1@@AF_INET@198.51.100.0@24 + It allow IPv4 in the subnet 198.51.100.0/24 for jail 2 and all interfaces. + It allow IPv6 address in the subnet fc00::/7 but deny the subnet fc00::1111:2200/120, and allow + individual IP fc00::1111:2299 from the denied subnet for all interfaces in the jail 2 + +4. Using the test scripts: + a.) + Test scripts are not completely automatic :( So, the user has to create + edit the scripts to enter the jid of the test jails and interface. + After editing the scripts run make && make install, which then install + the scripts in /usr/tests/sys/mac/ipacl. + you may also need to create that directory if it gives error. + +6. To discuss the limitation of the module and point to be kept in mind while + using it. + a.) + rules are checked in the same sequence they are given. If many rules are + there for a IP(or a set of IP), result depend on final rule. + b.) + +7. Future Works + a.) + rules are given with sysctl interface which gets very complex to give them all in + command line. It has to be simplified with a better way to input those rules. + + +------------------------------------- +Commands- +1. kld + * kldstat + * kldload /usr/obj/usr/home/shivank/freebsd/amd64.amd64/sys/security/mac_ipacl/mac_ipacl.ko + * kldunload mac_ipacl +2. make + * make obj depend all install #create obj in /boot/modules, can be loaded and unloaded by just name + * make -j 4 KERNCONF=VIMAGE kernel -DKERNFAST Index: sys/security/mac_ipacl/tests/Makefile =================================================================== --- /dev/null +++ sys/security/mac_ipacl/tests/Makefile @@ -0,0 +1,14 @@ +PACKAGE= tests + +TESTSDIR= ${TESTSBASE}/sys/mac/ipacl + +${PACKAGE}FILES+= ipacl_script.sh + +TAP_TESTS_SH+= ip4_test +TAP_TESTS_SH+= ip6_test +.for t in ${TAP_TESTS_SH} +TEST_METADATA.$t+= required_user="root" +TEST_METADATA.$t+= timeout="450" +.endfor + +.include Index: sys/security/mac_ipacl/tests/ip4_test.sh =================================================================== --- /dev/null +++ sys/security/mac_ipacl/tests/ip4_test.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +dir=`dirname $0` +. ${dir}/ipacl_script.sh + +echo "1..28" +jid1=1 +jid2=5 +#run this script for epair0a and epair0b as of now +#use ifconfig epair create to generate epair +#epair0a = host #epair0b = jail 1 +# make sure to create second jail(jid=2) with epair1b + +#this script also tests that host remain unaffected in all cases +if1_host="epair0a" +if1_jail1="epair0b" +if2_jail1="lo0" +if1_jail2="epair1b" +if2_jail2="lo0" + +# Verify effect of changing security.mac.ipacl.ipv4 +sysctl security.mac.ipacl.ipv4=0 >/dev/null +exec_test ok ipv4 ${if1_host} '192.168.43.26' 16 0 +exec_test ok ipv4 ${if1_jail1} '192.168.43.26' 16 1 +exec_test ok ipv4 ${if1_host} '127.1.32.31' 24 0 +exec_test ok ipv4 ${if1_jail1} '198.18.0.12' 15 1 + +sysctl security.mac.ipacl.ipv4=1 >/dev/null +sysctl security.mac.ipacl.rules= >/dev/null + +exec_test ok ipv4 ${if1_host} '192.168.43.26' 16 0 +exec_test fl ipv4 ${if1_jail1} '192.168.43.26' 16 1 +exec_test ok ipv4 ${if1_host} '127.1.32.31' 24 0 +exec_test fl ipv4 ${if1_jail1} '198.18.0.12' 15 1 + +# rule: jid@allow@interface_name@addr_family@ip_addr@subnet_mask +sysctl security.mac.ipacl.rules=${jid1}@1@${if1_jail1}@AF_INET@192.168.42.2@-1,${jid2}@1@${if1_jail2}@AF_INET@127.1.32.1@-1,${jid2}@1@@AF_INET@198.18.0.1@15,${jid2}@0@@AF_INET@198.18.0.12@-1 >/dev/null + +# Verify if security.mac.ipacl.rules allow jail to set certain IPv4 address +exec_test ok ipv4 ${if1_jail1} '192.168.42.2' 16 ${jid1} +exec_test fl ipv4 ${if1_jail1} '192.168.42.3' 16 ${jid1} +exec_test ok ipv4 ${if1_jail2} '127.1.32.1' 24 ${jid2} +exec_test fl ipv4 ${if2_jail2} '127.1.32.1' 24 ${jid2} + +# Verify if scurity.mac.ipacl.rules allow jail to set any address in subnet +exec_test ok ipv4 ${if1_jail2} '198.18.0.192' 15 ${jid2} +exec_test ok ipv4 ${if1_jail2} '198.18.132.121' 15 ${jid2} +exec_test fl ipv4 ${if1_jail2} '197.1.123.123' 15 ${jid2} +exec_test fl ipv4 ${if1_jail2} '198.18.0.12' 15 ${jid2} #last rule disllow the ip in that subnet + +# Verify if security.mac.ipacl.rules (interface wildcard) allow jail to set certain IPv4 address +exec_test ok ipv4 ${if2_jail2} '198.18.0.192' 15 ${jid2} +exec_test ok ipv4 ${if2_jail2} '198.18.132.121' 15 ${jid2} +exec_test fl ipv4 ${if2_jail2} '197.1.123.123' 15 ${jid2} +exec_test fl ipv4 ${if2_jail2} '198.18.0.12' 15 ${jid2} #last rule disllow the ip in that subnet + +sysctl security.mac.ipacl.rules=${jid1}@1@@AF_INET@169.254.0.0@16,${jid1}@0@@AF_INET@169.254.123.0@24,${jid1}@1@@AF_INET@169.254.123.123@-1,${jid1}@1@@AF_INET@198.51.100.0@24,${jid1}@0@@AF_INET@198.51.100.100@-1 >/dev/null +# Add more tests from Link-Local space and Documentation(TEST-NET-3) +exec_test ok ipv4 ${if1_jail1} '169.254.121.121' 16 ${jid1} +exec_test fl ipv4 ${if1_jail1} '169.254.123.121' 16 ${jid1} +exec_test ok ipv4 ${if1_jail1} '169.254.123.123' 16 ${jid1} +exec_test fl ipv4 ${if1_jail1} '169.253.121.121' 16 ${jid1} + +exec_test ok ipv4 ${if2_jail1} '198.51.100.001' 24 ${jid1} +exec_test ok ipv4 ${if2_jail1} '198.51.100.254' 24 ${jid1} +exec_test fl ipv4 ${if1_jail1} '198.51.100.100' 24 ${jid1} +exec_test fl ipv4 ${if1_jail1} '198.151.100.100' 24 ${jid1} + +sysctl security.mac.ipacl.ipv4=0 >/dev/null +sysctl security.mac.ipacl.rules= >/dev/null Index: sys/security/mac_ipacl/tests/ip6_test.sh =================================================================== --- /dev/null +++ sys/security/mac_ipacl/tests/ip6_test.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +dir=`dirname $0` +. ${dir}/ipacl_script.sh + +echo "1..32" +jid1=1 +jid2=5 + +if1_host="epair0a" +if1_jail1="epair0b" +if2_jail1="lo0" +if1_jail2="epair1b" +if2_jail2="lo0" + +#run this script for epair0a and epair0b as of now +#use ifconfig epair create to generate epair +#epair0a = host #epair0b = jail 1 +# make sure to create second jail(jid=2) with epair1b + +#this script also tests that host remain unaffected in all cases + +# Verify effect of changing security.mac.ipacl.ipv4 +sysctl security.mac.ipacl.ipv6=0 >/dev/null +exec_test ok ipv6 ${if1_host} '2001:db8::1111' 32 0 +exec_test ok ipv6 ${if1_jail1} '2001:db8::1112' 64 1 +exec_test ok ipv6 ${if1_host} '2001:2::abcd' 24 0 +exec_test ok ipv6 ${if1_jail1} '001:470:1e01:5ea::11' 48 1 + +sysctl security.mac.ipacl.ipv6=1 >/dev/null +sysctl security.mac.ipacl.rules= >/dev/null + +exec_test ok ipv6 ${if1_host} '2001:db8::1111' 32 0 +exec_test fl ipv6 ${if1_jail1} '2001:db8::1112' 64 1 +exec_test ok ipv6 ${if1_host} '2001:2::abcd' 24 0 +exec_test fl ipv6 ${if1_jail1} '001:470:1e01:5ea::11' 48 1 + +# rule: jid@allow@interface_name@addr_family@ip_addr@subnet_mask +sysctl security.mac.ipacl.rules=${jid1}@1@epair0b@AF_INET6@2001:db8::1111@-1,${jid2}@1@epair1b@AF_INET6@2001:2::1234:1234@-1,${jid2}@1@@AF_INET6@fe80::@32,${jid2}@0@@AF_INET6@fe80::abcd@-1 >/dev/null + +# Verify if security.mac.ipacl.rules allow jail to set certain IPv4 address +exec_test ok ipv6 ${if1_jail1} '2001:db8::1111' 16 ${jid1} +exec_test fl ipv6 ${if1_jail1} '2001:db8::1112' 16 ${jid1} +exec_test ok ipv6 ${if1_jail2} '2001:2::1234:1234' 48 ${jid2} +exec_test fl ipv6 ${if1_jail1} '2001:2::1234:1234' 48 ${jid1} + +# Verify if scurity.mac.ipacl.rules allow jail to set any address in subnet +exec_test ok ipv6 ${if1_jail2} 'FE80::1101:1221' 15 ${jid2} +exec_test ok ipv6 ${if1_jail2} 'FE80::abab' 15 ${jid2} +exec_test ok ipv6 ${if1_jail2} 'FE80::1' 64 ${jid2} +exec_test fl ipv6 ${if1_jail2} 'FE80::abcd' 15 ${jid2} #last rule disllow the ip in that subnet + +# Verify if security.mac.ipacl.rules (interface wildcard) allow jail to set certain IPv4 address +exec_test ok ipv6 ${if2_jail2} 'FE80::1101:1221' 15 ${jid2} +exec_test ok ipv6 ${if2_jail2} 'FE80::abab' 32 ${jid2} +exec_test fl ipv6 ${if2_jail2} 'FE81::1' 64 ${jid2} +exec_test fl ipv6 ${if2_jail2} 'FE80::abcd' 32 ${jid2} #last rule disllow the ip in that subnet + +#add more tests of ULA address space +#allow subnet fc00::/7 except subnet fc00::1111:22xx but allow fc00::1111:2281 +sysctl security.mac.ipacl.rules=${jid1}@1@@AF_INET6@fc00::@7,${jid1}@0@@AF_INET6@fc00::1111:2200@120,${jid1}@1@@AF_INET6@fc00::1111:2299@-1,${jid1}@1@@AF_INET6@2001:db8::@32,${jid1}@0@@AF_INET6@2001:db8::abcd@-1 >/dev/null +exec_test ok ipv6 ${if1_jail1} 'fc00::0000:1234' 48 ${jid1} +exec_test ok ipv6 ${if1_jail1} 'fc00::1112:1234' 48 ${jid1} +exec_test fl ipv6 ${if1_jail1} 'f800::2222:2200' 48 ${jid1} +exec_test fl ipv6 ${if1_jail1} 'f800::2222:22ff' 48 ${jid1} + +exec_test ok ipv6 ${if1_jail1} 'fc00::1111:2111' 64 ${jid1} +exec_test fl ipv6 ${if1_jail1} 'fc00::1111:2211' 64 ${jid1} +exec_test fl ipv6 ${if1_jail1} 'fc00::1111:22aa' 48 ${jid1} +exec_test ok ipv6 ${if1_jail1} 'fc00::1111:2299' 48 ${jid1} + +#add more tests of documentation range IPV6 +exec_test ok ipv6 ${if1_jail1} '2001:db8:abcd:bcde:cdef:def1:ef12:f123' 32 ${jid1} +exec_test ok ipv6 ${if1_jail1} '2001:db8:1111:2222:3333:4444:5555:6666' 32 ${jid1} +exec_test fl ipv6 ${if1_jail1} '2000:db9:1111:2222:3333:4444:5555:6666' 32 ${jid1} +exec_test fl ipv6 ${if2_jail1} '2001:db8::abcd' 32 ${jid1} + +sysctl security.mac.ipacl.ipv6=0 >/dev/null +sysctl security.mac.ipacl.rules= >/dev/null Index: sys/security/mac_ipacl/tests/ipacl_script.sh =================================================================== --- /dev/null +++ sys/security/mac_ipacl/tests/ipacl_script.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# $FresBSD$ + +sysctl security.mac.ipacl >/dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "1..0 # SKIP MAC_IPACL is unavailable." + exit 0 +fi + +if [ "$(id -u)" -ne 0 ]; then + echo "1..0 # SKIP testcases must be run as root" + exit 0 +fi + +ntest=1 + +test_ip() { + local proto interface address prefix jid + + proto=${1} + interface=${2} + address=${3} + prefix=${4} + jid=${5} #if jid = 0 then assume host + + if [ "${proto}" = "ipv4" ]; then + if [ "${jid}" -eq 0 ]; then + echo | ifconfig ${interface} ${address}/${prefix} up + RetVal=$? + else + echo | jexec ${jid} ifconfig ${interface} ${address}/${prefix} up + RetVal=$? + fi + elif [ "${proto}" = "ipv6" ]; then + if [ "${jid}" -eq 0 ]; then + echo | ifconfig ${interface} inet6 ${address} prefixlen ${prefix} + RetVal=$? + else + echo | jexec ${jid} ifconfig ${interface} inet6 ${address} prefixlen ${prefix} + RetVal=$? + fi + fi + if [ ${RetVal} -eq 0 ]; then + echo ok + else + echo fl + fi + +} + +exec_test() { + local expect_with_rule proto interface address prefix jid + expect_with_rule=${1} + proto=${2} + interface=${3} + address=${4} + prefix=${5} + jid=${6} + + out=$(test_ip "${proto}" "${interface}" "${address}" "${prefix}" "${jid}") + if [ "${out}" = "${expect_with_rule}" ]; then + echo "ok : PASS ${ntest}" + elif [ "${out}" = "ok" ] || [ "${out}" = "fl" ]; then + echo "not ok : FAIL ${ntest} # '${out}' != '${expect_with_rule}'" + else + echo "not ok : FAIL ${ntest} # unexpected output: '${out}'" + fi + : $(( ntest += 1 )) +}