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