summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkinobu Mita <akinobu.mita@gmail.com>2017-07-14 14:49:57 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-14 15:05:13 -0700
commit1203c8e6fb0aa1e9c39d2323607a74c3adc34fd8 (patch)
tree67fc0c8911aec1b7c4bfdfc90305c2ff72b081a0
parentbfc740938d151001cb1158580796f8f3be3bf0c1 (diff)
fault-inject: simplify access check for fail-nth
The fail-nth file is created with 0666 and the access is permitted if and only if the task is current. This file is owned by the currnet user. So we can create it with 0644 and allow the owner to write it. This enables to watch the status of task->fail_nth from another processes. [akinobu.mita@gmail.com: don't convert unsigned type value as signed int] Link: http://lkml.kernel.org/r/1492444483-9239-1-git-send-email-akinobu.mita@gmail.com [akinobu.mita@gmail.com: avoid unwanted data race to task->fail_nth] Link: http://lkml.kernel.org/r/1499962492-8931-1-git-send-email-akinobu.mita@gmail.com Link: http://lkml.kernel.org/r/1491490561-10485-5-git-send-email-akinobu.mita@gmail.com Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> Acked-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/base.c25
-rw-r--r--lib/fault-inject.c7
2 files changed, 15 insertions, 17 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 7d795d28dd02..872a3f28bfe4 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1363,16 +1363,16 @@ static ssize_t proc_fail_nth_write(struct file *file, const char __user *buf,
int err;
unsigned int n;
+ err = kstrtouint_from_user(buf, count, 0, &n);
+ if (err)
+ return err;
+
task = get_proc_task(file_inode(file));
if (!task)
return -ESRCH;
+ WRITE_ONCE(task->fail_nth, n);
put_task_struct(task);
- if (task != current)
- return -EPERM;
- err = kstrtouint_from_user(buf, count, 0, &n);
- if (err)
- return err;
- current->fail_nth = n;
+
return count;
}
@@ -1386,11 +1386,10 @@ static ssize_t proc_fail_nth_read(struct file *file, char __user *buf,
task = get_proc_task(file_inode(file));
if (!task)
return -ESRCH;
- put_task_struct(task);
- if (task != current)
- return -EPERM;
- len = snprintf(numbuf, sizeof(numbuf), "%u\n", task->fail_nth);
+ len = snprintf(numbuf, sizeof(numbuf), "%u\n",
+ READ_ONCE(task->fail_nth));
len = simple_read_from_buffer(buf, count, ppos, numbuf, len);
+ put_task_struct(task);
return len;
}
@@ -3355,11 +3354,7 @@ static const struct pid_entry tid_base_stuff[] = {
#endif
#ifdef CONFIG_FAULT_INJECTION
REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
- /*
- * Operations on the file check that the task is current,
- * so we create it with 0666 to support testing under unprivileged user.
- */
- REG("fail-nth", 0666, proc_fail_nth_operations),
+ REG("fail-nth", 0644, proc_fail_nth_operations),
#endif
#ifdef CONFIG_TASK_IO_ACCOUNTING
ONE("io", S_IRUSR, proc_tid_io_accounting),
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index 09ac73c177fd..7d315fdb9f13 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -107,9 +107,12 @@ static inline bool fail_stacktrace(struct fault_attr *attr)
bool should_fail(struct fault_attr *attr, ssize_t size)
{
- if (in_task() && current->fail_nth) {
- if (--current->fail_nth == 0)
+ if (in_task()) {
+ unsigned int fail_nth = READ_ONCE(current->fail_nth);
+
+ if (fail_nth && !WRITE_ONCE(current->fail_nth, fail_nth - 1))
goto fail;
+
return false;
}