Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Module for modifying the secmark field of the skb, for use by
0004  * security subsystems.
0005  *
0006  * Based on the nfmark match by:
0007  * (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
0008  *
0009  * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
0010  */
0011 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0012 #include <linux/module.h>
0013 #include <linux/security.h>
0014 #include <linux/skbuff.h>
0015 #include <linux/netfilter/x_tables.h>
0016 #include <linux/netfilter/xt_SECMARK.h>
0017 
0018 MODULE_LICENSE("GPL");
0019 MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
0020 MODULE_DESCRIPTION("Xtables: packet security mark modification");
0021 MODULE_ALIAS("ipt_SECMARK");
0022 MODULE_ALIAS("ip6t_SECMARK");
0023 
0024 static u8 mode;
0025 
0026 static unsigned int
0027 secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info)
0028 {
0029     u32 secmark = 0;
0030 
0031     switch (mode) {
0032     case SECMARK_MODE_SEL:
0033         secmark = info->secid;
0034         break;
0035     default:
0036         BUG();
0037     }
0038 
0039     skb->secmark = secmark;
0040     return XT_CONTINUE;
0041 }
0042 
0043 static int checkentry_lsm(struct xt_secmark_target_info_v1 *info)
0044 {
0045     int err;
0046 
0047     info->secctx[SECMARK_SECCTX_MAX - 1] = '\0';
0048     info->secid = 0;
0049 
0050     err = security_secctx_to_secid(info->secctx, strlen(info->secctx),
0051                        &info->secid);
0052     if (err) {
0053         if (err == -EINVAL)
0054             pr_info_ratelimited("invalid security context \'%s\'\n",
0055                         info->secctx);
0056         return err;
0057     }
0058 
0059     if (!info->secid) {
0060         pr_info_ratelimited("unable to map security context \'%s\'\n",
0061                     info->secctx);
0062         return -ENOENT;
0063     }
0064 
0065     err = security_secmark_relabel_packet(info->secid);
0066     if (err) {
0067         pr_info_ratelimited("unable to obtain relabeling permission\n");
0068         return err;
0069     }
0070 
0071     security_secmark_refcount_inc();
0072     return 0;
0073 }
0074 
0075 static int
0076 secmark_tg_check(const char *table, struct xt_secmark_target_info_v1 *info)
0077 {
0078     int err;
0079 
0080     if (strcmp(table, "mangle") != 0 &&
0081         strcmp(table, "security") != 0) {
0082         pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
0083                     table);
0084         return -EINVAL;
0085     }
0086 
0087     if (mode && mode != info->mode) {
0088         pr_info_ratelimited("mode already set to %hu cannot mix with rules for mode %hu\n",
0089                     mode, info->mode);
0090         return -EINVAL;
0091     }
0092 
0093     switch (info->mode) {
0094     case SECMARK_MODE_SEL:
0095         break;
0096     default:
0097         pr_info_ratelimited("invalid mode: %hu\n", info->mode);
0098         return -EINVAL;
0099     }
0100 
0101     err = checkentry_lsm(info);
0102     if (err)
0103         return err;
0104 
0105     if (!mode)
0106         mode = info->mode;
0107     return 0;
0108 }
0109 
0110 static void secmark_tg_destroy(const struct xt_tgdtor_param *par)
0111 {
0112     switch (mode) {
0113     case SECMARK_MODE_SEL:
0114         security_secmark_refcount_dec();
0115     }
0116 }
0117 
0118 static int secmark_tg_check_v0(const struct xt_tgchk_param *par)
0119 {
0120     struct xt_secmark_target_info *info = par->targinfo;
0121     struct xt_secmark_target_info_v1 newinfo = {
0122         .mode   = info->mode,
0123     };
0124     int ret;
0125 
0126     memcpy(newinfo.secctx, info->secctx, SECMARK_SECCTX_MAX);
0127 
0128     ret = secmark_tg_check(par->table, &newinfo);
0129     info->secid = newinfo.secid;
0130 
0131     return ret;
0132 }
0133 
0134 static unsigned int
0135 secmark_tg_v0(struct sk_buff *skb, const struct xt_action_param *par)
0136 {
0137     const struct xt_secmark_target_info *info = par->targinfo;
0138     struct xt_secmark_target_info_v1 newinfo = {
0139         .secid  = info->secid,
0140     };
0141 
0142     return secmark_tg(skb, &newinfo);
0143 }
0144 
0145 static int secmark_tg_check_v1(const struct xt_tgchk_param *par)
0146 {
0147     return secmark_tg_check(par->table, par->targinfo);
0148 }
0149 
0150 static unsigned int
0151 secmark_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
0152 {
0153     return secmark_tg(skb, par->targinfo);
0154 }
0155 
0156 static struct xt_target secmark_tg_reg[] __read_mostly = {
0157     {
0158         .name       = "SECMARK",
0159         .revision   = 0,
0160         .family     = NFPROTO_UNSPEC,
0161         .checkentry = secmark_tg_check_v0,
0162         .destroy    = secmark_tg_destroy,
0163         .target     = secmark_tg_v0,
0164         .targetsize = sizeof(struct xt_secmark_target_info),
0165         .me     = THIS_MODULE,
0166     },
0167     {
0168         .name       = "SECMARK",
0169         .revision   = 1,
0170         .family     = NFPROTO_UNSPEC,
0171         .checkentry = secmark_tg_check_v1,
0172         .destroy    = secmark_tg_destroy,
0173         .target     = secmark_tg_v1,
0174         .targetsize = sizeof(struct xt_secmark_target_info_v1),
0175         .usersize   = offsetof(struct xt_secmark_target_info_v1, secid),
0176         .me     = THIS_MODULE,
0177     },
0178 };
0179 
0180 static int __init secmark_tg_init(void)
0181 {
0182     return xt_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
0183 }
0184 
0185 static void __exit secmark_tg_exit(void)
0186 {
0187     xt_unregister_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
0188 }
0189 
0190 module_init(secmark_tg_init);
0191 module_exit(secmark_tg_exit);