mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 12:12:05 +00:00
107 lines
2.3 KiB
C
107 lines
2.3 KiB
C
|
// SPDX-License-Identifier: GPL-2.0-only
|
||
|
|
||
|
#include <linux/debugfs.h>
|
||
|
#include <linux/fault-inject.h>
|
||
|
#include <linux/netdevice.h>
|
||
|
#include <linux/skbuff.h>
|
||
|
|
||
|
static struct {
|
||
|
struct fault_attr attr;
|
||
|
char devname[IFNAMSIZ];
|
||
|
bool filtered;
|
||
|
} skb_realloc = {
|
||
|
.attr = FAULT_ATTR_INITIALIZER,
|
||
|
.filtered = false,
|
||
|
};
|
||
|
|
||
|
static bool should_fail_net_realloc_skb(struct sk_buff *skb)
|
||
|
{
|
||
|
struct net_device *net = skb->dev;
|
||
|
|
||
|
if (skb_realloc.filtered &&
|
||
|
strncmp(net->name, skb_realloc.devname, IFNAMSIZ))
|
||
|
/* device name filter set, but names do not match */
|
||
|
return false;
|
||
|
|
||
|
if (!should_fail(&skb_realloc.attr, 1))
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
ALLOW_ERROR_INJECTION(should_fail_net_realloc_skb, TRUE);
|
||
|
|
||
|
void skb_might_realloc(struct sk_buff *skb)
|
||
|
{
|
||
|
if (!should_fail_net_realloc_skb(skb))
|
||
|
return;
|
||
|
|
||
|
pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
|
||
|
}
|
||
|
EXPORT_SYMBOL(skb_might_realloc);
|
||
|
|
||
|
static int __init fail_skb_realloc_setup(char *str)
|
||
|
{
|
||
|
return setup_fault_attr(&skb_realloc.attr, str);
|
||
|
}
|
||
|
__setup("fail_skb_realloc=", fail_skb_realloc_setup);
|
||
|
|
||
|
static void reset_settings(void)
|
||
|
{
|
||
|
skb_realloc.filtered = false;
|
||
|
memset(&skb_realloc.devname, 0, IFNAMSIZ);
|
||
|
}
|
||
|
|
||
|
static ssize_t devname_write(struct file *file, const char __user *buffer,
|
||
|
size_t count, loff_t *ppos)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
reset_settings();
|
||
|
ret = simple_write_to_buffer(&skb_realloc.devname, IFNAMSIZ,
|
||
|
ppos, buffer, count);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
|
||
|
skb_realloc.devname[IFNAMSIZ - 1] = '\0';
|
||
|
/* Remove a possible \n at the end of devname */
|
||
|
strim(skb_realloc.devname);
|
||
|
|
||
|
if (strnlen(skb_realloc.devname, IFNAMSIZ))
|
||
|
skb_realloc.filtered = true;
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t devname_read(struct file *file,
|
||
|
char __user *buffer,
|
||
|
size_t size, loff_t *ppos)
|
||
|
{
|
||
|
if (!skb_realloc.filtered)
|
||
|
return 0;
|
||
|
|
||
|
return simple_read_from_buffer(buffer, size, ppos, &skb_realloc.devname,
|
||
|
strlen(skb_realloc.devname));
|
||
|
}
|
||
|
|
||
|
static const struct file_operations devname_ops = {
|
||
|
.write = devname_write,
|
||
|
.read = devname_read,
|
||
|
};
|
||
|
|
||
|
static int __init fail_skb_realloc_debugfs(void)
|
||
|
{
|
||
|
umode_t mode = S_IFREG | 0600;
|
||
|
struct dentry *dir;
|
||
|
|
||
|
dir = fault_create_debugfs_attr("fail_skb_realloc", NULL,
|
||
|
&skb_realloc.attr);
|
||
|
if (IS_ERR(dir))
|
||
|
return PTR_ERR(dir);
|
||
|
|
||
|
debugfs_create_file("devname", mode, dir, NULL, &devname_ops);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
late_initcall(fail_skb_realloc_debugfs);
|