xt_SECMARK.c (4348B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Module for modifying the secmark field of the skb, for use by 4 * security subsystems. 5 * 6 * Based on the nfmark match by: 7 * (C) 1999-2001 Marc Boucher <marc@mbsi.ca> 8 * 9 * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com> 10 */ 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12#include <linux/module.h> 13#include <linux/security.h> 14#include <linux/skbuff.h> 15#include <linux/netfilter/x_tables.h> 16#include <linux/netfilter/xt_SECMARK.h> 17 18MODULE_LICENSE("GPL"); 19MODULE_AUTHOR("James Morris <jmorris@redhat.com>"); 20MODULE_DESCRIPTION("Xtables: packet security mark modification"); 21MODULE_ALIAS("ipt_SECMARK"); 22MODULE_ALIAS("ip6t_SECMARK"); 23 24static u8 mode; 25 26static unsigned int 27secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info) 28{ 29 u32 secmark = 0; 30 31 switch (mode) { 32 case SECMARK_MODE_SEL: 33 secmark = info->secid; 34 break; 35 default: 36 BUG(); 37 } 38 39 skb->secmark = secmark; 40 return XT_CONTINUE; 41} 42 43static int checkentry_lsm(struct xt_secmark_target_info_v1 *info) 44{ 45 int err; 46 47 info->secctx[SECMARK_SECCTX_MAX - 1] = '\0'; 48 info->secid = 0; 49 50 err = security_secctx_to_secid(info->secctx, strlen(info->secctx), 51 &info->secid); 52 if (err) { 53 if (err == -EINVAL) 54 pr_info_ratelimited("invalid security context \'%s\'\n", 55 info->secctx); 56 return err; 57 } 58 59 if (!info->secid) { 60 pr_info_ratelimited("unable to map security context \'%s\'\n", 61 info->secctx); 62 return -ENOENT; 63 } 64 65 err = security_secmark_relabel_packet(info->secid); 66 if (err) { 67 pr_info_ratelimited("unable to obtain relabeling permission\n"); 68 return err; 69 } 70 71 security_secmark_refcount_inc(); 72 return 0; 73} 74 75static int 76secmark_tg_check(const char *table, struct xt_secmark_target_info_v1 *info) 77{ 78 int err; 79 80 if (strcmp(table, "mangle") != 0 && 81 strcmp(table, "security") != 0) { 82 pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n", 83 table); 84 return -EINVAL; 85 } 86 87 if (mode && mode != info->mode) { 88 pr_info_ratelimited("mode already set to %hu cannot mix with rules for mode %hu\n", 89 mode, info->mode); 90 return -EINVAL; 91 } 92 93 switch (info->mode) { 94 case SECMARK_MODE_SEL: 95 break; 96 default: 97 pr_info_ratelimited("invalid mode: %hu\n", info->mode); 98 return -EINVAL; 99 } 100 101 err = checkentry_lsm(info); 102 if (err) 103 return err; 104 105 if (!mode) 106 mode = info->mode; 107 return 0; 108} 109 110static void secmark_tg_destroy(const struct xt_tgdtor_param *par) 111{ 112 switch (mode) { 113 case SECMARK_MODE_SEL: 114 security_secmark_refcount_dec(); 115 } 116} 117 118static int secmark_tg_check_v0(const struct xt_tgchk_param *par) 119{ 120 struct xt_secmark_target_info *info = par->targinfo; 121 struct xt_secmark_target_info_v1 newinfo = { 122 .mode = info->mode, 123 }; 124 int ret; 125 126 memcpy(newinfo.secctx, info->secctx, SECMARK_SECCTX_MAX); 127 128 ret = secmark_tg_check(par->table, &newinfo); 129 info->secid = newinfo.secid; 130 131 return ret; 132} 133 134static unsigned int 135secmark_tg_v0(struct sk_buff *skb, const struct xt_action_param *par) 136{ 137 const struct xt_secmark_target_info *info = par->targinfo; 138 struct xt_secmark_target_info_v1 newinfo = { 139 .secid = info->secid, 140 }; 141 142 return secmark_tg(skb, &newinfo); 143} 144 145static int secmark_tg_check_v1(const struct xt_tgchk_param *par) 146{ 147 return secmark_tg_check(par->table, par->targinfo); 148} 149 150static unsigned int 151secmark_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) 152{ 153 return secmark_tg(skb, par->targinfo); 154} 155 156static struct xt_target secmark_tg_reg[] __read_mostly = { 157 { 158 .name = "SECMARK", 159 .revision = 0, 160 .family = NFPROTO_UNSPEC, 161 .checkentry = secmark_tg_check_v0, 162 .destroy = secmark_tg_destroy, 163 .target = secmark_tg_v0, 164 .targetsize = sizeof(struct xt_secmark_target_info), 165 .me = THIS_MODULE, 166 }, 167 { 168 .name = "SECMARK", 169 .revision = 1, 170 .family = NFPROTO_UNSPEC, 171 .checkentry = secmark_tg_check_v1, 172 .destroy = secmark_tg_destroy, 173 .target = secmark_tg_v1, 174 .targetsize = sizeof(struct xt_secmark_target_info_v1), 175 .usersize = offsetof(struct xt_secmark_target_info_v1, secid), 176 .me = THIS_MODULE, 177 }, 178}; 179 180static int __init secmark_tg_init(void) 181{ 182 return xt_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg)); 183} 184 185static void __exit secmark_tg_exit(void) 186{ 187 xt_unregister_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg)); 188} 189 190module_init(secmark_tg_init); 191module_exit(secmark_tg_exit);