Hi Folks, Below is an updated patch for IP layer networking against the current bk repository. The main changes are that the fragmentation and en/decapsulation hooks have been moved here from the skb hook code, and the addition of a new hook for defragmentation. The latter is a simple hook for defragmentation which is called when an incoming fragment is about to be inserted into a reassembly queue. Its purpose is to enable the validation of security attributes for each fragment. Due to the way that the defragmentation code is encapsulated, it is difficult to access the actual fragment queue itself. I don't think we absolutely need to however, as we can catch each fragment as it is about to be queued and maintain relevant state within the LSM module. An LSM module which uses this hook will need to expire fragment information and implement DoS countermeasures. I'd recommend that we initially try to use this simple defragmentation hook, rather than implement a significantly more invasive approach. Another issue is that we now have a few ip_ops hooks that do not use Netfilter. I don't think that we can demand that every LSM implementation to enable Netfilter, or TCP/IP networking, so we may need to make TCP/IP networking support for LSM a configurable kernel option. If we did this, it would mean using macros for the relevant hooks, which would probably also make the code more palatable to the core networking maintainers. Any thoughts on this issue, and the patch, are most welcome. - James -- James Morris <jmorrisat_private> diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/include/linux/security.h lsm-w2/include/linux/security.h --- lsm/include/linux/security.h Wed Jul 25 11:34:53 2001 +++ lsm-w2/include/linux/security.h Thu Jul 26 00:47:15 2001 @@ -125,6 +125,28 @@ struct socket_security_ops { }; +struct sk_buff; +struct net_device; +typedef unsigned int (*ip_opfn)(unsigned int hooknum, struct sk_buff **skb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)); +struct ip_security_ops { + ip_opfn preroute_first; + ip_opfn preroute_last; + ip_opfn input_first; + ip_opfn input_last; + ip_opfn forward_first; + ip_opfn forward_last; + ip_opfn output_first; + ip_opfn output_last; + ip_opfn postroute_first; + ip_opfn postroute_last; + void (* fragment) (struct sk_buff *newskb, const struct sk_buff *oldskb); + int (* defragment) (struct sk_buff *skb); + void (* encapsulate) (struct sk_buff *skb); + void (* decapsulate) (struct sk_buff *skb); +}; + struct module_security_ops { int (* create_module) (const char *name_user, size_t size); int (* init_module) (const char *name_user, struct module *mod_user); @@ -198,6 +220,7 @@ struct file_security_ops * file_ops; struct task_security_ops * task_ops; struct socket_security_ops * socket_ops; + struct ip_security_ops * ip_ops; struct module_security_ops * module_ops; struct ipc_security_ops * ipc_ops; struct msg_msg_security_ops * msg_msg_ops; diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/kernel/Makefile lsm-w2/kernel/Makefile --- lsm/kernel/Makefile Thu Jun 28 04:01:57 2001 +++ lsm-w2/kernel/Makefile Wed Jul 25 23:20:49 2001 @@ -22,6 +22,8 @@ obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_CAPABILITIES) += capability_plug.o +obj-$(CONFIG_LSM_IP) += lsm_ip_glue.o + ifneq ($(CONFIG_IA64),y) # According to Alan Modra <alanat_private>, the -fno-omit-frame-pointer is # needed for x86 only. Why this used to be enabled for all architectures is beyond diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/kernel/capability_plug.c lsm-w2/kernel/capability_plug.c --- lsm/kernel/capability_plug.c Wed Jul 25 11:34:54 2001 +++ lsm-w2/kernel/capability_plug.c Thu Jul 26 01:17:06 2001 @@ -19,6 +19,7 @@ #include <linux/slab.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> +#include <linux/netfilter.h> /* flag to keep track of how we were registered */ static int secondary; @@ -296,6 +297,41 @@ return; } +static unsigned int cap_ip_preroute_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_preroute_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_input_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_input_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_forward_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_forward_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_output_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_output_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_postroute_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int cap_ip_postroute_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static void cap_ip_fragment (struct sk_buff *newskb, const struct sk_buff *oldskb) {return;} +static int cap_ip_defragment (struct sk_buff *skb) {return 0;} +static void cap_ip_decapsulate (struct sk_buff *skb) {return;} +static void cap_ip_encapsulate (struct sk_buff *skb) {return;} + static int cap_module_create_module (const char *name_user, size_t size) {return 0;} static int cap_module_init_module (const char *name_user, struct module *mod_user) {return 0;} static int cap_module_delete_module (const char *name_user) {return 0;} @@ -406,6 +442,23 @@ static struct socket_security_ops cap_socket_ops = {}; +static struct ip_security_ops cap_ip_ops = { + preroute_first: cap_ip_preroute_first, + preroute_last: cap_ip_preroute_last, + input_first: cap_ip_input_first, + input_last: cap_ip_input_last, + forward_first: cap_ip_forward_first, + forward_last: cap_ip_forward_last, + output_first: cap_ip_output_first, + output_last: cap_ip_output_last, + postroute_first: cap_ip_postroute_first, + postroute_last: cap_ip_postroute_last, + fragment: cap_ip_fragment, + defragment: cap_ip_defragment, + encapsulate: cap_ip_encapsulate, + decapsulate: cap_ip_encapsulate, +}; + static struct module_security_ops cap_module_ops = { create_module: cap_module_create_module, init_module: cap_module_init_module, @@ -477,6 +530,7 @@ file_ops: &cap_file_ops, task_ops: &cap_task_ops, socket_ops: &cap_socket_ops, + ip_ops: &cap_ip_ops, module_ops: &cap_module_ops, ipc_ops: &cap_ipc_ops, msg_msg_ops: &cap_msg_ops, diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/kernel/lsm_ip_glue.c lsm-w2/kernel/lsm_ip_glue.c --- lsm/kernel/lsm_ip_glue.c Thu Jan 1 10:00:00 1970 +++ lsm-w2/kernel/lsm_ip_glue.c Wed Jul 25 23:20:12 2001 @@ -0,0 +1,152 @@ +/* + * Nefilter IPv4 Operations Glue Module for LSM + * + * Copyright (c) 2001 James Morris <jmorrisat_private> + * This code is GPL. + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/security.h> +#include <linux/netfilter.h> +#include <linux/netfilter_ipv4.h> + +#define NF_IP_PRI_LSM_FIRST (NF_IP_PRI_FIRST + 20) +#define NF_IP_PRI_LSM_LAST (NF_IP_PRI_LAST - 20) + +static unsigned int +preroute_first(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->preroute_first(hooknum, pskb, in, out, okfn); +} + +static unsigned int +preroute_last(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->preroute_last(hooknum, pskb, in, out, okfn); +} + +static unsigned int +input_first(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->input_first(hooknum, pskb, in, out, okfn); +} + +static unsigned int +input_last(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->input_last(hooknum, pskb, in, out, okfn); +} + +static unsigned int +forward_first(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->forward_first(hooknum, pskb, in, out, okfn); +} + +static unsigned int +forward_last(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->forward_last(hooknum, pskb, in, out, okfn); +} + +static unsigned int +output_first(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->output_first(hooknum, pskb, in, out, okfn); +} + +static unsigned int +output_last(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->output_last(hooknum, pskb, in, out, okfn); +} + +static unsigned int +postroute_first(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->postroute_first(hooknum, pskb, in, out, okfn); +} + +static unsigned int +postroute_last(unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return security_ops->ip_ops->postroute_last(hooknum, pskb, in, out, okfn); +} + +static struct nf_hook_ops lsm_ip_ops[] = { + { { NULL, NULL }, preroute_first, + PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_LSM_FIRST }, + + { { NULL, NULL }, preroute_last, + PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_LSM_LAST }, + + { { NULL, NULL }, input_first, + PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LSM_FIRST }, + + { { NULL, NULL }, input_last, + PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LSM_LAST }, + + { { NULL, NULL }, forward_first, + PF_INET, NF_IP_FORWARD, NF_IP_PRI_LSM_FIRST }, + + { { NULL, NULL }, forward_last, + PF_INET, NF_IP_FORWARD, NF_IP_PRI_LSM_LAST }, + + { { NULL, NULL }, output_first, + PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_LSM_FIRST }, + + { { NULL, NULL }, output_last, + PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_LSM_LAST }, + + { { NULL, NULL }, postroute_first, + PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_LSM_FIRST }, + + { { NULL, NULL }, postroute_last, + PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_LSM_LAST } +}; + +static int __init init(void) +{ + int i; + + /* Hook registration never returns error (for now) */ + for (i = 0; i < sizeof(lsm_ip_ops)/sizeof(struct nf_hook_ops); i++) + nf_register_hook(&lsm_ip_ops[i]); + + return 0; +} + +static void __exit fini(void) +{ + unsigned int i; + + for (i = 0; i < sizeof(lsm_ip_ops)/sizeof(struct nf_hook_ops); i++) + nf_unregister_hook(&lsm_ip_ops[i]); +} + +module_init(init); +module_exit(fini); + +MODULE_DESCRIPTION("Nefilter IPv4 Operations Glue for Linux Security Module"); + diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/kernel/security.c lsm-w2/kernel/security.c --- lsm/kernel/security.c Wed Jul 25 11:34:54 2001 +++ lsm-w2/kernel/security.c Thu Jul 26 00:51:52 2001 @@ -30,7 +30,7 @@ #include <linux/module.h> #include <linux/sysctl.h> - +#include <linux/netfilter.h> @@ -133,6 +133,42 @@ static void dummy_task_kmod_set_label (void) {return;} + +static unsigned int dummy_ip_preroute_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_preroute_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_input_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_input_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_forward_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_forward_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_output_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_output_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_postroute_first (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static unsigned int dummy_ip_postroute_last (unsigned int hooknum, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) {return NF_ACCEPT;} +static void dummy_ip_fragment (struct sk_buff *newskb, const struct sk_buff *oldskb) {return;} +static int dummy_ip_defragment (struct sk_buff *skb) {return 0;} +static void dummy_ip_decapsulate (struct sk_buff *skb) {return;} +static void dummy_ip_encapsulate (struct sk_buff *skb) {return;} + static int dummy_module_create_module (const char *name_user, size_t size) {return 0;} static int dummy_module_init_module (const char *name_user, struct module *mod_user) {return 0;} static int dummy_module_delete_module (const char *name_user) {return 0;} @@ -241,6 +277,23 @@ static struct socket_security_ops dummy_socket_ops = {}; +static struct ip_security_ops dummy_ip_ops = { + preroute_first: dummy_ip_preroute_first, + preroute_last: dummy_ip_preroute_last, + input_first: dummy_ip_input_first, + input_last: dummy_ip_input_last, + forward_first: dummy_ip_forward_first, + forward_last: dummy_ip_forward_last, + output_first: dummy_ip_output_first, + output_last: dummy_ip_output_last, + postroute_first: dummy_ip_postroute_first, + postroute_last: dummy_ip_postroute_last, + fragment: dummy_ip_fragment, + defragment: dummy_ip_defragment, + encapsulate: dummy_ip_encapsulate, + decapsulate: dummy_ip_decapsulate, +}; + static struct module_security_ops dummy_module_ops = { create_module: dummy_module_create_module, init_module: dummy_module_init_module, @@ -312,6 +365,7 @@ file_ops: &dummy_file_ops, task_ops: &dummy_task_ops, socket_ops: &dummy_socket_ops, + ip_ops: &dummy_ip_ops, ipc_ops: &dummy_ipc_ops, module_ops: &dummy_module_ops, msg_msg_ops: &dummy_msg_msg_ops, @@ -382,6 +436,7 @@ !ops->file_ops || !ops->task_ops || !ops->socket_ops || + !ops->ip_ops || !ops->module_ops || !ops->ipc_ops || !ops->msg_msg_ops || diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/net/ipv4/ip_fragment.c lsm-w2/net/ipv4/ip_fragment.c --- lsm/net/ipv4/ip_fragment.c Thu Jun 28 04:02:01 2001 +++ lsm-w2/net/ipv4/ip_fragment.c Thu Jul 26 00:36:27 2001 @@ -37,6 +37,7 @@ #include <linux/udp.h> #include <linux/inet.h> #include <linux/netfilter_ipv4.h> +#include <linux/security.h> /* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6 * code now. If you change something here, _PLEASE_ update ipv6/reassembly.c @@ -372,8 +373,12 @@ { struct sk_buff *prev, *next; int flags, offset; - int ihl, end; + int ihl, end, ret; + ret = security_ops->ip_ops->defragment(skb); + if (ret) + goto err; + if (qp->last_in & COMPLETE) goto err; diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/net/ipv4/ip_gre.c lsm-w2/net/ipv4/ip_gre.c --- lsm/net/ipv4/ip_gre.c Thu Jun 28 04:02:01 2001 +++ lsm-w2/net/ipv4/ip_gre.c Thu Jul 26 01:05:01 2001 @@ -655,6 +655,7 @@ skb->nf_debug = 0; #endif #endif + security_ops->ip_ops->decapsulate(skb); ipgre_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipgre_lock); @@ -884,7 +885,8 @@ skb->nf_debug = 0; #endif #endif - + security_ops->ip_ops->encapsulate(skb); + IPTUNNEL_XMIT(); tunnel->recursion--; return 0; diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/net/ipv4/ip_output.c lsm-w2/net/ipv4/ip_output.c --- lsm/net/ipv4/ip_output.c Wed Jul 25 11:35:03 2001 +++ lsm-w2/net/ipv4/ip_output.c Thu Jul 26 01:03:34 2001 @@ -859,6 +859,7 @@ skb2->nf_debug = skb->nf_debug; #endif #endif + security_ops->ip_ops->fragment(skb2, skb); /* * Put this fragment into the sending queue. diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/net/ipv4/ipip.c lsm-w2/net/ipv4/ipip.c --- lsm/net/ipv4/ipip.c Thu Jun 28 04:02:01 2001 +++ lsm-w2/net/ipv4/ipip.c Thu Jul 26 01:04:45 2001 @@ -500,6 +500,7 @@ skb->nf_debug = 0; #endif #endif + security_ops->ip_ops->decapsulate(skb); ipip_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipip_lock); @@ -647,6 +648,8 @@ skb->nf_debug = 0; #endif #endif + + security_ops->ip_ops->encapsulate(skb); IPTUNNEL_XMIT(); tunnel->recursion--; diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/net/ipv4/ipmr.c lsm-w2/net/ipv4/ipmr.c --- lsm/net/ipv4/ipmr.c Wed Jul 25 11:35:03 2001 +++ lsm-w2/net/ipv4/ipmr.c Thu Jul 26 01:04:55 2001 @@ -1104,6 +1104,7 @@ nf_conntrack_put(skb->nfct); skb->nfct = NULL; #endif + security_ops->ip_ops->encapsulate(skb); } static inline int ipmr_forward_finish(struct sk_buff *skb) @@ -1449,6 +1450,7 @@ nf_conntrack_put(skb->nfct); skb->nfct = NULL; #endif + security_ops->ip_ops->decapsulate(skb); netif_rx(skb); dev_put(reg_dev); return 0; @@ -1516,6 +1518,7 @@ nf_conntrack_put(skb->nfct); skb->nfct = NULL; #endif + security_ops->ip_ops->decapsulate(skb); netif_rx(skb); dev_put(reg_dev); return 0; diff -urN --exclude SCCS --exclude BitKeeper --exclude ChangeSet lsm/security/Config.in lsm-w2/security/Config.in --- lsm/security/Config.in Thu Jul 5 15:28:18 2001 +++ lsm-w2/security/Config.in Wed Jul 25 23:39:42 2001 @@ -4,5 +4,5 @@ mainmenu_option next_comment comment 'Security options' tristate 'Capabilities Support' CONFIG_CAPABILITIES - +dep_tristate 'IP Networking Support' CONFIG_LSM_IP $CONFIG_NETFILTER endmenu _______________________________________________ linux-security-module mailing list linux-security-moduleat_private http://mail.wirex.com/mailman/listinfo/linux-security-module
This archive was generated by hypermail 2b30 : Wed Jul 25 2001 - 08:55:59 PDT