1*12079a59SBreno Leitao // SPDX-License-Identifier: GPL-2.0-only 2*12079a59SBreno Leitao 3*12079a59SBreno Leitao #include <linux/debugfs.h> 4*12079a59SBreno Leitao #include <linux/fault-inject.h> 5*12079a59SBreno Leitao #include <linux/netdevice.h> 6*12079a59SBreno Leitao #include <linux/skbuff.h> 7*12079a59SBreno Leitao 8*12079a59SBreno Leitao static struct { 9*12079a59SBreno Leitao struct fault_attr attr; 10*12079a59SBreno Leitao char devname[IFNAMSIZ]; 11*12079a59SBreno Leitao bool filtered; 12*12079a59SBreno Leitao } skb_realloc = { 13*12079a59SBreno Leitao .attr = FAULT_ATTR_INITIALIZER, 14*12079a59SBreno Leitao .filtered = false, 15*12079a59SBreno Leitao }; 16*12079a59SBreno Leitao 17*12079a59SBreno Leitao static bool should_fail_net_realloc_skb(struct sk_buff *skb) 18*12079a59SBreno Leitao { 19*12079a59SBreno Leitao struct net_device *net = skb->dev; 20*12079a59SBreno Leitao 21*12079a59SBreno Leitao if (skb_realloc.filtered && 22*12079a59SBreno Leitao strncmp(net->name, skb_realloc.devname, IFNAMSIZ)) 23*12079a59SBreno Leitao /* device name filter set, but names do not match */ 24*12079a59SBreno Leitao return false; 25*12079a59SBreno Leitao 26*12079a59SBreno Leitao if (!should_fail(&skb_realloc.attr, 1)) 27*12079a59SBreno Leitao return false; 28*12079a59SBreno Leitao 29*12079a59SBreno Leitao return true; 30*12079a59SBreno Leitao } 31*12079a59SBreno Leitao ALLOW_ERROR_INJECTION(should_fail_net_realloc_skb, TRUE); 32*12079a59SBreno Leitao 33*12079a59SBreno Leitao void skb_might_realloc(struct sk_buff *skb) 34*12079a59SBreno Leitao { 35*12079a59SBreno Leitao if (!should_fail_net_realloc_skb(skb)) 36*12079a59SBreno Leitao return; 37*12079a59SBreno Leitao 38*12079a59SBreno Leitao pskb_expand_head(skb, 0, 0, GFP_ATOMIC); 39*12079a59SBreno Leitao } 40*12079a59SBreno Leitao EXPORT_SYMBOL(skb_might_realloc); 41*12079a59SBreno Leitao 42*12079a59SBreno Leitao static int __init fail_skb_realloc_setup(char *str) 43*12079a59SBreno Leitao { 44*12079a59SBreno Leitao return setup_fault_attr(&skb_realloc.attr, str); 45*12079a59SBreno Leitao } 46*12079a59SBreno Leitao __setup("fail_skb_realloc=", fail_skb_realloc_setup); 47*12079a59SBreno Leitao 48*12079a59SBreno Leitao static void reset_settings(void) 49*12079a59SBreno Leitao { 50*12079a59SBreno Leitao skb_realloc.filtered = false; 51*12079a59SBreno Leitao memset(&skb_realloc.devname, 0, IFNAMSIZ); 52*12079a59SBreno Leitao } 53*12079a59SBreno Leitao 54*12079a59SBreno Leitao static ssize_t devname_write(struct file *file, const char __user *buffer, 55*12079a59SBreno Leitao size_t count, loff_t *ppos) 56*12079a59SBreno Leitao { 57*12079a59SBreno Leitao ssize_t ret; 58*12079a59SBreno Leitao 59*12079a59SBreno Leitao reset_settings(); 60*12079a59SBreno Leitao ret = simple_write_to_buffer(&skb_realloc.devname, IFNAMSIZ, 61*12079a59SBreno Leitao ppos, buffer, count); 62*12079a59SBreno Leitao if (ret < 0) 63*12079a59SBreno Leitao return ret; 64*12079a59SBreno Leitao 65*12079a59SBreno Leitao skb_realloc.devname[IFNAMSIZ - 1] = '\0'; 66*12079a59SBreno Leitao /* Remove a possible \n at the end of devname */ 67*12079a59SBreno Leitao strim(skb_realloc.devname); 68*12079a59SBreno Leitao 69*12079a59SBreno Leitao if (strnlen(skb_realloc.devname, IFNAMSIZ)) 70*12079a59SBreno Leitao skb_realloc.filtered = true; 71*12079a59SBreno Leitao 72*12079a59SBreno Leitao return count; 73*12079a59SBreno Leitao } 74*12079a59SBreno Leitao 75*12079a59SBreno Leitao static ssize_t devname_read(struct file *file, 76*12079a59SBreno Leitao char __user *buffer, 77*12079a59SBreno Leitao size_t size, loff_t *ppos) 78*12079a59SBreno Leitao { 79*12079a59SBreno Leitao if (!skb_realloc.filtered) 80*12079a59SBreno Leitao return 0; 81*12079a59SBreno Leitao 82*12079a59SBreno Leitao return simple_read_from_buffer(buffer, size, ppos, &skb_realloc.devname, 83*12079a59SBreno Leitao strlen(skb_realloc.devname)); 84*12079a59SBreno Leitao } 85*12079a59SBreno Leitao 86*12079a59SBreno Leitao static const struct file_operations devname_ops = { 87*12079a59SBreno Leitao .write = devname_write, 88*12079a59SBreno Leitao .read = devname_read, 89*12079a59SBreno Leitao }; 90*12079a59SBreno Leitao 91*12079a59SBreno Leitao static int __init fail_skb_realloc_debugfs(void) 92*12079a59SBreno Leitao { 93*12079a59SBreno Leitao umode_t mode = S_IFREG | 0600; 94*12079a59SBreno Leitao struct dentry *dir; 95*12079a59SBreno Leitao 96*12079a59SBreno Leitao dir = fault_create_debugfs_attr("fail_skb_realloc", NULL, 97*12079a59SBreno Leitao &skb_realloc.attr); 98*12079a59SBreno Leitao if (IS_ERR(dir)) 99*12079a59SBreno Leitao return PTR_ERR(dir); 100*12079a59SBreno Leitao 101*12079a59SBreno Leitao debugfs_create_file("devname", mode, dir, NULL, &devname_ops); 102*12079a59SBreno Leitao 103*12079a59SBreno Leitao return 0; 104*12079a59SBreno Leitao } 105*12079a59SBreno Leitao 106*12079a59SBreno Leitao late_initcall(fail_skb_realloc_debugfs); 107