Commit f4f154fd authored by Akinobu Mita's avatar Akinobu Mita Committed by Linus Torvalds

[PATCH] fault injection: process filtering for fault-injection capabilities

This patch provides process filtering feature.
The process filter allows failing only permitted processes
by /proc/<pid>/make-it-fail

Please see the example that demostrates how to inject slab allocation
failures into module init/cleanup code
in Documentation/fault-injection/fault-injection.txt
Signed-off-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c17bb495
......@@ -853,6 +853,65 @@ static struct file_operations proc_seccomp_operations = {
};
#endif /* CONFIG_SECCOMP */
#ifdef CONFIG_FAULT_INJECTION
static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
char buffer[PROC_NUMBUF];
size_t len;
int make_it_fail;
loff_t __ppos = *ppos;
if (!task)
return -ESRCH;
make_it_fail = task->make_it_fail;
put_task_struct(task);
len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
if (__ppos >= len)
return 0;
if (count > len-__ppos)
count = len-__ppos;
if (copy_to_user(buf, buffer + __ppos, count))
return -EFAULT;
*ppos = __ppos + count;
return count;
}
static ssize_t proc_fault_inject_write(struct file * file,
const char __user * buf, size_t count, loff_t *ppos)
{
struct task_struct *task;
char buffer[PROC_NUMBUF], *end;
int make_it_fail;
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;
memset(buffer, 0, sizeof(buffer));
if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
if (copy_from_user(buffer, buf, count))
return -EFAULT;
make_it_fail = simple_strtol(buffer, &end, 0);
if (*end == '\n')
end++;
task = get_proc_task(file->f_dentry->d_inode);
if (!task)
return -ESRCH;
task->make_it_fail = make_it_fail;
put_task_struct(task);
if (end - buffer == 0)
return -EIO;
return end - buffer;
}
static struct file_operations proc_fault_inject_operations = {
.read = proc_fault_inject_read,
.write = proc_fault_inject_write,
};
#endif
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
......@@ -1793,6 +1852,9 @@ static struct pid_entry tgid_base_stuff[] = {
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
#ifdef CONFIG_FAULT_INJECTION
REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
#endif
};
static int proc_tgid_base_readdir(struct file * filp,
......@@ -2068,6 +2130,9 @@ static struct pid_entry tid_base_stuff[] = {
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
#ifdef CONFIG_FAULT_INJECTION
REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
#endif
};
static int proc_tid_base_readdir(struct file * filp,
......
......@@ -17,6 +17,7 @@ struct fault_attr {
atomic_t times;
atomic_t space;
unsigned long verbose;
u32 task_filter;
unsigned long count;
......@@ -30,6 +31,7 @@ struct fault_attr {
struct dentry *times_file;
struct dentry *space_file;
struct dentry *verbose_file;
struct dentry *task_filter_file;
} dentries;
#endif
......
......@@ -1045,6 +1045,9 @@ struct task_struct {
#ifdef CONFIG_TASK_DELAY_ACCT
struct task_delay_info *delays;
#endif
#ifdef CONFIG_FAULT_INJECTION
int make_it_fail;
#endif
};
static inline pid_t process_group(struct task_struct *tsk)
......
......@@ -5,6 +5,7 @@
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/fault-inject.h>
/*
......@@ -44,6 +45,11 @@ static void fail_dump(struct fault_attr *attr)
#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
static int fail_task(struct fault_attr *attr, struct task_struct *task)
{
return !in_interrupt() && task->make_it_fail;
}
/*
* This code is stolen from failmalloc-1.0
* http://www.nongnu.org/failmalloc/
......@@ -51,6 +57,9 @@ static void fail_dump(struct fault_attr *attr)
int should_fail(struct fault_attr *attr, ssize_t size)
{
if (attr->task_filter && !fail_task(attr, current))
return 0;
if (atomic_read(&attr->times) == 0)
return 0;
......@@ -135,6 +144,9 @@ void cleanup_fault_attr_dentries(struct fault_attr *attr)
debugfs_remove(attr->dentries.verbose_file);
attr->dentries.verbose_file = NULL;
debugfs_remove(attr->dentries.task_filter_file);
attr->dentries.task_filter_file = NULL;
if (attr->dentries.dir)
WARN_ON(!simple_empty(attr->dentries.dir));
......@@ -169,9 +181,12 @@ int init_fault_attr_dentries(struct fault_attr *attr, const char *name)
attr->dentries.verbose_file =
debugfs_create_ul("verbose", mode, dir, &attr->verbose);
attr->dentries.task_filter_file = debugfs_create_bool("task-filter",
mode, dir, &attr->task_filter);
if (!attr->dentries.probability_file || !attr->dentries.interval_file
|| !attr->dentries.times_file || !attr->dentries.space_file
|| !attr->dentries.verbose_file)
|| !attr->dentries.verbose_file || !attr->dentries.task_filter_file)
goto fail;
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment