aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2017-09-27 11:25:30 -0400
committerKees Cook <keescook@chromium.org>2017-09-28 01:51:12 -0400
commit66a733ea6b611aecf0119514d2dddab5f9d6c01e (patch)
tree0b1d31848a156eb1008a3adb65fc716fe446153f
parente19b205be43d11bff638cad4487008c48d21c103 (diff)
seccomp: fix the usage of get/put_seccomp_filter() in seccomp_get_filter()
As Chris explains, get_seccomp_filter() and put_seccomp_filter() can end up using different filters. Once we drop ->siglock it is possible for task->seccomp.filter to have been replaced by SECCOMP_FILTER_FLAG_TSYNC. Fixes: f8e529ed941b ("seccomp, ptrace: add support for dumping seccomp filters") Reported-by: Chris Salls <chrissalls5@gmail.com> Cc: stable@vger.kernel.org # needs s/refcount_/atomic_/ for v4.12 and earlier Signed-off-by: Oleg Nesterov <oleg@redhat.com> [tycho: add __get_seccomp_filter vs. open coding refcount_inc()] Signed-off-by: Tycho Andersen <tycho@docker.com> [kees: tweak commit log] Signed-off-by: Kees Cook <keescook@chromium.org>
-rw-r--r--kernel/seccomp.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index c24579dfa7a1..bb3a38005b9c 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -473,14 +473,19 @@ static long seccomp_attach_filter(unsigned int flags,
473 return 0; 473 return 0;
474} 474}
475 475
476void __get_seccomp_filter(struct seccomp_filter *filter)
477{
478 /* Reference count is bounded by the number of total processes. */
479 refcount_inc(&filter->usage);
480}
481
476/* get_seccomp_filter - increments the reference count of the filter on @tsk */ 482/* get_seccomp_filter - increments the reference count of the filter on @tsk */
477void get_seccomp_filter(struct task_struct *tsk) 483void get_seccomp_filter(struct task_struct *tsk)
478{ 484{
479 struct seccomp_filter *orig = tsk->seccomp.filter; 485 struct seccomp_filter *orig = tsk->seccomp.filter;
480 if (!orig) 486 if (!orig)
481 return; 487 return;
482 /* Reference count is bounded by the number of total processes. */ 488 __get_seccomp_filter(orig);
483 refcount_inc(&orig->usage);
484} 489}
485 490
486static inline void seccomp_filter_free(struct seccomp_filter *filter) 491static inline void seccomp_filter_free(struct seccomp_filter *filter)
@@ -491,10 +496,8 @@ static inline void seccomp_filter_free(struct seccomp_filter *filter)
491 } 496 }
492} 497}
493 498
494/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */ 499static void __put_seccomp_filter(struct seccomp_filter *orig)
495void put_seccomp_filter(struct task_struct *tsk)
496{ 500{
497 struct seccomp_filter *orig = tsk->seccomp.filter;
498 /* Clean up single-reference branches iteratively. */ 501 /* Clean up single-reference branches iteratively. */
499 while (orig && refcount_dec_and_test(&orig->usage)) { 502 while (orig && refcount_dec_and_test(&orig->usage)) {
500 struct seccomp_filter *freeme = orig; 503 struct seccomp_filter *freeme = orig;
@@ -503,6 +506,12 @@ void put_seccomp_filter(struct task_struct *tsk)
503 } 506 }
504} 507}
505 508
509/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
510void put_seccomp_filter(struct task_struct *tsk)
511{
512 __put_seccomp_filter(tsk->seccomp.filter);
513}
514
506static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason) 515static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason)
507{ 516{
508 memset(info, 0, sizeof(*info)); 517 memset(info, 0, sizeof(*info));
@@ -1025,13 +1034,13 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
1025 if (!data) 1034 if (!data)
1026 goto out; 1035 goto out;
1027 1036
1028 get_seccomp_filter(task); 1037 __get_seccomp_filter(filter);
1029 spin_unlock_irq(&task->sighand->siglock); 1038 spin_unlock_irq(&task->sighand->siglock);
1030 1039
1031 if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog))) 1040 if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
1032 ret = -EFAULT; 1041 ret = -EFAULT;
1033 1042
1034 put_seccomp_filter(task); 1043 __put_seccomp_filter(filter);
1035 return ret; 1044 return ret;
1036 1045
1037out: 1046out: