xref: /linux/net/core/skb_fault_injection.c (revision c771600c6af14749609b49565ffb4cac2959710d)
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