Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: gw: add a variable limit for CAN frame routings

To prevent a possible misconfiguration (e.g. circular CAN frame routings)
limit the number of routings of a single CAN frame to a small variable value.

The limit can be specified by the module parameter 'max_hops' (1..6).
The default value is 1 (one hop), according to the original can-gw behaviour.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
be286baf d904d3ed

+40 -16
+40 -16
net/can/gw.c
··· 42 42 #include <linux/module.h> 43 43 #include <linux/init.h> 44 44 #include <linux/types.h> 45 + #include <linux/kernel.h> 45 46 #include <linux/list.h> 46 47 #include <linux/spinlock.h> 47 48 #include <linux/rcupdate.h> ··· 59 58 #include <net/net_namespace.h> 60 59 #include <net/sock.h> 61 60 62 - #define CAN_GW_VERSION "20101209" 63 - static __initconst const char banner[] = 64 - KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n"; 61 + #define CAN_GW_VERSION "20130117" 62 + #define CAN_GW_NAME "can-gw" 65 63 66 64 MODULE_DESCRIPTION("PF_CAN netlink gateway"); 67 65 MODULE_LICENSE("Dual BSD/GPL"); 68 66 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>"); 69 - MODULE_ALIAS("can-gw"); 67 + MODULE_ALIAS(CAN_GW_NAME); 68 + 69 + #define CGW_MIN_HOPS 1 70 + #define CGW_MAX_HOPS 6 71 + #define CGW_DEFAULT_HOPS 1 72 + 73 + static unsigned int max_hops __read_mostly = CGW_DEFAULT_HOPS; 74 + module_param(max_hops, uint, S_IRUGO); 75 + MODULE_PARM_DESC(max_hops, 76 + "maximum " CAN_GW_NAME " routing hops for CAN frames " 77 + "(valid values: " __stringify(CGW_MIN_HOPS) "-" 78 + __stringify(CGW_MAX_HOPS) " hops, " 79 + "default: " __stringify(CGW_DEFAULT_HOPS) ")"); 70 80 71 81 static HLIST_HEAD(cgw_list); 72 82 static struct notifier_block notifier; ··· 351 339 struct sk_buff *nskb; 352 340 int modidx = 0; 353 341 354 - /* do not handle already routed frames - see comment below */ 355 - if (skb_mac_header_was_set(skb)) 342 + /* 343 + * Do not handle CAN frames routed more than 'max_hops' times. 344 + * In general we should never catch this delimiter which is intended 345 + * to cover a misconfiguration protection (e.g. circular CAN routes). 346 + * 347 + * The Controller Area Network controllers only accept CAN frames with 348 + * correct CRCs - which are not visible in the controller registers. 349 + * According to skbuff.h documentation the csum_start element for IP 350 + * checksums is undefined/unsued when ip_summed == CHECKSUM_UNNECESSARY. 351 + * Only CAN skbs can be processed here which already have this property. 352 + */ 353 + 354 + #define cgw_hops(skb) ((skb)->csum_start) 355 + 356 + BUG_ON(skb->ip_summed != CHECKSUM_UNNECESSARY); 357 + 358 + if (cgw_hops(skb) >= max_hops) 356 359 return; 357 360 358 361 if (!(gwj->dst.dev->flags & IFF_UP)) { ··· 398 371 return; 399 372 } 400 373 401 - /* 402 - * Mark routed frames by setting some mac header length which is 403 - * not relevant for the CAN frames located in the skb->data section. 404 - * 405 - * As dev->header_ops is not set in CAN netdevices no one is ever 406 - * accessing the various header offsets in the CAN skbuffs anyway. 407 - * E.g. using the packet socket to read CAN frames is still working. 408 - */ 409 - skb_set_mac_header(nskb, 8); 374 + /* put the incremented hop counter in the cloned skb */ 375 + cgw_hops(nskb) = cgw_hops(skb) + 1; 410 376 nskb->dev = gwj->dst.dev; 411 377 412 378 /* pointer to modifiable CAN frame */ ··· 923 903 924 904 static __init int cgw_module_init(void) 925 905 { 926 - printk(banner); 906 + /* sanitize given module parameter */ 907 + max_hops = clamp_t(unsigned int, max_hops, CGW_MIN_HOPS, CGW_MAX_HOPS); 908 + 909 + pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n", 910 + max_hops); 927 911 928 912 cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job), 929 913 0, 0, NULL);