aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 21:47:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 21:47:30 -0400
commitfb21affa49204acd409328415b49bfe90136653c (patch)
tree3535dbe0c0aad049a38cadfcffe78409397a1b32
parenta00b6151a2ae4c52576c35d3998e144a993d50b8 (diff)
parentf23ca335462e3c84f13270b9e65f83936068ec2c (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull second pile of signal handling patches from Al Viro: "This one is just task_work_add() series + remaining prereqs for it. There probably will be another pull request from that tree this cycle - at least for helpers, to get them out of the way for per-arch fixes remaining in the tree." Fix trivial conflict in kernel/irq/manage.c: the merge of Andrew's pile had brought in commit 97fd75b7b8e0 ("kernel/irq/manage.c: use the pr_foo() infrastructure to prefix printks") which changed one of the pr_err() calls that this merge moves around. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: keys: kill task_struct->replacement_session_keyring keys: kill the dummy key_replace_session_keyring() keys: change keyctl_session_to_parent() to use task_work_add() genirq: reimplement exit_irq_thread() hook via task_work_add() task_work_add: generic process-context callbacks avr32: missed _TIF_NOTIFY_RESUME on one of do_notify_resume callers parisc: need to check NOTIFY_RESUME when exiting from syscall move key_repace_session_keyring() into tracehook_notify_resume() TIF_NOTIFY_RESUME is defined on all targets now
-rw-r--r--arch/alpha/kernel/signal.c2
-rw-r--r--arch/arm/kernel/signal.c2
-rw-r--r--arch/avr32/kernel/entry-avr32b.S2
-rw-r--r--arch/avr32/kernel/signal.c2
-rw-r--r--arch/blackfin/kernel/signal.c2
-rw-r--r--arch/c6x/kernel/signal.c2
-rw-r--r--arch/cris/kernel/ptrace.c2
-rw-r--r--arch/frv/kernel/signal.c2
-rw-r--r--arch/h8300/kernel/signal.c2
-rw-r--r--arch/hexagon/kernel/signal.c2
-rw-r--r--arch/ia64/kernel/process.c2
-rw-r--r--arch/m32r/kernel/signal.c2
-rw-r--r--arch/m68k/kernel/signal.c5
-rw-r--r--arch/microblaze/kernel/signal.c5
-rw-r--r--arch/mips/kernel/signal.c2
-rw-r--r--arch/mn10300/kernel/signal.c2
-rw-r--r--arch/openrisc/kernel/signal.c2
-rw-r--r--arch/parisc/kernel/entry.S2
-rw-r--r--arch/parisc/kernel/signal.c2
-rw-r--r--arch/powerpc/kernel/signal.c2
-rw-r--r--arch/s390/kernel/signal.c2
-rw-r--r--arch/score/kernel/signal.c2
-rw-r--r--arch/sh/kernel/signal_32.c2
-rw-r--r--arch/sh/kernel/signal_64.c2
-rw-r--r--arch/sparc/kernel/signal_32.c2
-rw-r--r--arch/sparc/kernel/signal_64.c2
-rw-r--r--arch/tile/kernel/process.c2
-rw-r--r--arch/um/kernel/process.c5
-rw-r--r--arch/unicore32/kernel/signal.c2
-rw-r--r--arch/x86/kernel/signal.c2
-rw-r--r--arch/xtensa/kernel/signal.c5
-rw-r--r--include/linux/interrupt.h4
-rw-r--r--include/linux/key.h4
-rw-r--r--include/linux/sched.h14
-rw-r--r--include/linux/task_work.h33
-rw-r--r--include/linux/tracehook.h13
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/cred.c9
-rw-r--r--kernel/exit.c5
-rw-r--r--kernel/fork.c1
-rw-r--r--kernel/irq/manage.c68
-rw-r--r--kernel/task_work.c84
-rw-r--r--security/keys/internal.h2
-rw-r--r--security/keys/keyctl.c73
-rw-r--r--security/keys/process_keys.c20
45 files changed, 220 insertions, 186 deletions
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 10ab2d74ecbb..f6db3032ddf0 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -590,7 +590,5 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
590 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 590 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
591 clear_thread_flag(TIF_NOTIFY_RESUME); 591 clear_thread_flag(TIF_NOTIFY_RESUME);
592 tracehook_notify_resume(regs); 592 tracehook_notify_resume(regs);
593 if (current->replacement_session_keyring)
594 key_replace_session_keyring();
595 } 593 }
596} 594}
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 17fc36c41cff..63f327dd5198 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -679,7 +679,5 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
679 if (thread_flags & _TIF_NOTIFY_RESUME) { 679 if (thread_flags & _TIF_NOTIFY_RESUME) {
680 clear_thread_flag(TIF_NOTIFY_RESUME); 680 clear_thread_flag(TIF_NOTIFY_RESUME);
681 tracehook_notify_resume(regs); 681 tracehook_notify_resume(regs);
682 if (current->replacement_session_keyring)
683 key_replace_session_keyring();
684 } 682 }
685} 683}
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
index 169268c40ae2..5e6beb2597a8 100644
--- a/arch/avr32/kernel/entry-avr32b.S
+++ b/arch/avr32/kernel/entry-avr32b.S
@@ -587,7 +587,7 @@ fault_exit_work:
587 ld.w r1, r0[TI_flags] 587 ld.w r1, r0[TI_flags]
588 rjmp fault_exit_work 588 rjmp fault_exit_work
589 589
5901: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK 5901: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME
591 tst r1, r2 591 tst r1, r2
592 breq 2f 592 breq 2f
593 unmask_interrupts 593 unmask_interrupts
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index ae386c304bee..e7595ef74f51 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -321,7 +321,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti)
321 if (ti->flags & _TIF_NOTIFY_RESUME) { 321 if (ti->flags & _TIF_NOTIFY_RESUME) {
322 clear_thread_flag(TIF_NOTIFY_RESUME); 322 clear_thread_flag(TIF_NOTIFY_RESUME);
323 tracehook_notify_resume(regs); 323 tracehook_notify_resume(regs);
324 if (current->replacement_session_keyring)
325 key_replace_session_keyring();
326 } 324 }
327} 325}
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index e5bbc1a5edc2..fc9ecce8b6ce 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -336,8 +336,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs)
336 if (test_thread_flag(TIF_NOTIFY_RESUME)) { 336 if (test_thread_flag(TIF_NOTIFY_RESUME)) {
337 clear_thread_flag(TIF_NOTIFY_RESUME); 337 clear_thread_flag(TIF_NOTIFY_RESUME);
338 tracehook_notify_resume(regs); 338 tracehook_notify_resume(regs);
339 if (current->replacement_session_keyring)
340 key_replace_session_keyring();
341 } 339 }
342} 340}
343 341
diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c
index cf37478c1169..9493f0bbf0a6 100644
--- a/arch/c6x/kernel/signal.c
+++ b/arch/c6x/kernel/signal.c
@@ -364,7 +364,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags,
364 if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) { 364 if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) {
365 clear_thread_flag(TIF_NOTIFY_RESUME); 365 clear_thread_flag(TIF_NOTIFY_RESUME);
366 tracehook_notify_resume(regs); 366 tracehook_notify_resume(regs);
367 if (current->replacement_session_keyring)
368 key_replace_session_keyring();
369 } 367 }
370} 368}
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
index d114ad3da9b1..58d44ee1a71f 100644
--- a/arch/cris/kernel/ptrace.c
+++ b/arch/cris/kernel/ptrace.c
@@ -40,7 +40,5 @@ void do_notify_resume(int canrestart, struct pt_regs *regs,
40 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 40 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
41 clear_thread_flag(TIF_NOTIFY_RESUME); 41 clear_thread_flag(TIF_NOTIFY_RESUME);
42 tracehook_notify_resume(regs); 42 tracehook_notify_resume(regs);
43 if (current->replacement_session_keyring)
44 key_replace_session_keyring();
45 } 43 }
46} 44}
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 8cf5dca01758..595bf1e5a5dc 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -562,8 +562,6 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags)
562 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 562 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
563 clear_thread_flag(TIF_NOTIFY_RESUME); 563 clear_thread_flag(TIF_NOTIFY_RESUME);
564 tracehook_notify_resume(__frame); 564 tracehook_notify_resume(__frame);
565 if (current->replacement_session_keyring)
566 key_replace_session_keyring();
567 } 565 }
568 566
569} /* end do_notify_resume() */ 567} /* end do_notify_resume() */
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index d4b0555d2904..e58992ad789e 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -513,7 +513,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
513 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 513 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
514 clear_thread_flag(TIF_NOTIFY_RESUME); 514 clear_thread_flag(TIF_NOTIFY_RESUME);
515 tracehook_notify_resume(regs); 515 tracehook_notify_resume(regs);
516 if (current->replacement_session_keyring)
517 key_replace_session_keyring();
518 } 516 }
519} 517}
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index 434866eb0f1c..21a3018cb9bf 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -273,8 +273,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
273 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 273 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
274 clear_thread_flag(TIF_NOTIFY_RESUME); 274 clear_thread_flag(TIF_NOTIFY_RESUME);
275 tracehook_notify_resume(regs); 275 tracehook_notify_resume(regs);
276 if (current->replacement_session_keyring)
277 key_replace_session_keyring();
278 } 276 }
279} 277}
280 278
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 5e0e86ddb12f..dd6fc1449741 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -199,8 +199,6 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
199 if (test_thread_flag(TIF_NOTIFY_RESUME)) { 199 if (test_thread_flag(TIF_NOTIFY_RESUME)) {
200 clear_thread_flag(TIF_NOTIFY_RESUME); 200 clear_thread_flag(TIF_NOTIFY_RESUME);
201 tracehook_notify_resume(&scr->pt); 201 tracehook_notify_resume(&scr->pt);
202 if (current->replacement_session_keyring)
203 key_replace_session_keyring();
204 } 202 }
205 203
206 /* copy user rbs to kernel rbs */ 204 /* copy user rbs to kernel rbs */
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index f54d96993ea1..64804f1f5141 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -383,8 +383,6 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags)
383 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 383 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
384 clear_thread_flag(TIF_NOTIFY_RESUME); 384 clear_thread_flag(TIF_NOTIFY_RESUME);
385 tracehook_notify_resume(regs); 385 tracehook_notify_resume(regs);
386 if (current->replacement_session_keyring)
387 key_replace_session_keyring();
388 } 386 }
389 387
390 clear_thread_flag(TIF_IRET); 388 clear_thread_flag(TIF_IRET);
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index d9f3d1900eed..973eec60cad4 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -1193,9 +1193,6 @@ void do_notify_resume(struct pt_regs *regs)
1193 if (test_thread_flag(TIF_SIGPENDING)) 1193 if (test_thread_flag(TIF_SIGPENDING))
1194 do_signal(regs); 1194 do_signal(regs);
1195 1195
1196 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { 1196 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
1197 tracehook_notify_resume(regs); 1197 tracehook_notify_resume(regs);
1198 if (current->replacement_session_keyring)
1199 key_replace_session_keyring();
1200 }
1201} 1198}
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 7f4c7bef1642..5d796e32786e 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -401,9 +401,6 @@ void do_notify_resume(struct pt_regs *regs, int in_syscall)
401 if (test_thread_flag(TIF_SIGPENDING)) 401 if (test_thread_flag(TIF_SIGPENDING))
402 do_signal(regs, in_syscall); 402 do_signal(regs, in_syscall);
403 403
404 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { 404 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
405 tracehook_notify_resume(regs); 405 tracehook_notify_resume(regs);
406 if (current->replacement_session_keyring)
407 key_replace_session_keyring();
408 }
409} 406}
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 17f6ee30ad0d..8a6e6d116ab0 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -636,8 +636,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
636 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 636 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
637 clear_thread_flag(TIF_NOTIFY_RESUME); 637 clear_thread_flag(TIF_NOTIFY_RESUME);
638 tracehook_notify_resume(regs); 638 tracehook_notify_resume(regs);
639 if (current->replacement_session_keyring)
640 key_replace_session_keyring();
641 } 639 }
642} 640}
643 641
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index 890cf91767cc..b8b6aa1a6837 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -554,7 +554,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
554 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 554 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
555 clear_thread_flag(TIF_NOTIFY_RESUME); 555 clear_thread_flag(TIF_NOTIFY_RESUME);
556 tracehook_notify_resume(current_frame()); 556 tracehook_notify_resume(current_frame());
557 if (current->replacement_session_keyring)
558 key_replace_session_keyring();
559 } 557 }
560} 558}
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c
index e970743251ae..9ae611522953 100644
--- a/arch/openrisc/kernel/signal.c
+++ b/arch/openrisc/kernel/signal.c
@@ -376,7 +376,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs)
376 if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) { 376 if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) {
377 clear_thread_flag(TIF_NOTIFY_RESUME); 377 clear_thread_flag(TIF_NOTIFY_RESUME);
378 tracehook_notify_resume(regs); 378 tracehook_notify_resume(regs);
379 if (current->replacement_session_keyring)
380 key_replace_session_keyring();
381 } 379 }
382} 380}
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 07ef351edd57..c7fbc96472f3 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -2032,7 +2032,7 @@ syscall_check_resched:
2032 .import do_signal,code 2032 .import do_signal,code
2033syscall_check_sig: 2033syscall_check_sig:
2034 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 2034 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19
2035 ldi (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r26 2035 ldi (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NOTIFY_RESUME), %r26
2036 and,COND(<>) %r19, %r26, %r0 2036 and,COND(<>) %r19, %r26, %r0
2037 b,n syscall_restore /* skip past if we've nothing to do */ 2037 b,n syscall_restore /* skip past if we've nothing to do */
2038 2038
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 4b9cb0d546d1..e7a7cd3e1120 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -638,7 +638,5 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall)
638 if (test_thread_flag(TIF_NOTIFY_RESUME)) { 638 if (test_thread_flag(TIF_NOTIFY_RESUME)) {
639 clear_thread_flag(TIF_NOTIFY_RESUME); 639 clear_thread_flag(TIF_NOTIFY_RESUME);
640 tracehook_notify_resume(regs); 640 tracehook_notify_resume(regs);
641 if (current->replacement_session_keyring)
642 key_replace_session_keyring();
643 } 641 }
644} 642}
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 651c5963662b..bfc3ec1382fb 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -193,8 +193,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
193 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 193 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
194 clear_thread_flag(TIF_NOTIFY_RESUME); 194 clear_thread_flag(TIF_NOTIFY_RESUME);
195 tracehook_notify_resume(regs); 195 tracehook_notify_resume(regs);
196 if (current->replacement_session_keyring)
197 key_replace_session_keyring();
198 } 196 }
199} 197}
200 198
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index f626232e216c..42a6e8b47f06 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -494,6 +494,4 @@ void do_notify_resume(struct pt_regs *regs)
494{ 494{
495 clear_thread_flag(TIF_NOTIFY_RESUME); 495 clear_thread_flag(TIF_NOTIFY_RESUME);
496 tracehook_notify_resume(regs); 496 tracehook_notify_resume(regs);
497 if (current->replacement_session_keyring)
498 key_replace_session_keyring();
499} 497}
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c
index d4a49011c48a..302838d3acf6 100644
--- a/arch/score/kernel/signal.c
+++ b/arch/score/kernel/signal.c
@@ -356,7 +356,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
356 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 356 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
357 clear_thread_flag(TIF_NOTIFY_RESUME); 357 clear_thread_flag(TIF_NOTIFY_RESUME);
358 tracehook_notify_resume(regs); 358 tracehook_notify_resume(regs);
359 if (current->replacement_session_keyring)
360 key_replace_session_keyring();
361 } 359 }
362} 360}
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index cb4172c8af7d..9d7bfd66f189 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -626,7 +626,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
626 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 626 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
627 clear_thread_flag(TIF_NOTIFY_RESUME); 627 clear_thread_flag(TIF_NOTIFY_RESUME);
628 tracehook_notify_resume(regs); 628 tracehook_notify_resume(regs);
629 if (current->replacement_session_keyring)
630 key_replace_session_keyring();
631 } 629 }
632} 630}
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index b589a354c069..aa6428430842 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -685,7 +685,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info
685 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 685 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
686 clear_thread_flag(TIF_NOTIFY_RESUME); 686 clear_thread_flag(TIF_NOTIFY_RESUME);
687 tracehook_notify_resume(regs); 687 tracehook_notify_resume(regs);
688 if (current->replacement_session_keyring)
689 key_replace_session_keyring();
690 } 688 }
691} 689}
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 2b7e849f7c65..6b42e8622d12 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -590,8 +590,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
590 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 590 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
591 clear_thread_flag(TIF_NOTIFY_RESUME); 591 clear_thread_flag(TIF_NOTIFY_RESUME);
592 tracehook_notify_resume(regs); 592 tracehook_notify_resume(regs);
593 if (current->replacement_session_keyring)
594 key_replace_session_keyring();
595 } 593 }
596} 594}
597 595
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index eafaab486b2d..c82cf1cc3965 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -607,8 +607,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long
607 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 607 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
608 clear_thread_flag(TIF_NOTIFY_RESUME); 608 clear_thread_flag(TIF_NOTIFY_RESUME);
609 tracehook_notify_resume(regs); 609 tracehook_notify_resume(regs);
610 if (current->replacement_session_keyring)
611 key_replace_session_keyring();
612 } 610 }
613} 611}
614 612
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index ba1023d8a021..6be799150501 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -565,8 +565,6 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
565 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 565 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
566 clear_thread_flag(TIF_NOTIFY_RESUME); 566 clear_thread_flag(TIF_NOTIFY_RESUME);
567 tracehook_notify_resume(regs); 567 tracehook_notify_resume(regs);
568 if (current->replacement_session_keyring)
569 key_replace_session_keyring();
570 return 1; 568 return 1;
571 } 569 }
572 if (thread_info_flags & _TIF_SINGLESTEP) { 570 if (thread_info_flags & _TIF_SINGLESTEP) {
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 3a2235e0abc3..ccb9a9d283f1 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -117,11 +117,8 @@ void interrupt_end(void)
117 schedule(); 117 schedule();
118 if (test_thread_flag(TIF_SIGPENDING)) 118 if (test_thread_flag(TIF_SIGPENDING))
119 do_signal(); 119 do_signal();
120 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { 120 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
121 tracehook_notify_resume(&current->thread.regs); 121 tracehook_notify_resume(&current->thread.regs);
122 if (current->replacement_session_keyring)
123 key_replace_session_keyring();
124 }
125} 122}
126 123
127void exit_thread(void) 124void exit_thread(void)
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c
index 7754df6ef7d4..28782ad47b93 100644
--- a/arch/unicore32/kernel/signal.c
+++ b/arch/unicore32/kernel/signal.c
@@ -464,8 +464,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
464 if (thread_flags & _TIF_NOTIFY_RESUME) { 464 if (thread_flags & _TIF_NOTIFY_RESUME) {
465 clear_thread_flag(TIF_NOTIFY_RESUME); 465 clear_thread_flag(TIF_NOTIFY_RESUME);
466 tracehook_notify_resume(regs); 466 tracehook_notify_resume(regs);
467 if (current->replacement_session_keyring)
468 key_replace_session_keyring();
469 } 467 }
470} 468}
471 469
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 965dfda0fd5e..2e937a5ad531 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -827,8 +827,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
827 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 827 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
828 clear_thread_flag(TIF_NOTIFY_RESUME); 828 clear_thread_flag(TIF_NOTIFY_RESUME);
829 tracehook_notify_resume(regs); 829 tracehook_notify_resume(regs);
830 if (current->replacement_session_keyring)
831 key_replace_session_keyring();
832 } 830 }
833 if (thread_info_flags & _TIF_USER_RETURN_NOTIFY) 831 if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
834 fire_user_return_notifiers(); 832 fire_user_return_notifiers();
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index c5e4ec0598d2..ea7e17778a75 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -548,9 +548,6 @@ void do_notify_resume(struct pt_regs *regs)
548 if (test_thread_flag(TIF_SIGPENDING)) 548 if (test_thread_flag(TIF_SIGPENDING))
549 do_signal(regs); 549 do_signal(regs);
550 550
551 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { 551 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
552 tracehook_notify_resume(regs); 552 tracehook_notify_resume(regs);
553 if (current->replacement_session_keyring)
554 key_replace_session_keyring();
555 }
556} 553}
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index c91171599cb6..e68a8e53bb59 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -142,8 +142,6 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler,
142extern int __must_check 142extern int __must_check
143request_percpu_irq(unsigned int irq, irq_handler_t handler, 143request_percpu_irq(unsigned int irq, irq_handler_t handler,
144 const char *devname, void __percpu *percpu_dev_id); 144 const char *devname, void __percpu *percpu_dev_id);
145
146extern void exit_irq_thread(void);
147#else 145#else
148 146
149extern int __must_check 147extern int __must_check
@@ -177,8 +175,6 @@ request_percpu_irq(unsigned int irq, irq_handler_t handler,
177{ 175{
178 return request_irq(irq, handler, 0, devname, percpu_dev_id); 176 return request_irq(irq, handler, 0, devname, percpu_dev_id);
179} 177}
180
181static inline void exit_irq_thread(void) { }
182#endif 178#endif
183 179
184extern void free_irq(unsigned int, void *); 180extern void free_irq(unsigned int, void *);
diff --git a/include/linux/key.h b/include/linux/key.h
index 5231800770e1..4cd22ed627ef 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -308,9 +308,6 @@ static inline bool key_is_instantiated(const struct key *key)
308#ifdef CONFIG_SYSCTL 308#ifdef CONFIG_SYSCTL
309extern ctl_table key_sysctls[]; 309extern ctl_table key_sysctls[];
310#endif 310#endif
311
312extern void key_replace_session_keyring(void);
313
314/* 311/*
315 * the userspace interface 312 * the userspace interface
316 */ 313 */
@@ -334,7 +331,6 @@ extern void key_init(void);
334#define key_fsuid_changed(t) do { } while(0) 331#define key_fsuid_changed(t) do { } while(0)
335#define key_fsgid_changed(t) do { } while(0) 332#define key_fsgid_changed(t) do { } while(0)
336#define key_init() do { } while(0) 333#define key_init() do { } while(0)
337#define key_replace_session_keyring() do { } while(0)
338 334
339#endif /* CONFIG_KEYS */ 335#endif /* CONFIG_KEYS */
340#endif /* __KERNEL__ */ 336#endif /* __KERNEL__ */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f45c0b280b5d..660c8ae93471 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1301,11 +1301,6 @@ struct task_struct {
1301 unsigned sched_reset_on_fork:1; 1301 unsigned sched_reset_on_fork:1;
1302 unsigned sched_contributes_to_load:1; 1302 unsigned sched_contributes_to_load:1;
1303 1303
1304#ifdef CONFIG_GENERIC_HARDIRQS
1305 /* IRQ handler threads */
1306 unsigned irq_thread:1;
1307#endif
1308
1309 pid_t pid; 1304 pid_t pid;
1310 pid_t tgid; 1305 pid_t tgid;
1311 1306
@@ -1313,10 +1308,9 @@ struct task_struct {
1313 /* Canary value for the -fstack-protector gcc feature */ 1308 /* Canary value for the -fstack-protector gcc feature */
1314 unsigned long stack_canary; 1309 unsigned long stack_canary;
1315#endif 1310#endif
1316 1311 /*
1317 /*
1318 * pointers to (original) parent process, youngest child, younger sibling, 1312 * pointers to (original) parent process, youngest child, younger sibling,
1319 * older sibling, respectively. (p->father can be replaced with 1313 * older sibling, respectively. (p->father can be replaced with
1320 * p->real_parent->pid) 1314 * p->real_parent->pid)
1321 */ 1315 */
1322 struct task_struct __rcu *real_parent; /* real parent process */ 1316 struct task_struct __rcu *real_parent; /* real parent process */
@@ -1363,8 +1357,6 @@ struct task_struct {
1363 * credentials (COW) */ 1357 * credentials (COW) */
1364 const struct cred __rcu *cred; /* effective (overridable) subjective task 1358 const struct cred __rcu *cred; /* effective (overridable) subjective task
1365 * credentials (COW) */ 1359 * credentials (COW) */
1366 struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */
1367
1368 char comm[TASK_COMM_LEN]; /* executable name excluding path 1360 char comm[TASK_COMM_LEN]; /* executable name excluding path
1369 - access with [gs]et_task_comm (which lock 1361 - access with [gs]et_task_comm (which lock
1370 it with task_lock()) 1362 it with task_lock())
@@ -1400,6 +1392,8 @@ struct task_struct {
1400 int (*notifier)(void *priv); 1392 int (*notifier)(void *priv);
1401 void *notifier_data; 1393 void *notifier_data;
1402 sigset_t *notifier_mask; 1394 sigset_t *notifier_mask;
1395 struct hlist_head task_works;
1396
1403 struct audit_context *audit_context; 1397 struct audit_context *audit_context;
1404#ifdef CONFIG_AUDITSYSCALL 1398#ifdef CONFIG_AUDITSYSCALL
1405 uid_t loginuid; 1399 uid_t loginuid;
diff --git a/include/linux/task_work.h b/include/linux/task_work.h
new file mode 100644
index 000000000000..294d5d5e90b1
--- /dev/null
+++ b/include/linux/task_work.h
@@ -0,0 +1,33 @@
1#ifndef _LINUX_TASK_WORK_H
2#define _LINUX_TASK_WORK_H
3
4#include <linux/list.h>
5#include <linux/sched.h>
6
7struct task_work;
8typedef void (*task_work_func_t)(struct task_work *);
9
10struct task_work {
11 struct hlist_node hlist;
12 task_work_func_t func;
13 void *data;
14};
15
16static inline void
17init_task_work(struct task_work *twork, task_work_func_t func, void *data)
18{
19 twork->func = func;
20 twork->data = data;
21}
22
23int task_work_add(struct task_struct *task, struct task_work *twork, bool);
24struct task_work *task_work_cancel(struct task_struct *, task_work_func_t);
25void task_work_run(void);
26
27static inline void exit_task_work(struct task_struct *task)
28{
29 if (unlikely(!hlist_empty(&task->task_works)))
30 task_work_run();
31}
32
33#endif /* _LINUX_TASK_WORK_H */
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index 51bd91d911c3..6a4d82bedb03 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -49,6 +49,7 @@
49#include <linux/sched.h> 49#include <linux/sched.h>
50#include <linux/ptrace.h> 50#include <linux/ptrace.h>
51#include <linux/security.h> 51#include <linux/security.h>
52#include <linux/task_work.h>
52struct linux_binprm; 53struct linux_binprm;
53 54
54/* 55/*
@@ -153,7 +154,6 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
153 ptrace_notify(SIGTRAP); 154 ptrace_notify(SIGTRAP);
154} 155}
155 156
156#ifdef TIF_NOTIFY_RESUME
157/** 157/**
158 * set_notify_resume - cause tracehook_notify_resume() to be called 158 * set_notify_resume - cause tracehook_notify_resume() to be called
159 * @task: task that will call tracehook_notify_resume() 159 * @task: task that will call tracehook_notify_resume()
@@ -165,8 +165,10 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
165 */ 165 */
166static inline void set_notify_resume(struct task_struct *task) 166static inline void set_notify_resume(struct task_struct *task)
167{ 167{
168#ifdef TIF_NOTIFY_RESUME
168 if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_RESUME)) 169 if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_RESUME))
169 kick_process(task); 170 kick_process(task);
171#endif
170} 172}
171 173
172/** 174/**
@@ -184,7 +186,14 @@ static inline void set_notify_resume(struct task_struct *task)
184 */ 186 */
185static inline void tracehook_notify_resume(struct pt_regs *regs) 187static inline void tracehook_notify_resume(struct pt_regs *regs)
186{ 188{
189 /*
190 * The caller just cleared TIF_NOTIFY_RESUME. This barrier
191 * pairs with task_work_add()->set_notify_resume() after
192 * hlist_add_head(task->task_works);
193 */
194 smp_mb__after_clear_bit();
195 if (unlikely(!hlist_empty(&current->task_works)))
196 task_work_run();
187} 197}
188#endif /* TIF_NOTIFY_RESUME */
189 198
190#endif /* <linux/tracehook.h> */ 199#endif /* <linux/tracehook.h> */
diff --git a/kernel/Makefile b/kernel/Makefile
index 80be6ca0cc75..6f3d0ae044b2 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -5,7 +5,7 @@
5obj-y = fork.o exec_domain.o panic.o printk.o \ 5obj-y = fork.o exec_domain.o panic.o printk.o \
6 cpu.o exit.o itimer.o time.o softirq.o resource.o \ 6 cpu.o exit.o itimer.o time.o softirq.o resource.o \
7 sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \ 7 sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
8 signal.o sys.o kmod.o workqueue.o pid.o \ 8 signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
9 rcupdate.o extable.o params.o posix-timers.o \ 9 rcupdate.o extable.o params.o posix-timers.o \
10 kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ 10 kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
11 hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ 11 hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
diff --git a/kernel/cred.c b/kernel/cred.c
index 430557ea488f..de728ac50d82 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -207,13 +207,6 @@ void exit_creds(struct task_struct *tsk)
207 validate_creds(cred); 207 validate_creds(cred);
208 alter_cred_subscribers(cred, -1); 208 alter_cred_subscribers(cred, -1);
209 put_cred(cred); 209 put_cred(cred);
210
211 cred = (struct cred *) tsk->replacement_session_keyring;
212 if (cred) {
213 tsk->replacement_session_keyring = NULL;
214 validate_creds(cred);
215 put_cred(cred);
216 }
217} 210}
218 211
219/** 212/**
@@ -396,8 +389,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
396 struct cred *new; 389 struct cred *new;
397 int ret; 390 int ret;
398 391
399 p->replacement_session_keyring = NULL;
400
401 if ( 392 if (
402#ifdef CONFIG_KEYS 393#ifdef CONFIG_KEYS
403 !p->cred->thread_keyring && 394 !p->cred->thread_keyring &&
diff --git a/kernel/exit.c b/kernel/exit.c
index 6d85655353e9..34867cc5b42a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -946,12 +946,13 @@ void do_exit(long code)
946 exit_signals(tsk); /* sets PF_EXITING */ 946 exit_signals(tsk); /* sets PF_EXITING */
947 /* 947 /*
948 * tsk->flags are checked in the futex code to protect against 948 * tsk->flags are checked in the futex code to protect against
949 * an exiting task cleaning up the robust pi futexes. 949 * an exiting task cleaning up the robust pi futexes, and in
950 * task_work_add() to avoid the race with exit_task_work().
950 */ 951 */
951 smp_mb(); 952 smp_mb();
952 raw_spin_unlock_wait(&tsk->pi_lock); 953 raw_spin_unlock_wait(&tsk->pi_lock);
953 954
954 exit_irq_thread(); 955 exit_task_work(tsk);
955 956
956 if (unlikely(in_atomic())) 957 if (unlikely(in_atomic()))
957 printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", 958 printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
diff --git a/kernel/fork.c b/kernel/fork.c
index c55b61ab6d64..ab5211b9e622 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1415,6 +1415,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1415 */ 1415 */
1416 p->group_leader = p; 1416 p->group_leader = p;
1417 INIT_LIST_HEAD(&p->thread_group); 1417 INIT_LIST_HEAD(&p->thread_group);
1418 INIT_HLIST_HEAD(&p->task_works);
1418 1419
1419 /* Now that the task is set up, run cgroup callbacks if 1420 /* Now that the task is set up, run cgroup callbacks if
1420 * necessary. We need to run them before the task is visible 1421 * necessary. We need to run them before the task is visible
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 7c475cd3f6e6..ea0c6c2ae6f7 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -16,6 +16,7 @@
16#include <linux/interrupt.h> 16#include <linux/interrupt.h>
17#include <linux/slab.h> 17#include <linux/slab.h>
18#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/task_work.h>
19 20
20#include "internals.h" 21#include "internals.h"
21 22
@@ -775,11 +776,39 @@ static void wake_threads_waitq(struct irq_desc *desc)
775 wake_up(&desc->wait_for_threads); 776 wake_up(&desc->wait_for_threads);
776} 777}
777 778
779static void irq_thread_dtor(struct task_work *unused)
780{
781 struct task_struct *tsk = current;
782 struct irq_desc *desc;
783 struct irqaction *action;
784
785 if (WARN_ON_ONCE(!(current->flags & PF_EXITING)))
786 return;
787
788 action = kthread_data(tsk);
789
790 pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
791 tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
792
793
794 desc = irq_to_desc(action->irq);
795 /*
796 * If IRQTF_RUNTHREAD is set, we need to decrement
797 * desc->threads_active and wake possible waiters.
798 */
799 if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
800 wake_threads_waitq(desc);
801
802 /* Prevent a stale desc->threads_oneshot */
803 irq_finalize_oneshot(desc, action);
804}
805
778/* 806/*
779 * Interrupt handler thread 807 * Interrupt handler thread
780 */ 808 */
781static int irq_thread(void *data) 809static int irq_thread(void *data)
782{ 810{
811 struct task_work on_exit_work;
783 static const struct sched_param param = { 812 static const struct sched_param param = {
784 .sched_priority = MAX_USER_RT_PRIO/2, 813 .sched_priority = MAX_USER_RT_PRIO/2,
785 }; 814 };
@@ -795,7 +824,9 @@ static int irq_thread(void *data)
795 handler_fn = irq_thread_fn; 824 handler_fn = irq_thread_fn;
796 825
797 sched_setscheduler(current, SCHED_FIFO, &param); 826 sched_setscheduler(current, SCHED_FIFO, &param);
798 current->irq_thread = 1; 827
828 init_task_work(&on_exit_work, irq_thread_dtor, NULL);
829 task_work_add(current, &on_exit_work, false);
799 830
800 while (!irq_wait_for_interrupt(action)) { 831 while (!irq_wait_for_interrupt(action)) {
801 irqreturn_t action_ret; 832 irqreturn_t action_ret;
@@ -817,44 +848,11 @@ static int irq_thread(void *data)
817 * cannot touch the oneshot mask at this point anymore as 848 * cannot touch the oneshot mask at this point anymore as
818 * __setup_irq() might have given out currents thread_mask 849 * __setup_irq() might have given out currents thread_mask
819 * again. 850 * again.
820 *
821 * Clear irq_thread. Otherwise exit_irq_thread() would make
822 * fuzz about an active irq thread going into nirvana.
823 */ 851 */
824 current->irq_thread = 0; 852 task_work_cancel(current, irq_thread_dtor);
825 return 0; 853 return 0;
826} 854}
827 855
828/*
829 * Called from do_exit()
830 */
831void exit_irq_thread(void)
832{
833 struct task_struct *tsk = current;
834 struct irq_desc *desc;
835 struct irqaction *action;
836
837 if (!tsk->irq_thread)
838 return;
839
840 action = kthread_data(tsk);
841
842 pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
843 tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
844
845 desc = irq_to_desc(action->irq);
846
847 /*
848 * If IRQTF_RUNTHREAD is set, we need to decrement
849 * desc->threads_active and wake possible waiters.
850 */
851 if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
852 wake_threads_waitq(desc);
853
854 /* Prevent a stale desc->threads_oneshot */
855 irq_finalize_oneshot(desc, action);
856}
857
858static void irq_setup_forced_threading(struct irqaction *new) 856static void irq_setup_forced_threading(struct irqaction *new)
859{ 857{
860 if (!force_irqthreads) 858 if (!force_irqthreads)
diff --git a/kernel/task_work.c b/kernel/task_work.c
new file mode 100644
index 000000000000..82d1c794066d
--- /dev/null
+++ b/kernel/task_work.c
@@ -0,0 +1,84 @@
1#include <linux/spinlock.h>
2#include <linux/task_work.h>
3#include <linux/tracehook.h>
4
5int
6task_work_add(struct task_struct *task, struct task_work *twork, bool notify)
7{
8 unsigned long flags;
9 int err = -ESRCH;
10
11#ifndef TIF_NOTIFY_RESUME
12 if (notify)
13 return -ENOTSUPP;
14#endif
15 /*
16 * We must not insert the new work if the task has already passed
17 * exit_task_work(). We rely on do_exit()->raw_spin_unlock_wait()
18 * and check PF_EXITING under pi_lock.
19 */
20 raw_spin_lock_irqsave(&task->pi_lock, flags);
21 if (likely(!(task->flags & PF_EXITING))) {
22 hlist_add_head(&twork->hlist, &task->task_works);
23 err = 0;
24 }
25 raw_spin_unlock_irqrestore(&task->pi_lock, flags);
26
27 /* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */
28 if (likely(!err) && notify)
29 set_notify_resume(task);
30 return err;
31}
32
33struct task_work *
34task_work_cancel(struct task_struct *task, task_work_func_t func)
35{
36 unsigned long flags;
37 struct task_work *twork;
38 struct hlist_node *pos;
39
40 raw_spin_lock_irqsave(&task->pi_lock, flags);
41 hlist_for_each_entry(twork, pos, &task->task_works, hlist) {
42 if (twork->func == func) {
43 hlist_del(&twork->hlist);
44 goto found;
45 }
46 }
47 twork = NULL;
48 found:
49 raw_spin_unlock_irqrestore(&task->pi_lock, flags);
50
51 return twork;
52}
53
54void task_work_run(void)
55{
56 struct task_struct *task = current;
57 struct hlist_head task_works;
58 struct hlist_node *pos;
59
60 raw_spin_lock_irq(&task->pi_lock);
61 hlist_move_list(&task->task_works, &task_works);
62 raw_spin_unlock_irq(&task->pi_lock);
63
64 if (unlikely(hlist_empty(&task_works)))
65 return;
66 /*
67 * We use hlist to save the space in task_struct, but we want fifo.
68 * Find the last entry, the list should be short, then process them
69 * in reverse order.
70 */
71 for (pos = task_works.first; pos->next; pos = pos->next)
72 ;
73
74 for (;;) {
75 struct hlist_node **pprev = pos->pprev;
76 struct task_work *twork = container_of(pos, struct task_work,
77 hlist);
78 twork->func(twork);
79
80 if (pprev == &task_works.first)
81 break;
82 pos = container_of(pprev, struct hlist_node, next);
83 }
84}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index f711b094ed41..3dcbf86b0d31 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -14,6 +14,7 @@
14 14
15#include <linux/sched.h> 15#include <linux/sched.h>
16#include <linux/key-type.h> 16#include <linux/key-type.h>
17#include <linux/task_work.h>
17 18
18#ifdef __KDEBUG 19#ifdef __KDEBUG
19#define kenter(FMT, ...) \ 20#define kenter(FMT, ...) \
@@ -148,6 +149,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
148#define KEY_LOOKUP_FOR_UNLINK 0x04 149#define KEY_LOOKUP_FOR_UNLINK 0x04
149 150
150extern long join_session_keyring(const char *name); 151extern long join_session_keyring(const char *name);
152extern void key_change_session_keyring(struct task_work *twork);
151 153
152extern struct work_struct key_gc_work; 154extern struct work_struct key_gc_work;
153extern unsigned key_gc_delay; 155extern unsigned key_gc_delay;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 21907ea35b15..0f5b3f027299 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1454,50 +1454,57 @@ long keyctl_get_security(key_serial_t keyid,
1454 */ 1454 */
1455long keyctl_session_to_parent(void) 1455long keyctl_session_to_parent(void)
1456{ 1456{
1457#ifdef TIF_NOTIFY_RESUME
1458 struct task_struct *me, *parent; 1457 struct task_struct *me, *parent;
1459 const struct cred *mycred, *pcred; 1458 const struct cred *mycred, *pcred;
1460 struct cred *cred, *oldcred; 1459 struct task_work *newwork, *oldwork;
1461 key_ref_t keyring_r; 1460 key_ref_t keyring_r;
1461 struct cred *cred;
1462 int ret; 1462 int ret;
1463 1463
1464 keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); 1464 keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
1465 if (IS_ERR(keyring_r)) 1465 if (IS_ERR(keyring_r))
1466 return PTR_ERR(keyring_r); 1466 return PTR_ERR(keyring_r);
1467 1467
1468 ret = -ENOMEM;
1469 newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
1470 if (!newwork)
1471 goto error_keyring;
1472
1468 /* our parent is going to need a new cred struct, a new tgcred struct 1473 /* our parent is going to need a new cred struct, a new tgcred struct
1469 * and new security data, so we allocate them here to prevent ENOMEM in 1474 * and new security data, so we allocate them here to prevent ENOMEM in
1470 * our parent */ 1475 * our parent */
1471 ret = -ENOMEM;
1472 cred = cred_alloc_blank(); 1476 cred = cred_alloc_blank();
1473 if (!cred) 1477 if (!cred)
1474 goto error_keyring; 1478 goto error_newwork;
1475 1479
1476 cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); 1480 cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
1477 keyring_r = NULL; 1481 init_task_work(newwork, key_change_session_keyring, cred);
1478 1482
1479 me = current; 1483 me = current;
1480 rcu_read_lock(); 1484 rcu_read_lock();
1481 write_lock_irq(&tasklist_lock); 1485 write_lock_irq(&tasklist_lock);
1482 1486
1483 parent = me->real_parent;
1484 ret = -EPERM; 1487 ret = -EPERM;
1488 oldwork = NULL;
1489 parent = me->real_parent;
1485 1490
1486 /* the parent mustn't be init and mustn't be a kernel thread */ 1491 /* the parent mustn't be init and mustn't be a kernel thread */
1487 if (parent->pid <= 1 || !parent->mm) 1492 if (parent->pid <= 1 || !parent->mm)
1488 goto not_permitted; 1493 goto unlock;
1489 1494
1490 /* the parent must be single threaded */ 1495 /* the parent must be single threaded */
1491 if (!thread_group_empty(parent)) 1496 if (!thread_group_empty(parent))
1492 goto not_permitted; 1497 goto unlock;
1493 1498
1494 /* the parent and the child must have different session keyrings or 1499 /* the parent and the child must have different session keyrings or
1495 * there's no point */ 1500 * there's no point */
1496 mycred = current_cred(); 1501 mycred = current_cred();
1497 pcred = __task_cred(parent); 1502 pcred = __task_cred(parent);
1498 if (mycred == pcred || 1503 if (mycred == pcred ||
1499 mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) 1504 mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) {
1500 goto already_same; 1505 ret = 0;
1506 goto unlock;
1507 }
1501 1508
1502 /* the parent must have the same effective ownership and mustn't be 1509 /* the parent must have the same effective ownership and mustn't be
1503 * SUID/SGID */ 1510 * SUID/SGID */
@@ -1507,50 +1514,40 @@ long keyctl_session_to_parent(void)
1507 pcred->gid != mycred->egid || 1514 pcred->gid != mycred->egid ||
1508 pcred->egid != mycred->egid || 1515 pcred->egid != mycred->egid ||
1509 pcred->sgid != mycred->egid) 1516 pcred->sgid != mycred->egid)
1510 goto not_permitted; 1517 goto unlock;
1511 1518
1512 /* the keyrings must have the same UID */ 1519 /* the keyrings must have the same UID */
1513 if ((pcred->tgcred->session_keyring && 1520 if ((pcred->tgcred->session_keyring &&
1514 pcred->tgcred->session_keyring->uid != mycred->euid) || 1521 pcred->tgcred->session_keyring->uid != mycred->euid) ||
1515 mycred->tgcred->session_keyring->uid != mycred->euid) 1522 mycred->tgcred->session_keyring->uid != mycred->euid)
1516 goto not_permitted; 1523 goto unlock;
1517 1524
1518 /* if there's an already pending keyring replacement, then we replace 1525 /* cancel an already pending keyring replacement */
1519 * that */ 1526 oldwork = task_work_cancel(parent, key_change_session_keyring);
1520 oldcred = parent->replacement_session_keyring;
1521 1527
1522 /* the replacement session keyring is applied just prior to userspace 1528 /* the replacement session keyring is applied just prior to userspace
1523 * restarting */ 1529 * restarting */
1524 parent->replacement_session_keyring = cred; 1530 ret = task_work_add(parent, newwork, true);
1525 cred = NULL; 1531 if (!ret)
1526 set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); 1532 newwork = NULL;
1527 1533unlock:
1528 write_unlock_irq(&tasklist_lock); 1534 write_unlock_irq(&tasklist_lock);
1529 rcu_read_unlock(); 1535 rcu_read_unlock();
1530 if (oldcred) 1536 if (oldwork) {
1531 put_cred(oldcred); 1537 put_cred(oldwork->data);
1532 return 0; 1538 kfree(oldwork);
1533 1539 }
1534already_same: 1540 if (newwork) {
1535 ret = 0; 1541 put_cred(newwork->data);
1536not_permitted: 1542 kfree(newwork);
1537 write_unlock_irq(&tasklist_lock); 1543 }
1538 rcu_read_unlock();
1539 put_cred(cred);
1540 return ret; 1544 return ret;
1541 1545
1546error_newwork:
1547 kfree(newwork);
1542error_keyring: 1548error_keyring:
1543 key_ref_put(keyring_r); 1549 key_ref_put(keyring_r);
1544 return ret; 1550 return ret;
1545
1546#else /* !TIF_NOTIFY_RESUME */
1547 /*
1548 * To be removed when TIF_NOTIFY_RESUME has been implemented on
1549 * m68k/xtensa
1550 */
1551#warning TIF_NOTIFY_RESUME not implemented
1552 return -EOPNOTSUPP;
1553#endif /* !TIF_NOTIFY_RESUME */
1554} 1551}
1555 1552
1556/* 1553/*
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index d71056db7b67..4ad54eea1ea4 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -834,23 +834,17 @@ error:
834 * Replace a process's session keyring on behalf of one of its children when 834 * Replace a process's session keyring on behalf of one of its children when
835 * the target process is about to resume userspace execution. 835 * the target process is about to resume userspace execution.
836 */ 836 */
837void key_replace_session_keyring(void) 837void key_change_session_keyring(struct task_work *twork)
838{ 838{
839 const struct cred *old; 839 const struct cred *old = current_cred();
840 struct cred *new; 840 struct cred *new = twork->data;
841
842 if (!current->replacement_session_keyring)
843 return;
844 841
845 write_lock_irq(&tasklist_lock); 842 kfree(twork);
846 new = current->replacement_session_keyring; 843 if (unlikely(current->flags & PF_EXITING)) {
847 current->replacement_session_keyring = NULL; 844 put_cred(new);
848 write_unlock_irq(&tasklist_lock);
849
850 if (!new)
851 return; 845 return;
846 }
852 847
853 old = current_cred();
854 new-> uid = old-> uid; 848 new-> uid = old-> uid;
855 new-> euid = old-> euid; 849 new-> euid = old-> euid;
856 new-> suid = old-> suid; 850 new-> suid = old-> suid;