Page MenuHomeFreeBSD

D20967.id60618.diff
No OneTemporary

D20967.id60618.diff

Index: etc/mtree/BSD.tests.dist
===================================================================
--- etc/mtree/BSD.tests.dist
+++ etc/mtree/BSD.tests.dist
@@ -777,6 +777,8 @@
mac
bsdextended
..
+ ipacl
+ ..
portacl
..
..
Index: share/man/man4/mac_ipacl.4
===================================================================
--- /dev/null
+++ share/man/man4/mac_ipacl.4
@@ -0,0 +1,165 @@
+.\" Copyright (c) 2019 Shivank Garg <shivank@FreeBSD.org>
+.\"
+.\" This code was developed as a Google Summer of Code 2019 project
+.\" under the guidance of Bjoern A. Zeeb.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 10, 2019
+.Dt MAC_IPACL 4
+.Os
+.Sh NAME
+.Nm mac_ipacl
+.Nd "IP Address access control policy"
+.Sh SYNOPSIS
+Add the following lines in your kernel configuration file for compiling the
+IP address access control policy into your kernel:
+.Bd -ragged -offset indent
+.Cd "options MAC"
+.Cd "options MAC_IPACL"
+.Ed
+.Pp
+For loading the mac_ipacl policy module at boot time,
+in your kernel configuration file add the following line:
+.Bd -ragged -offset indent
+.Cd "options MAC"
+.Ed
+.Pp
+and in
+.Xr loader.conf 5 add:
+.Pp
+.Dl "mac_ipacl_load=""YES"""
+.Sh DESCRIPTION
+The
+.Nm
+policy allows the root of the host to limit the
+.Xr VNET 9
+jail's privileges of setting IPv4 and IPv6 addresses via
+.Xr sysctl 8
+interface.
+So, the host can
+define rules for jails and their interfaces about IP addresses
+with
+.Xr sysctl 8
+MIBs.
+.Pp
+Its default behaviour is to deny all IP addresses for the jail if
+.Nm
+policy is enforced and allow/deny IP(or subnets) according to
+.Va security.mac.ipacl.rules
+string specified with
+.Xr sysctl 8
+.Ss Runtime Configuration
+The following
+.Xr sysctl 8
+MIBs are used to control enforcement and behavior of this MAC Policy.
+.Bl -tag -width indent
+.It Va security.mac.ipacl.ipv4
+Enforce
+.Nm
+for IPv4 addresses.
+(Default: 1).
+.It Va security.mac.ipacl.ipv6
+Enforce
+.Nm
+for IPv6 addresses.
+(Default: 1).
+.It Va security.mac.ipacl.rules
+The IP address access control list is specified in the following format:
+.Pp
+.Sm off
+.D1 jid @ allow @ interface @ addr_family @ IP_addr @ prefix Op , jid @ ...
+.Sm on
+.Bl -tag -width "interface"
+.It jid
+Describe the jail id of the jail for which the rule is written.
+.It allow
+1 for allow and 0 for deny.
+Decides action performed for the rule.
+.It interface
+Name of the interface the rule is enforced for.
+If the Interface is left empty then it is a wildcard to enforce the
+rule for all interfaces.
+.It addr_family
+Address family of the IP_addr.
+The input to be given as AF_INET or AF_INET6
+string only.
+.It IP_addr
+IP address(or subnet) to be allowed/deny.
+Action depends on the prefix length.
+.It prefix
+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 is calculated as subnet = IP_addr & mask.
+.El
+.El
+.Sh EXAMPLES
+Behavior of the
+.Nm
+policy module for different inputs of sysctl variable:
+.Bl -tag -width "1."
+.It 1.
+Assign ipv4=1, ipv6=0 and rules="1@1@@AF_INET@169.254.123.123@-1"
+.Pp
+It allow only 169.254.123.123 IPv4 address for all interfaces (wildcard) of jail 1.
+It allow all IPv6 address since the policy is not enforced for IPv6.
+.It 2.
+Assign ipv4=1, ipv6=1 and rules="1@1@epair0b@AF_INET6@fe80::@32,1@0@epair0b@AF_INET6@fe80::abcd@-1"
+.Pp
+It deny all IPv4 address as the 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.
+.It 3.
+Assign ipv4=1, ipv6=1, 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"
+.Pp
+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 jail 2.
+.El
+Please refer to mac/ipacl tests-framework for wide variety of examples on using
+the ipacl module.
+.Sh LIMITATIONS/PRECAUTIONS
+Rules are checked in the same sequence they are given.
+If many rules are there for an IP address (or a set of IP addresses),
+the result depends on final rule.
+.Sh FUTURE WORKS
+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.
+.Sh SEE ALSO
+.Xr mac 4 ,
+.Xr mac 9
+.Sh AUTHORS
+The
+.Nm
+policy module was developed as a Google Summer of Code Project in 2019
+by
+.An -nosplit
+.An "Shivank Garg" Aq Mt shivank@FreeBSD.org
+under the guidance of
+.An "Bjoern A. Zeeb" Aq Mt bz@FreeBSD.org .
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -4843,6 +4843,7 @@
security/mac_bsdextended/ugidfw_system.c optional mac_bsdextended
security/mac_bsdextended/ugidfw_vnode.c optional mac_bsdextended
security/mac_ifoff/mac_ifoff.c optional mac_ifoff
+security/mac_ipacl/mac_ipacl.c optional mac_ipacl
security/mac_lomac/mac_lomac.c optional mac_lomac
security/mac_mls/mac_mls.c optional mac_mls
security/mac_none/mac_none.c optional mac_none
Index: sys/modules/Makefile
===================================================================
--- sys/modules/Makefile
+++ sys/modules/Makefile
@@ -215,6 +215,7 @@
mac_biba \
mac_bsdextended \
mac_ifoff \
+ mac_ipacl \
mac_lomac \
mac_mls \
mac_none \
Index: sys/modules/mac_ipacl/Makefile
===================================================================
--- /dev/null
+++ sys/modules/mac_ipacl/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/security/mac_ipacl
+
+KMOD= mac_ipacl
+SRCS= mac_ipacl.c
+SRCS+= opt_inet.h opt_inet6.h
+
+.include <bsd.kmod.mk>
Index: sys/netinet/in.c
===================================================================
--- sys/netinet/in.c
+++ sys/netinet/in.c
@@ -72,6 +72,10 @@
#include <netinet/udp.h>
#include <netinet/udp_var.h>
+#ifdef MAC
+#include <security/mac/mac_framework.h>
+#endif
+
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 +376,15 @@
/*
* See whether address already exist.
*/
+
+#ifdef MAC
+ /* Check if a MAC policy disallows setting the IPv4 address. */
+ 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,9 @@
#include <netinet6/in6_fib.h>
#include <netinet6/in6_pcb.h>
+#ifdef MAC
+#include <security/mac/mac_framework.h>
+#endif
/*
* struct in6_ifreq and struct ifreq must be type punnable for common members
@@ -557,6 +560,13 @@
struct nd_prefixctl pr0;
struct nd_prefix *pr;
+#ifdef MAC
+ /* Check if a MAC policy disallows setting the IPv6 address. */
+ 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 <sys/acl.h> /* XXX acl_type_t */
#include <sys/types.h> /* accmode_t */
@@ -153,6 +156,12 @@
int mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr,
struct ifnet *ifp);
+/* Check if the IP address is allowed for the 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);
void mac_inpcb_create(struct socket *so, 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,17 @@
return (0);
}
+/* Check with rules in module if the IPv4 address is allowed. */
+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,17 @@
q6->ip6q_label);
}
+/* Check with rules in module if the IPv6 address is allowed. */
+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,12 @@
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 +755,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/mac_ipacl.c
===================================================================
--- /dev/null
+++ sys/security/mac_ipacl/mac_ipacl.c
@@ -0,0 +1,473 @@
+/*-
+ * Copyright (c) 2003-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2019 Shivank Garg <shivank@FreeBSD.org>
+ *
+ * This software was developed for the FreeBSD Project by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * This code was developed as a Google Summer of Code 2019 project
+ * under the guidance of Bjoern A. Zeeb.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * The IP address access control policy module - 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.
+ * sysctl(8) is to be used to modify the rules string in following format-
+ * "jail_id@allow@interface@address_family@IP_addr@prefix_length[,jail_id@...]"
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/ucred.h>
+#include <sys/jail.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet6/scope6_var.h>
+
+#include <security/mac/mac_policy.h>
+
+SYSCTL_DECL(_security_mac);
+
+static SYSCTL_NODE(_security_mac, OID_AUTO, ipacl, CTLFLAG_RW, 0,
+ "TrustedBSD mac_ipacl policy controls");
+
+#ifdef INET
+static int ipacl_ipv4 = 1;
+SYSCTL_INT(_security_mac_ipacl, OID_AUTO, ipv4, CTLFLAG_RWTUN,
+ &ipacl_ipv4, 0, "Enforce mac_ipacl for IPv4 addresses");
+#endif
+
+#ifdef INET6
+static int ipacl_ipv6 = 1;
+SYSCTL_INT(_security_mac_ipacl, OID_AUTO, ipv6, CTLFLAG_RWTUN,
+ &ipacl_ipv6, 0, "Enforce mac_ipacl for IPv6 addresses");
+#endif
+
+static MALLOC_DEFINE(M_IPACL, "ipacl_rule", "Rules for mac_ipacl");
+
+#define MAC_RULE_STRING_LEN 1024
+
+struct ipacl_addr {
+ union {
+#ifdef INET
+ struct in_addr ipv4;
+#endif
+#ifdef INET6
+ struct in6_addr ipv6;
+#endif
+ u_int8_t addr8[16];
+ u_int16_t addr16[8];
+ u_int32_t addr32[4];
+ } ipa; /* 128 bit address*/
+#ifdef INET
+#define v4 ipa.ipv4
+#endif
+#ifdef INET6
+#define v6 ipa.ipv6
+#endif
+#define addr8 ipa.addr8
+#define addr16 ipa.addr16
+#define addr32 ipa.addr32
+};
+
+struct ip_rule {
+ int jid;
+ bool allow;
+ bool subnet_apply; /* Apply rule on whole subnet. */
+ char if_name[IFNAMSIZ];
+ int af; /* Address family. */
+ struct ipacl_addr addr;
+ struct ipacl_addr mask;
+ TAILQ_ENTRY(ip_rule) r_entries;
+};
+
+static struct mtx rule_mtx;
+static TAILQ_HEAD(rulehead, ip_rule) rule_head;
+static char rule_string[MAC_RULE_STRING_LEN];
+
+static void
+destroy_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);
+ destroy_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);
+ /* Should we support a jail wildcard? */
+ jid = strsep(&element, "@");
+ if (jid == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ 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) > IFNAMSIZ) {
+ error = EINVAL;
+ goto out;
+ }
+ /* Empty interface name is wildcard to all interfaces. */
+ bzero(new->if_name, IFNAMSIZ);
+ 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;
+ }
+ /* Value -1 for prefix make policy applicable to individual IP only. */
+ if (prefix == -1)
+ new->subnet_apply = false;
+ else {
+ new->subnet_apply = true;
+ switch (new->af) {
+#ifdef INET
+ case 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));
+ new->addr.addr32[0] &= new->mask.addr32[0];
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (prefix < 0 || prefix > 128) {
+ error = EINVAL;
+ goto out;
+ }
+ for (i = 0; prefix > 0; prefix -= 8, i++)
+ new->mask.addr8[i] = prefix >= 8 ? 0xFF :
+ (u_int8_t)((0xFFU << (8 - prefix)) & 0xFFU);
+ for (i=0; i<16; i++)
+ new->addr.addr8[i] &= new->mask.addr8[i];
+ break;
+#endif
+ }
+ }
+out:
+ if (error != 0) {
+ free(new, M_IPACL);
+ *rule = NULL;
+ } else
+ *rule = new;
+ return (error);
+}
+
+/*
+ * Format of Rule- jid@allow@interface_name@addr_family@ip_addr@subnet_mask
+ * Example: sysctl security.mac.ipacl.rules=1@1@epair0b@AF_INET@192.0.2.2@24
+ */
+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)
+ destroy_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);
+ destroy_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");
+
+static int
+rules_check(struct ucred *cred,
+ struct ipacl_addr *ip_addr, struct ifnet *ifp)
+{
+ struct ip_rule *rule;
+ int error, i;
+ bool same_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 applies to 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) {
+#ifdef INET
+ case AF_INET:
+ if (rule->subnet_apply) {
+ if (rule->addr.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;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (rule->subnet_apply) {
+ same_subnet=true;
+ for (i=0 ; i<16 ; i++)
+ if (rule->addr.v6.s6_addr[i] !=
+ (ip_addr->v6.s6_addr[i] &
+ rule->mask.v6.s6_addr[i])) {
+ same_subnet=false;
+ break;
+ }
+ if (!same_subnet)
+ continue;
+ } else
+ if (bcmp(&rule->addr, ip_addr,
+ sizeof(*ip_addr)))
+ continue;
+ break;
+#endif
+ }
+
+ if (rule->allow)
+ error = 0;
+ else
+ error = EPERM;
+ }
+
+ mtx_unlock(&rule_mtx);
+
+ return (error);
+}
+
+/* Feature request: Can we make this a sysctl policy as well defaulting
+ * to jails only, but if changed also applying to the base system?
+ */
+#ifdef INET
+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;
+
+ if (!jailed(cred))
+ return 0;
+
+ /* Checks with the policy only when it is enforced for ipv4. */
+ if (ipacl_ipv4)
+ return rules_check(cred, &ip4_addr, ifp);
+
+ return 0;
+}
+#endif
+
+#ifdef INET6
+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 the scope id. */
+
+ if (!jailed(cred))
+ return 0;
+
+ /* Checks with the policy when it is enforced for ipv6. */
+ if (ipacl_ipv6)
+ return rules_check(cred, &ip6_addr, ifp);
+
+ return 0;
+}
+#endif
+
+static struct mac_policy_ops ipacl_ops =
+{
+ .mpo_init = ipacl_init,
+ .mpo_destroy = ipacl_destroy,
+#ifdef INET
+ .mpo_ip4_check_jail = ipacl_ip4_check_jail,
+#endif
+#ifdef INET6
+ .mpo_ip6_check_jail = ipacl_ip6_check_jail,
+#endif
+};
+
+MAC_POLICY_SET(&ipacl_ops, mac_ipacl, "TrustedBSD MAC/ipacl",
+ MPC_LOADTIME_FLAG_UNLOADOK, NULL);
Index: tests/sys/mac/Makefile
===================================================================
--- tests/sys/mac/Makefile
+++ tests/sys/mac/Makefile
@@ -3,6 +3,7 @@
TESTSDIR= ${TESTSBASE}/sys/mac
TESTS_SUBDIRS+= bsdextended
+TESTS_SUBDIRS+= ipacl
TESTS_SUBDIRS+= portacl
.include <bsd.test.mk>
Index: tests/sys/mac/ipacl/Makefile
===================================================================
--- /dev/null
+++ tests/sys/mac/ipacl/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/sys/mac/ipacl
+
+ATF_TESTS_SH+= ipacl_test
+
+${PACKAGE}FILES+= utils.subr
+
+.include <bsd.test.mk>
Index: tests/sys/mac/ipacl/ipacl_test.sh
===================================================================
--- /dev/null
+++ tests/sys/mac/ipacl/ipacl_test.sh
@@ -0,0 +1,283 @@
+#-
+# Copyright (c) 2019 Shivank Garg <shivank@FreeBSD.org>
+#
+# This code was developed as a Google Summer of Code 2019 project
+# under the guidance of Bjoern A. Zeeb.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+. $(atf_get_srcdir)/utils.subr
+
+atf_test_case "ipacl_v4" "cleanup"
+
+ipacl_v4_head()
+{
+ atf_set descr 'basic test for ipacl on IPv4 addresses'
+ atf_set require.user root
+}
+
+ipacl_v4_body()
+{
+ ipacl_test_init
+
+ epairA=$(vnet_mkepair)
+ epairB=$(vnet_mkepair)
+ epairC=$(vnet_mkepair)
+
+ vnet_mkjail A ${epairA}b
+ vnet_mkjail B ${epairB}b ${epairC}b
+
+ jidA=$(jls -j A -s jid | grep -o -E '[0-9]+')
+ jidB=$(jls -j B -s jid | grep -o -E '[0-9]+')
+
+ # The ipacl policy module is not enforced for IPv4.
+ sysctl security.mac.ipacl.ipv4=0
+
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 192.0.2.2/24 up
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 203.0.113.254/24 up
+
+ # The ipacl policy module is enforced for IPv4 and prevent all
+ # jails from setting their IPv4 address.
+ sysctl security.mac.ipacl.ipv4=1
+ sysctl security.mac.ipacl.rules=
+
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 192.0.2.2/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 203.0.113.254/24 up
+
+ rule="${jidA}@1@${epairA}b@AF_INET@192.0.2.42@-1,"
+ rule="${rule}${jidB}@1@${epairB}b@AF_INET@198.51.100.12@-1,"
+ rule="${rule}${jidB}@1@@AF_INET@203.0.113.1@24,"
+ rule="${rule}${jidB}@0@@AF_INET@203.0.113.9@-1"
+ sysctl security.mac.ipacl.rules="${rule}"
+
+ # Verify if it allows jail to set only certain IPv4 address.
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 192.0.2.42/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 192.0.2.43/24 up
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b 198.51.100.12/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b 198.51.100.12/24 up
+
+ # Verify if the module allow jail to set any address in subnet.
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b 203.0.113.19/24 up
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b 203.0.113.241/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b 198.18.0.1/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b 203.0.113.9/24 up
+
+ # Check wildcard for interfaces.
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b 203.0.113.20/24 up
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b 203.0.113.242/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b 198.18.0.1/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b 203.0.113.9/24 up
+
+ rule="${jidA}@1@@AF_INET@198.18.0.0@15,"
+ rule="${rule}${jidA}@0@@AF_INET@198.18.23.0@24,"
+ rule="${rule}${jidA}@1@@AF_INET@198.18.23.1@-1,"
+ rule="${rule}${jidA}@1@@AF_INET@198.51.100.0@24,"
+ rule="${rule}${jidA}@0@@AF_INET@198.51.100.100@-1"
+ sysctl security.mac.ipacl.rules="${rule}"
+
+ # Tests from Benchamarking and Documentation(TEST-NET-3).
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 198.18.0.1/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 198.18.23.2/24 up
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 198.18.23.1/22 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 198.18.23.3/24 up
+
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 198.51.100.001/24 up
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 198.51.100.254/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 198.51.100.100/24 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b 203.0.113.1/24 up
+
+ # Reset rules OID.
+ sysctl security.mac.ipacl.rules=
+}
+
+ipacl_v4_cleanup()
+{
+ ipacl_test_cleanup
+}
+
+atf_test_case "ipacl_v6" "cleanup"
+
+ipacl_v6_head()
+{
+ atf_set descr 'basic test for ipacl on IPv6 addresses'
+ atf_set require.user root
+}
+
+ipacl_v6_body()
+{
+ ipacl_test_init
+
+ epairA=$(vnet_mkepair)
+ epairB=$(vnet_mkepair)
+ epairC=$(vnet_mkepair)
+
+ vnet_mkjail A ${epairA}b
+ vnet_mkjail B ${epairB}b ${epairC}b
+
+ jidA=$(jls -j A -s jid | grep -o -E '[0-9]+')
+ jidB=$(jls -j B -s jid | grep -o -E '[0-9]+')
+
+ # The ipacl policy module is not enforced for IPv6.
+ sysctl security.mac.ipacl.ipv6=0
+
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 2001:2::abcd/48 up
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 2001:2::5ea:11/48 up
+
+ # The ipacl policy module is enforced for IPv6 and prevent all
+ # jails from setting their IPv6 address.
+ sysctl security.mac.ipacl.ipv6=1
+ sysctl security.mac.ipacl.rules=
+
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 2001:2::abcd/48 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 2001:2::5ea:11/48 up
+
+ rule="${jidA}@1@${epairA}b@AF_INET6@2001:db8::1111@-1,"
+ rule="${rule}${jidB}@1@${epairB}b@AF_INET6@2001:2::1234:1234@-1,"
+ rule="${rule}${jidB}@1@@AF_INET6@fe80::@32,"
+ rule="${rule}${jidB}@0@@AF_INET6@fe80::abcd@-1"
+ sysctl security.mac.ipacl.rules="${rule}"
+
+ # Verify if it allows jail to set only certain IPv6 address.
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 2001:db8::1111/64 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 2001:db8::1112/64 up
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b inet6 2001:2::1234:1234/48 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 2001:2::1234:1234/48 up
+
+ # Verify if the module allow jail set any address in subnet.
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b inet6 FE80::1101:1221/15 up
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b inet6 FE80::abab/15 up
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b inet6 FE80::1/64 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairB}b inet6 FE80::abcd/15 up
+
+ # Check wildcard for interfaces.
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b inet6 FE80::1101:1221/15 up
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b inet6 FE80::abab/32 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b inet6 FE81::1/64 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b inet6 FE80::abcd/32 up
+
+
+ rule="${jidB}@1@@AF_INET6@2001:2::@48,"
+ rule="${rule}${jidB}@1@@AF_INET6@2001:3::@32"
+ sysctl security.mac.ipacl.rules="${rule}"
+
+ # Tests when subnet is allowed.
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b inet6 2001:2:0001::1/64 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b inet6 2001:2:1000::1/32 up
+ atf_check -s exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b inet6 2001:3:0001::1/64 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec B ifconfig ${epairC}b inet6 2001:4::1/64 up
+
+ # More tests of ULA address space.
+ rule="${jidA}@1@@AF_INET6@fc00::@7,"
+ rule="${rule}${jidA}@0@@AF_INET6@fc00::1111:2200@120,"
+ rule="${rule}${jidA}@1@@AF_INET6@fc00::1111:2299@-1,"
+ rule="${rule}${jidA}@1@@AF_INET6@2001:db8::@32,"
+ rule="${rule}${jidA}@0@@AF_INET6@2001:db8::abcd@-1"
+ sysctl security.mac.ipacl.rules="${rule}"
+
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 fc00::0000:1234/48 up
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 fc00::0000:1234/48 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 f800::2222:2200/48 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 f800::2222:22ff/48 up
+
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 fc00::1111:2111/64 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 fc00::1111:2211/64 up
+ atf_check -s not-exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 fc00::1111:22aa/48 up
+ atf_check -s exit:0 -e ignore \
+ jexec A ifconfig ${epairA}b inet6 fc00::1111:2299/48 up
+
+ # More tests from IPv6 documentation range.
+ atf_check -s exit:0 -e ignore jexec A ifconfig \
+ ${epairA}b inet6 2001:db8:abcd:bcde:cdef:def1:ef12:f123/32 up
+ atf_check -s exit:0 -e ignore jexec A ifconfig \
+ ${epairA}b inet6 2001:db8:1111:2222:3333:4444:5555:6666/32 up
+ atf_check -s not-exit:0 -e ignore jexec A ifconfig \
+ ${epairA}b inet6 2001:ab9:1111:2222:3333:4444:5555:6666/32 up
+ atf_check -s not-exit:0 -e ignore jexec A ifconfig \
+ ${epairA}b inet6 2001:db8::abcd/32 up
+
+ # Reset rules OID.
+ sysctl security.mac.ipacl.rules=
+}
+
+ipacl_v6_cleanup()
+{
+ ipacl_test_cleanup
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case "ipacl_v4"
+ atf_add_test_case "ipacl_v6"
+}
Index: tests/sys/mac/ipacl/utils.subr
===================================================================
--- /dev/null
+++ tests/sys/mac/ipacl/utils.subr
@@ -0,0 +1,18 @@
+# $FreeBSD$
+# Utility functions for mac_ipacl tests
+
+. $(atf_get_srcdir)/../../common/vnet.subr
+
+ipacl_test_init()
+{
+ vnet_init
+
+ if ! kldstat -q -m mac_ipacl; then
+ atf_skip "mac_ipacl is not loaded"
+ fi
+}
+
+ipacl_test_cleanup()
+{
+ vnet_cleanup
+}

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 22, 10:23 AM (14 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27841638
Default Alt Text
D20967.id60618.diff (34 KB)

Event Timeline