1 /* Xtables module to match packets using a BPF filter. 2 * Copyright 2013 Google Inc. 3 * Written by Willem de Bruijn <willemb@google.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/skbuff.h> 12 #include <linux/filter.h> 13 #include <linux/bpf.h> 14 15 #include <linux/netfilter/xt_bpf.h> 16 #include <linux/netfilter/x_tables.h> 17 18 MODULE_AUTHOR("Willem de Bruijn <willemb@google.com>"); 19 MODULE_DESCRIPTION("Xtables: BPF filter match"); 20 MODULE_LICENSE("GPL"); 21 MODULE_ALIAS("ipt_bpf"); 22 MODULE_ALIAS("ip6t_bpf"); 23 24 static int __bpf_mt_check_bytecode(struct sock_filter *insns, __u16 len, 25 struct bpf_prog **ret) 26 { 27 struct sock_fprog_kern program; 28 29 program.len = len; 30 program.filter = insns; 31 32 if (bpf_prog_create(ret, &program)) { 33 pr_info("bpf: check failed: parse error\n"); 34 return -EINVAL; 35 } 36 37 return 0; 38 } 39 40 static int __bpf_mt_check_fd(int fd, struct bpf_prog **ret) 41 { 42 struct bpf_prog *prog; 43 44 prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_SOCKET_FILTER); 45 if (IS_ERR(prog)) 46 return PTR_ERR(prog); 47 48 *ret = prog; 49 return 0; 50 } 51 52 static int bpf_mt_check(const struct xt_mtchk_param *par) 53 { 54 struct xt_bpf_info *info = par->matchinfo; 55 56 return __bpf_mt_check_bytecode(info->bpf_program, 57 info->bpf_program_num_elem, 58 &info->filter); 59 } 60 61 static int bpf_mt_check_v1(const struct xt_mtchk_param *par) 62 { 63 struct xt_bpf_info_v1 *info = par->matchinfo; 64 65 if (info->mode == XT_BPF_MODE_BYTECODE) 66 return __bpf_mt_check_bytecode(info->bpf_program, 67 info->bpf_program_num_elem, 68 &info->filter); 69 else if (info->mode == XT_BPF_MODE_FD_PINNED || 70 info->mode == XT_BPF_MODE_FD_ELF) 71 return __bpf_mt_check_fd(info->fd, &info->filter); 72 else 73 return -EINVAL; 74 } 75 76 static bool bpf_mt(const struct sk_buff *skb, struct xt_action_param *par) 77 { 78 const struct xt_bpf_info *info = par->matchinfo; 79 80 return BPF_PROG_RUN(info->filter, skb); 81 } 82 83 static bool bpf_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) 84 { 85 const struct xt_bpf_info_v1 *info = par->matchinfo; 86 87 return !!bpf_prog_run_save_cb(info->filter, (struct sk_buff *) skb); 88 } 89 90 static void bpf_mt_destroy(const struct xt_mtdtor_param *par) 91 { 92 const struct xt_bpf_info *info = par->matchinfo; 93 94 bpf_prog_destroy(info->filter); 95 } 96 97 static void bpf_mt_destroy_v1(const struct xt_mtdtor_param *par) 98 { 99 const struct xt_bpf_info_v1 *info = par->matchinfo; 100 101 bpf_prog_destroy(info->filter); 102 } 103 104 static struct xt_match bpf_mt_reg[] __read_mostly = { 105 { 106 .name = "bpf", 107 .revision = 0, 108 .family = NFPROTO_UNSPEC, 109 .checkentry = bpf_mt_check, 110 .match = bpf_mt, 111 .destroy = bpf_mt_destroy, 112 .matchsize = sizeof(struct xt_bpf_info), 113 .usersize = offsetof(struct xt_bpf_info, filter), 114 .me = THIS_MODULE, 115 }, 116 { 117 .name = "bpf", 118 .revision = 1, 119 .family = NFPROTO_UNSPEC, 120 .checkentry = bpf_mt_check_v1, 121 .match = bpf_mt_v1, 122 .destroy = bpf_mt_destroy_v1, 123 .matchsize = sizeof(struct xt_bpf_info_v1), 124 .usersize = offsetof(struct xt_bpf_info_v1, filter), 125 .me = THIS_MODULE, 126 }, 127 }; 128 129 static int __init bpf_mt_init(void) 130 { 131 return xt_register_matches(bpf_mt_reg, ARRAY_SIZE(bpf_mt_reg)); 132 } 133 134 static void __exit bpf_mt_exit(void) 135 { 136 xt_unregister_matches(bpf_mt_reg, ARRAY_SIZE(bpf_mt_reg)); 137 } 138 139 module_init(bpf_mt_init); 140 module_exit(bpf_mt_exit); 141