15e6874cdSJames Morris /* 25e6874cdSJames Morris * Module for modifying the secmark field of the skb, for use by 35e6874cdSJames Morris * security subsystems. 45e6874cdSJames Morris * 55e6874cdSJames Morris * Based on the nfmark match by: 65e6874cdSJames Morris * (C) 1999-2001 Marc Boucher <marc@mbsi.ca> 75e6874cdSJames Morris * 85e6874cdSJames Morris * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com> 95e6874cdSJames Morris * 105e6874cdSJames Morris * This program is free software; you can redistribute it and/or modify 115e6874cdSJames Morris * it under the terms of the GNU General Public License version 2 as 125e6874cdSJames Morris * published by the Free Software Foundation. 135e6874cdSJames Morris * 145e6874cdSJames Morris */ 155e6874cdSJames Morris #include <linux/module.h> 165e6874cdSJames Morris #include <linux/skbuff.h> 175e6874cdSJames Morris #include <linux/selinux.h> 185e6874cdSJames Morris #include <linux/netfilter/x_tables.h> 195e6874cdSJames Morris #include <linux/netfilter/xt_SECMARK.h> 205e6874cdSJames Morris 215e6874cdSJames Morris MODULE_LICENSE("GPL"); 225e6874cdSJames Morris MODULE_AUTHOR("James Morris <jmorris@redhat.com>"); 232ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: packet security mark modification"); 245e6874cdSJames Morris MODULE_ALIAS("ipt_SECMARK"); 255e6874cdSJames Morris MODULE_ALIAS("ip6t_SECMARK"); 265e6874cdSJames Morris 275e6874cdSJames Morris #define PFX "SECMARK: " 285e6874cdSJames Morris 295e6874cdSJames Morris static u8 mode; 305e6874cdSJames Morris 31d3c5ee6dSJan Engelhardt static unsigned int 32d3c5ee6dSJan Engelhardt secmark_tg(struct sk_buff *skb, const struct net_device *in, 335e6874cdSJames Morris const struct net_device *out, unsigned int hooknum, 34d3c5ee6dSJan Engelhardt const struct xt_target *target, const void *targinfo) 355e6874cdSJames Morris { 365e6874cdSJames Morris u32 secmark = 0; 375e6874cdSJames Morris const struct xt_secmark_target_info *info = targinfo; 385e6874cdSJames Morris 395e6874cdSJames Morris BUG_ON(info->mode != mode); 405e6874cdSJames Morris 415e6874cdSJames Morris switch (mode) { 425e6874cdSJames Morris case SECMARK_MODE_SEL: 435e6874cdSJames Morris secmark = info->u.sel.selsid; 445e6874cdSJames Morris break; 455e6874cdSJames Morris 465e6874cdSJames Morris default: 475e6874cdSJames Morris BUG(); 485e6874cdSJames Morris } 495e6874cdSJames Morris 503db05feaSHerbert Xu skb->secmark = secmark; 515e6874cdSJames Morris return XT_CONTINUE; 525e6874cdSJames Morris } 535e6874cdSJames Morris 54e1931b78SJan Engelhardt static bool checkentry_selinux(struct xt_secmark_target_info *info) 555e6874cdSJames Morris { 565e6874cdSJames Morris int err; 575e6874cdSJames Morris struct xt_secmark_target_selinux_info *sel = &info->u.sel; 58a280b899SJames Morris 59a280b899SJames Morris sel->selctx[SECMARK_SELCTX_MAX - 1] = '\0'; 605e6874cdSJames Morris 615e6874cdSJames Morris err = selinux_string_to_sid(sel->selctx, &sel->selsid); 625e6874cdSJames Morris if (err) { 635e6874cdSJames Morris if (err == -EINVAL) 645e6874cdSJames Morris printk(KERN_INFO PFX "invalid SELinux context \'%s\'\n", 655e6874cdSJames Morris sel->selctx); 66e1931b78SJan Engelhardt return false; 675e6874cdSJames Morris } 685e6874cdSJames Morris 695e6874cdSJames Morris if (!sel->selsid) { 705e6874cdSJames Morris printk(KERN_INFO PFX "unable to map SELinux context \'%s\'\n", 715e6874cdSJames Morris sel->selctx); 72e1931b78SJan Engelhardt return false; 735e6874cdSJames Morris } 745e6874cdSJames Morris 75d621d35eSPaul Moore err = selinux_secmark_relabel_packet_permission(sel->selsid); 765e6874cdSJames Morris if (err) { 775e6874cdSJames Morris printk(KERN_INFO PFX "unable to obtain relabeling permission\n"); 78e1931b78SJan Engelhardt return false; 795e6874cdSJames Morris } 805e6874cdSJames Morris 81d621d35eSPaul Moore selinux_secmark_refcount_inc(); 82e1931b78SJan Engelhardt return true; 835e6874cdSJames Morris } 845e6874cdSJames Morris 85d3c5ee6dSJan Engelhardt static bool 86d3c5ee6dSJan Engelhardt secmark_tg_check(const char *tablename, const void *entry, 875e6874cdSJames Morris const struct xt_target *target, void *targinfo, 88efa74165SPatrick McHardy unsigned int hook_mask) 895e6874cdSJames Morris { 905e6874cdSJames Morris struct xt_secmark_target_info *info = targinfo; 915e6874cdSJames Morris 925e6874cdSJames Morris if (mode && mode != info->mode) { 935e6874cdSJames Morris printk(KERN_INFO PFX "mode already set to %hu cannot mix with " 945e6874cdSJames Morris "rules for mode %hu\n", mode, info->mode); 95e1931b78SJan Engelhardt return false; 965e6874cdSJames Morris } 975e6874cdSJames Morris 985e6874cdSJames Morris switch (info->mode) { 995e6874cdSJames Morris case SECMARK_MODE_SEL: 1005e6874cdSJames Morris if (!checkentry_selinux(info)) 101e1931b78SJan Engelhardt return false; 1025e6874cdSJames Morris break; 1035e6874cdSJames Morris 1045e6874cdSJames Morris default: 1055e6874cdSJames Morris printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode); 106e1931b78SJan Engelhardt return false; 1075e6874cdSJames Morris } 1085e6874cdSJames Morris 1095e6874cdSJames Morris if (!mode) 1105e6874cdSJames Morris mode = info->mode; 111e1931b78SJan Engelhardt return true; 1125e6874cdSJames Morris } 1135e6874cdSJames Morris 114d621d35eSPaul Moore void secmark_tg_destroy(const struct xt_target *target, void *targinfo) 115d621d35eSPaul Moore { 116d621d35eSPaul Moore switch (mode) { 117d621d35eSPaul Moore case SECMARK_MODE_SEL: 118d621d35eSPaul Moore selinux_secmark_refcount_dec(); 119d621d35eSPaul Moore } 120d621d35eSPaul Moore } 121d621d35eSPaul Moore 122d3c5ee6dSJan Engelhardt static struct xt_target secmark_tg_reg[] __read_mostly = { 1234470bbc7SPatrick McHardy { 1245e6874cdSJames Morris .name = "SECMARK", 1255e6874cdSJames Morris .family = AF_INET, 126d3c5ee6dSJan Engelhardt .checkentry = secmark_tg_check, 127d621d35eSPaul Moore .destroy = secmark_tg_destroy, 128d3c5ee6dSJan Engelhardt .target = secmark_tg, 1295e6874cdSJames Morris .targetsize = sizeof(struct xt_secmark_target_info), 1305e6874cdSJames Morris .table = "mangle", 1315e6874cdSJames Morris .me = THIS_MODULE, 1324470bbc7SPatrick McHardy }, 1334470bbc7SPatrick McHardy { 1344470bbc7SPatrick McHardy .name = "SECMARK", 1355e6874cdSJames Morris .family = AF_INET6, 136d3c5ee6dSJan Engelhardt .checkentry = secmark_tg_check, 137d621d35eSPaul Moore .destroy = secmark_tg_destroy, 138d3c5ee6dSJan Engelhardt .target = secmark_tg, 1394470bbc7SPatrick McHardy .targetsize = sizeof(struct xt_secmark_target_info), 1404470bbc7SPatrick McHardy .table = "mangle", 1414470bbc7SPatrick McHardy .me = THIS_MODULE, 1424470bbc7SPatrick McHardy }, 1435e6874cdSJames Morris }; 1445e6874cdSJames Morris 145d3c5ee6dSJan Engelhardt static int __init secmark_tg_init(void) 1465e6874cdSJames Morris { 147d3c5ee6dSJan Engelhardt return xt_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg)); 1485e6874cdSJames Morris } 1495e6874cdSJames Morris 150d3c5ee6dSJan Engelhardt static void __exit secmark_tg_exit(void) 1515e6874cdSJames Morris { 152d3c5ee6dSJan Engelhardt xt_unregister_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg)); 1535e6874cdSJames Morris } 1545e6874cdSJames Morris 155d3c5ee6dSJan Engelhardt module_init(secmark_tg_init); 156d3c5ee6dSJan Engelhardt module_exit(secmark_tg_exit); 157