1/* 2 * Module for modifying the secmark field of the skb, for use by 3 * security subsystems. 4 * 5 * Based on the nfmark match by: 6 * (C) 1999-2001 Marc Boucher <marc@mbsi.ca> 7 * 8 * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 */ 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16#include <linux/module.h> 17#include <linux/skbuff.h> 18#include <linux/selinux.h> 19#include <linux/netfilter/x_tables.h> 20#include <linux/netfilter/xt_SECMARK.h> 21 22MODULE_LICENSE("GPL"); 23MODULE_AUTHOR("James Morris <jmorris@redhat.com>"); 24MODULE_DESCRIPTION("Xtables: packet security mark modification"); 25MODULE_ALIAS("ipt_SECMARK"); 26MODULE_ALIAS("ip6t_SECMARK"); 27 28#define PFX "SECMARK: " 29 30static u8 mode; 31 32static unsigned int 33secmark_tg(struct sk_buff *skb, const struct xt_action_param *par) 34{ 35 u32 secmark = 0; 36 const struct xt_secmark_target_info *info = par->targinfo; 37 38 BUG_ON(info->mode != mode); 39 40 switch (mode) { 41 case SECMARK_MODE_SEL: 42 secmark = info->u.sel.selsid; 43 break; 44 45 default: 46 BUG(); 47 } 48 49 skb->secmark = secmark; 50 return XT_CONTINUE; 51} 52 53static int checkentry_selinux(struct xt_secmark_target_info *info) 54{ 55 int err; 56 struct xt_secmark_target_selinux_info *sel = &info->u.sel; 57 58 sel->selctx[SECMARK_SELCTX_MAX - 1] = '\0'; 59 60 err = selinux_string_to_sid(sel->selctx, &sel->selsid); 61 if (err) { 62 if (err == -EINVAL) 63 pr_info("invalid SELinux context \'%s\'\n", 64 sel->selctx); 65 return err; 66 } 67 68 if (!sel->selsid) { 69 pr_info("unable to map SELinux context \'%s\'\n", sel->selctx); 70 return -ENOENT; 71 } 72 73 err = selinux_secmark_relabel_packet_permission(sel->selsid); 74 if (err) { 75 pr_info("unable to obtain relabeling permission\n"); 76 return err; 77 } 78 79 selinux_secmark_refcount_inc(); 80 return 0; 81} 82 83static int secmark_tg_check(const struct xt_tgchk_param *par) 84{ 85 struct xt_secmark_target_info *info = par->targinfo; 86 int err; 87 88 if (strcmp(par->table, "mangle") != 0 && 89 strcmp(par->table, "security") != 0) { 90 pr_info("target only valid in the \'mangle\' " 91 "or \'security\' tables, not \'%s\'.\n", par->table); 92 return -EINVAL; 93 } 94 95 if (mode && mode != info->mode) { 96 pr_info("mode already set to %hu cannot mix with " 97 "rules for mode %hu\n", mode, info->mode); 98 return -EINVAL; 99 } 100 101 switch (info->mode) { 102 case SECMARK_MODE_SEL: 103 err = checkentry_selinux(info); 104 if (err) 105 return err; 106 break; 107 108 default: 109 pr_info("invalid mode: %hu\n", info->mode); 110 return -EINVAL; 111 } 112 113 if (!mode) 114 mode = info->mode; 115 return 0; 116} 117 118static void secmark_tg_destroy(const struct xt_tgdtor_param *par) 119{ 120 switch (mode) { 121 case SECMARK_MODE_SEL: 122 selinux_secmark_refcount_dec(); 123 } 124} 125 126static struct xt_target secmark_tg_reg __read_mostly = { 127 .name = "SECMARK", 128 .revision = 0, 129 .family = NFPROTO_UNSPEC, 130 .checkentry = secmark_tg_check, 131 .destroy = secmark_tg_destroy, 132 .target = secmark_tg, 133 .targetsize = sizeof(struct xt_secmark_target_info), 134 .me = THIS_MODULE, 135}; 136 137static int __init secmark_tg_init(void) 138{ 139 return xt_register_target(&secmark_tg_reg); 140} 141 142static void __exit secmark_tg_exit(void) 143{ 144 xt_unregister_target(&secmark_tg_reg); 145} 146 147module_init(secmark_tg_init); 148module_exit(secmark_tg_exit); 149