mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 97fd75b7b8 ("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
			
			
This commit is contained in:
		
						commit
						fb21affa49
					
				
					 45 changed files with 220 additions and 186 deletions
				
			
		| 
						 | 
				
			
			@ -590,7 +590,5 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -679,7 +679,5 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
 | 
			
		|||
	if (thread_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -587,7 +587,7 @@ fault_exit_work:
 | 
			
		|||
	ld.w	r1, r0[TI_flags]
 | 
			
		||||
	rjmp	fault_exit_work
 | 
			
		||||
 | 
			
		||||
1:	mov	r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
 | 
			
		||||
1:	mov	r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME
 | 
			
		||||
	tst	r1, r2
 | 
			
		||||
	breq	2f
 | 
			
		||||
	unmask_interrupts
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -321,7 +321,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti)
 | 
			
		|||
	if (ti->flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -336,8 +336,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs)
 | 
			
		|||
	if (test_thread_flag(TIF_NOTIFY_RESUME)) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -364,7 +364,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags,
 | 
			
		|||
	if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,5 @@ void do_notify_resume(int canrestart, struct pt_regs *regs,
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -562,8 +562,6 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags)
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(__frame);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
} /* end do_notify_resume() */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -513,7 +513,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -273,8 +273,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -199,8 +199,6 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
 | 
			
		|||
	if (test_thread_flag(TIF_NOTIFY_RESUME)) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(&scr->pt);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* copy user rbs to kernel rbs */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -383,8 +383,6 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags)
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clear_thread_flag(TIF_IRET);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1193,9 +1193,6 @@ void do_notify_resume(struct pt_regs *regs)
 | 
			
		|||
	if (test_thread_flag(TIF_SIGPENDING))
 | 
			
		||||
		do_signal(regs);
 | 
			
		||||
 | 
			
		||||
	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
 | 
			
		||||
	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -401,9 +401,6 @@ void do_notify_resume(struct pt_regs *regs, int in_syscall)
 | 
			
		|||
	if (test_thread_flag(TIF_SIGPENDING))
 | 
			
		||||
		do_signal(regs, in_syscall);
 | 
			
		||||
 | 
			
		||||
	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
 | 
			
		||||
	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -636,8 +636,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -554,7 +554,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(current_frame());
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -376,7 +376,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs)
 | 
			
		|||
	if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2032,7 +2032,7 @@ syscall_check_resched:
 | 
			
		|||
	.import do_signal,code
 | 
			
		||||
syscall_check_sig:
 | 
			
		||||
	LDREG	TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19
 | 
			
		||||
	ldi	(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r26
 | 
			
		||||
	ldi	(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NOTIFY_RESUME), %r26
 | 
			
		||||
	and,COND(<>)	%r19, %r26, %r0
 | 
			
		||||
	b,n	syscall_restore	/* skip past if we've nothing to do */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -638,7 +638,5 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall)
 | 
			
		|||
	if (test_thread_flag(TIF_NOTIFY_RESUME)) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -193,8 +193,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -494,6 +494,4 @@ void do_notify_resume(struct pt_regs *regs)
 | 
			
		|||
{
 | 
			
		||||
	clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
	tracehook_notify_resume(regs);
 | 
			
		||||
	if (current->replacement_session_keyring)
 | 
			
		||||
		key_replace_session_keyring();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -356,7 +356,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -626,7 +626,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -685,7 +685,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -590,8 +590,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -607,8 +607,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -565,8 +565,6 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (thread_info_flags & _TIF_SINGLESTEP) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,11 +117,8 @@ void interrupt_end(void)
 | 
			
		|||
		schedule();
 | 
			
		||||
	if (test_thread_flag(TIF_SIGPENDING))
 | 
			
		||||
		do_signal();
 | 
			
		||||
	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
 | 
			
		||||
	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
 | 
			
		||||
		tracehook_notify_resume(¤t->thread.regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void exit_thread(void)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -464,8 +464,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
 | 
			
		|||
	if (thread_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -827,8 +827,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 | 
			
		|||
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 | 
			
		||||
		clear_thread_flag(TIF_NOTIFY_RESUME);
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
	if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
 | 
			
		||||
		fire_user_return_notifiers();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -548,9 +548,6 @@ void do_notify_resume(struct pt_regs *regs)
 | 
			
		|||
	if (test_thread_flag(TIF_SIGPENDING))
 | 
			
		||||
		do_signal(regs);
 | 
			
		||||
 | 
			
		||||
	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
 | 
			
		||||
	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
 | 
			
		||||
		tracehook_notify_resume(regs);
 | 
			
		||||
		if (current->replacement_session_keyring)
 | 
			
		||||
			key_replace_session_keyring();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,8 +142,6 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler,
 | 
			
		|||
extern int __must_check
 | 
			
		||||
request_percpu_irq(unsigned int irq, irq_handler_t handler,
 | 
			
		||||
		   const char *devname, void __percpu *percpu_dev_id);
 | 
			
		||||
 | 
			
		||||
extern void exit_irq_thread(void);
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
extern int __must_check
 | 
			
		||||
| 
						 | 
				
			
			@ -177,8 +175,6 @@ request_percpu_irq(unsigned int irq, irq_handler_t handler,
 | 
			
		|||
{
 | 
			
		||||
	return request_irq(irq, handler, 0, devname, percpu_dev_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void exit_irq_thread(void) { }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern void free_irq(unsigned int, void *);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -308,9 +308,6 @@ static inline bool key_is_instantiated(const struct key *key)
 | 
			
		|||
#ifdef CONFIG_SYSCTL
 | 
			
		||||
extern ctl_table key_sysctls[];
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern void key_replace_session_keyring(void);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * the userspace interface
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -334,7 +331,6 @@ extern void key_init(void);
 | 
			
		|||
#define key_fsuid_changed(t)		do { } while(0)
 | 
			
		||||
#define key_fsgid_changed(t)		do { } while(0)
 | 
			
		||||
#define key_init()			do { } while(0)
 | 
			
		||||
#define key_replace_session_keyring()	do { } while(0)
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_KEYS */
 | 
			
		||||
#endif /* __KERNEL__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1301,11 +1301,6 @@ struct task_struct {
 | 
			
		|||
	unsigned sched_reset_on_fork:1;
 | 
			
		||||
	unsigned sched_contributes_to_load:1;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_GENERIC_HARDIRQS
 | 
			
		||||
	/* IRQ handler threads */
 | 
			
		||||
	unsigned irq_thread:1;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	pid_t pid;
 | 
			
		||||
	pid_t tgid;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1313,7 +1308,6 @@ struct task_struct {
 | 
			
		|||
	/* Canary value for the -fstack-protector gcc feature */
 | 
			
		||||
	unsigned long stack_canary;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * pointers to (original) parent process, youngest child, younger sibling,
 | 
			
		||||
	 * older sibling, respectively.  (p->father can be replaced with
 | 
			
		||||
| 
						 | 
				
			
			@ -1363,8 +1357,6 @@ struct task_struct {
 | 
			
		|||
					 * credentials (COW) */
 | 
			
		||||
	const struct cred __rcu *cred;	/* effective (overridable) subjective task
 | 
			
		||||
					 * credentials (COW) */
 | 
			
		||||
	struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */
 | 
			
		||||
 | 
			
		||||
	char comm[TASK_COMM_LEN]; /* executable name excluding path
 | 
			
		||||
				     - access with [gs]et_task_comm (which lock
 | 
			
		||||
				       it with task_lock())
 | 
			
		||||
| 
						 | 
				
			
			@ -1400,6 +1392,8 @@ struct task_struct {
 | 
			
		|||
	int (*notifier)(void *priv);
 | 
			
		||||
	void *notifier_data;
 | 
			
		||||
	sigset_t *notifier_mask;
 | 
			
		||||
	struct hlist_head task_works;
 | 
			
		||||
 | 
			
		||||
	struct audit_context *audit_context;
 | 
			
		||||
#ifdef CONFIG_AUDITSYSCALL
 | 
			
		||||
	uid_t loginuid;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										33
									
								
								include/linux/task_work.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								include/linux/task_work.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
#ifndef _LINUX_TASK_WORK_H
 | 
			
		||||
#define _LINUX_TASK_WORK_H
 | 
			
		||||
 | 
			
		||||
#include <linux/list.h>
 | 
			
		||||
#include <linux/sched.h>
 | 
			
		||||
 | 
			
		||||
struct task_work;
 | 
			
		||||
typedef void (*task_work_func_t)(struct task_work *);
 | 
			
		||||
 | 
			
		||||
struct task_work {
 | 
			
		||||
	struct hlist_node hlist;
 | 
			
		||||
	task_work_func_t func;
 | 
			
		||||
	void *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
init_task_work(struct task_work *twork, task_work_func_t func, void *data)
 | 
			
		||||
{
 | 
			
		||||
	twork->func = func;
 | 
			
		||||
	twork->data = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int task_work_add(struct task_struct *task, struct task_work *twork, bool);
 | 
			
		||||
struct task_work *task_work_cancel(struct task_struct *, task_work_func_t);
 | 
			
		||||
void task_work_run(void);
 | 
			
		||||
 | 
			
		||||
static inline void exit_task_work(struct task_struct *task)
 | 
			
		||||
{
 | 
			
		||||
	if (unlikely(!hlist_empty(&task->task_works)))
 | 
			
		||||
		task_work_run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif	/* _LINUX_TASK_WORK_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +49,7 @@
 | 
			
		|||
#include <linux/sched.h>
 | 
			
		||||
#include <linux/ptrace.h>
 | 
			
		||||
#include <linux/security.h>
 | 
			
		||||
#include <linux/task_work.h>
 | 
			
		||||
struct linux_binprm;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +154,6 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
 | 
			
		|||
		ptrace_notify(SIGTRAP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef TIF_NOTIFY_RESUME
 | 
			
		||||
/**
 | 
			
		||||
 * set_notify_resume - cause tracehook_notify_resume() to be called
 | 
			
		||||
 * @task:		task that will call tracehook_notify_resume()
 | 
			
		||||
| 
						 | 
				
			
			@ -165,8 +165,10 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
 | 
			
		|||
 */
 | 
			
		||||
static inline void set_notify_resume(struct task_struct *task)
 | 
			
		||||
{
 | 
			
		||||
#ifdef TIF_NOTIFY_RESUME
 | 
			
		||||
	if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_RESUME))
 | 
			
		||||
		kick_process(task);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +186,14 @@ static inline void set_notify_resume(struct task_struct *task)
 | 
			
		|||
 */
 | 
			
		||||
static inline void tracehook_notify_resume(struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * The caller just cleared TIF_NOTIFY_RESUME. This barrier
 | 
			
		||||
	 * pairs with task_work_add()->set_notify_resume() after
 | 
			
		||||
	 * hlist_add_head(task->task_works);
 | 
			
		||||
	 */
 | 
			
		||||
	smp_mb__after_clear_bit();
 | 
			
		||||
	if (unlikely(!hlist_empty(¤t->task_works)))
 | 
			
		||||
		task_work_run();
 | 
			
		||||
}
 | 
			
		||||
#endif	/* TIF_NOTIFY_RESUME */
 | 
			
		||||
 | 
			
		||||
#endif	/* <linux/tracehook.h> */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
obj-y     = fork.o exec_domain.o panic.o printk.o \
 | 
			
		||||
	    cpu.o exit.o itimer.o time.o softirq.o resource.o \
 | 
			
		||||
	    sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
 | 
			
		||||
	    signal.o sys.o kmod.o workqueue.o pid.o \
 | 
			
		||||
	    signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
 | 
			
		||||
	    rcupdate.o extable.o params.o posix-timers.o \
 | 
			
		||||
	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 | 
			
		||||
	    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -207,13 +207,6 @@ void exit_creds(struct task_struct *tsk)
 | 
			
		|||
	validate_creds(cred);
 | 
			
		||||
	alter_cred_subscribers(cred, -1);
 | 
			
		||||
	put_cred(cred);
 | 
			
		||||
 | 
			
		||||
	cred = (struct cred *) tsk->replacement_session_keyring;
 | 
			
		||||
	if (cred) {
 | 
			
		||||
		tsk->replacement_session_keyring = NULL;
 | 
			
		||||
		validate_creds(cred);
 | 
			
		||||
		put_cred(cred);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -396,8 +389,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
 | 
			
		|||
	struct cred *new;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	p->replacement_session_keyring = NULL;
 | 
			
		||||
 | 
			
		||||
	if (
 | 
			
		||||
#ifdef CONFIG_KEYS
 | 
			
		||||
		!p->cred->thread_keyring &&
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -946,12 +946,13 @@ void do_exit(long code)
 | 
			
		|||
	exit_signals(tsk);  /* sets PF_EXITING */
 | 
			
		||||
	/*
 | 
			
		||||
	 * tsk->flags are checked in the futex code to protect against
 | 
			
		||||
	 * an exiting task cleaning up the robust pi futexes.
 | 
			
		||||
	 * an exiting task cleaning up the robust pi futexes, and in
 | 
			
		||||
	 * task_work_add() to avoid the race with exit_task_work().
 | 
			
		||||
	 */
 | 
			
		||||
	smp_mb();
 | 
			
		||||
	raw_spin_unlock_wait(&tsk->pi_lock);
 | 
			
		||||
 | 
			
		||||
	exit_irq_thread();
 | 
			
		||||
	exit_task_work(tsk);
 | 
			
		||||
 | 
			
		||||
	if (unlikely(in_atomic()))
 | 
			
		||||
		printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1415,6 +1415,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 | 
			
		|||
	 */
 | 
			
		||||
	p->group_leader = p;
 | 
			
		||||
	INIT_LIST_HEAD(&p->thread_group);
 | 
			
		||||
	INIT_HLIST_HEAD(&p->task_works);
 | 
			
		||||
 | 
			
		||||
	/* Now that the task is set up, run cgroup callbacks if
 | 
			
		||||
	 * necessary. We need to run them before the task is visible
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@
 | 
			
		|||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/sched.h>
 | 
			
		||||
#include <linux/task_work.h>
 | 
			
		||||
 | 
			
		||||
#include "internals.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -775,11 +776,39 @@ static void wake_threads_waitq(struct irq_desc *desc)
 | 
			
		|||
		wake_up(&desc->wait_for_threads);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void irq_thread_dtor(struct task_work *unused)
 | 
			
		||||
{
 | 
			
		||||
	struct task_struct *tsk = current;
 | 
			
		||||
	struct irq_desc *desc;
 | 
			
		||||
	struct irqaction *action;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON_ONCE(!(current->flags & PF_EXITING)))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	action = kthread_data(tsk);
 | 
			
		||||
 | 
			
		||||
	pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
 | 
			
		||||
	       tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	desc = irq_to_desc(action->irq);
 | 
			
		||||
	/*
 | 
			
		||||
	 * If IRQTF_RUNTHREAD is set, we need to decrement
 | 
			
		||||
	 * desc->threads_active and wake possible waiters.
 | 
			
		||||
	 */
 | 
			
		||||
	if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
 | 
			
		||||
		wake_threads_waitq(desc);
 | 
			
		||||
 | 
			
		||||
	/* Prevent a stale desc->threads_oneshot */
 | 
			
		||||
	irq_finalize_oneshot(desc, action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Interrupt handler thread
 | 
			
		||||
 */
 | 
			
		||||
static int irq_thread(void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct task_work on_exit_work;
 | 
			
		||||
	static const struct sched_param param = {
 | 
			
		||||
		.sched_priority = MAX_USER_RT_PRIO/2,
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			@ -795,7 +824,9 @@ static int irq_thread(void *data)
 | 
			
		|||
		handler_fn = irq_thread_fn;
 | 
			
		||||
 | 
			
		||||
	sched_setscheduler(current, SCHED_FIFO, ¶m);
 | 
			
		||||
	current->irq_thread = 1;
 | 
			
		||||
 | 
			
		||||
	init_task_work(&on_exit_work, irq_thread_dtor, NULL);
 | 
			
		||||
	task_work_add(current, &on_exit_work, false);
 | 
			
		||||
 | 
			
		||||
	while (!irq_wait_for_interrupt(action)) {
 | 
			
		||||
		irqreturn_t action_ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -817,44 +848,11 @@ static int irq_thread(void *data)
 | 
			
		|||
	 * cannot touch the oneshot mask at this point anymore as
 | 
			
		||||
	 * __setup_irq() might have given out currents thread_mask
 | 
			
		||||
	 * again.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Clear irq_thread. Otherwise exit_irq_thread() would make
 | 
			
		||||
	 * fuzz about an active irq thread going into nirvana.
 | 
			
		||||
	 */
 | 
			
		||||
	current->irq_thread = 0;
 | 
			
		||||
	task_work_cancel(current, irq_thread_dtor);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Called from do_exit()
 | 
			
		||||
 */
 | 
			
		||||
void exit_irq_thread(void)
 | 
			
		||||
{
 | 
			
		||||
	struct task_struct *tsk = current;
 | 
			
		||||
	struct irq_desc *desc;
 | 
			
		||||
	struct irqaction *action;
 | 
			
		||||
 | 
			
		||||
	if (!tsk->irq_thread)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	action = kthread_data(tsk);
 | 
			
		||||
 | 
			
		||||
	pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
 | 
			
		||||
	       tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
 | 
			
		||||
 | 
			
		||||
	desc = irq_to_desc(action->irq);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If IRQTF_RUNTHREAD is set, we need to decrement
 | 
			
		||||
	 * desc->threads_active and wake possible waiters.
 | 
			
		||||
	 */
 | 
			
		||||
	if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
 | 
			
		||||
		wake_threads_waitq(desc);
 | 
			
		||||
 | 
			
		||||
	/* Prevent a stale desc->threads_oneshot */
 | 
			
		||||
	irq_finalize_oneshot(desc, action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void irq_setup_forced_threading(struct irqaction *new)
 | 
			
		||||
{
 | 
			
		||||
	if (!force_irqthreads)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										84
									
								
								kernel/task_work.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								kernel/task_work.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
#include <linux/spinlock.h>
 | 
			
		||||
#include <linux/task_work.h>
 | 
			
		||||
#include <linux/tracehook.h>
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
task_work_add(struct task_struct *task, struct task_work *twork, bool notify)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int err = -ESRCH;
 | 
			
		||||
 | 
			
		||||
#ifndef TIF_NOTIFY_RESUME
 | 
			
		||||
	if (notify)
 | 
			
		||||
		return -ENOTSUPP;
 | 
			
		||||
#endif
 | 
			
		||||
	/*
 | 
			
		||||
	 * We must not insert the new work if the task has already passed
 | 
			
		||||
	 * exit_task_work(). We rely on do_exit()->raw_spin_unlock_wait()
 | 
			
		||||
	 * and check PF_EXITING under pi_lock.
 | 
			
		||||
	 */
 | 
			
		||||
	raw_spin_lock_irqsave(&task->pi_lock, flags);
 | 
			
		||||
	if (likely(!(task->flags & PF_EXITING))) {
 | 
			
		||||
		hlist_add_head(&twork->hlist, &task->task_works);
 | 
			
		||||
		err = 0;
 | 
			
		||||
	}
 | 
			
		||||
	raw_spin_unlock_irqrestore(&task->pi_lock, flags);
 | 
			
		||||
 | 
			
		||||
	/* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */
 | 
			
		||||
	if (likely(!err) && notify)
 | 
			
		||||
		set_notify_resume(task);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct task_work *
 | 
			
		||||
task_work_cancel(struct task_struct *task, task_work_func_t func)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	struct task_work *twork;
 | 
			
		||||
	struct hlist_node *pos;
 | 
			
		||||
 | 
			
		||||
	raw_spin_lock_irqsave(&task->pi_lock, flags);
 | 
			
		||||
	hlist_for_each_entry(twork, pos, &task->task_works, hlist) {
 | 
			
		||||
		if (twork->func == func) {
 | 
			
		||||
			hlist_del(&twork->hlist);
 | 
			
		||||
			goto found;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	twork = NULL;
 | 
			
		||||
 found:
 | 
			
		||||
	raw_spin_unlock_irqrestore(&task->pi_lock, flags);
 | 
			
		||||
 | 
			
		||||
	return twork;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void task_work_run(void)
 | 
			
		||||
{
 | 
			
		||||
	struct task_struct *task = current;
 | 
			
		||||
	struct hlist_head task_works;
 | 
			
		||||
	struct hlist_node *pos;
 | 
			
		||||
 | 
			
		||||
	raw_spin_lock_irq(&task->pi_lock);
 | 
			
		||||
	hlist_move_list(&task->task_works, &task_works);
 | 
			
		||||
	raw_spin_unlock_irq(&task->pi_lock);
 | 
			
		||||
 | 
			
		||||
	if (unlikely(hlist_empty(&task_works)))
 | 
			
		||||
		return;
 | 
			
		||||
	/*
 | 
			
		||||
	 * We use hlist to save the space in task_struct, but we want fifo.
 | 
			
		||||
	 * Find the last entry, the list should be short, then process them
 | 
			
		||||
	 * in reverse order.
 | 
			
		||||
	 */
 | 
			
		||||
	for (pos = task_works.first; pos->next; pos = pos->next)
 | 
			
		||||
		;
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		struct hlist_node **pprev = pos->pprev;
 | 
			
		||||
		struct task_work *twork = container_of(pos, struct task_work,
 | 
			
		||||
							hlist);
 | 
			
		||||
		twork->func(twork);
 | 
			
		||||
 | 
			
		||||
		if (pprev == &task_works.first)
 | 
			
		||||
			break;
 | 
			
		||||
		pos = container_of(pprev, struct hlist_node, next);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
 | 
			
		||||
#include <linux/sched.h>
 | 
			
		||||
#include <linux/key-type.h>
 | 
			
		||||
#include <linux/task_work.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __KDEBUG
 | 
			
		||||
#define kenter(FMT, ...) \
 | 
			
		||||
| 
						 | 
				
			
			@ -148,6 +149,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
 | 
			
		|||
#define KEY_LOOKUP_FOR_UNLINK	0x04
 | 
			
		||||
 | 
			
		||||
extern long join_session_keyring(const char *name);
 | 
			
		||||
extern void key_change_session_keyring(struct task_work *twork);
 | 
			
		||||
 | 
			
		||||
extern struct work_struct key_gc_work;
 | 
			
		||||
extern unsigned key_gc_delay;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1454,50 +1454,57 @@ long keyctl_get_security(key_serial_t keyid,
 | 
			
		|||
 */
 | 
			
		||||
long keyctl_session_to_parent(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef TIF_NOTIFY_RESUME
 | 
			
		||||
	struct task_struct *me, *parent;
 | 
			
		||||
	const struct cred *mycred, *pcred;
 | 
			
		||||
	struct cred *cred, *oldcred;
 | 
			
		||||
	struct task_work *newwork, *oldwork;
 | 
			
		||||
	key_ref_t keyring_r;
 | 
			
		||||
	struct cred *cred;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
 | 
			
		||||
	if (IS_ERR(keyring_r))
 | 
			
		||||
		return PTR_ERR(keyring_r);
 | 
			
		||||
 | 
			
		||||
	ret = -ENOMEM;
 | 
			
		||||
	newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
 | 
			
		||||
	if (!newwork)
 | 
			
		||||
		goto error_keyring;
 | 
			
		||||
 | 
			
		||||
	/* our parent is going to need a new cred struct, a new tgcred struct
 | 
			
		||||
	 * and new security data, so we allocate them here to prevent ENOMEM in
 | 
			
		||||
	 * our parent */
 | 
			
		||||
	ret = -ENOMEM;
 | 
			
		||||
	cred = cred_alloc_blank();
 | 
			
		||||
	if (!cred)
 | 
			
		||||
		goto error_keyring;
 | 
			
		||||
		goto error_newwork;
 | 
			
		||||
 | 
			
		||||
	cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
 | 
			
		||||
	keyring_r = NULL;
 | 
			
		||||
	init_task_work(newwork, key_change_session_keyring, cred);
 | 
			
		||||
 | 
			
		||||
	me = current;
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	write_lock_irq(&tasklist_lock);
 | 
			
		||||
 | 
			
		||||
	parent = me->real_parent;
 | 
			
		||||
	ret = -EPERM;
 | 
			
		||||
	oldwork = NULL;
 | 
			
		||||
	parent = me->real_parent;
 | 
			
		||||
 | 
			
		||||
	/* the parent mustn't be init and mustn't be a kernel thread */
 | 
			
		||||
	if (parent->pid <= 1 || !parent->mm)
 | 
			
		||||
		goto not_permitted;
 | 
			
		||||
		goto unlock;
 | 
			
		||||
 | 
			
		||||
	/* the parent must be single threaded */
 | 
			
		||||
	if (!thread_group_empty(parent))
 | 
			
		||||
		goto not_permitted;
 | 
			
		||||
		goto unlock;
 | 
			
		||||
 | 
			
		||||
	/* the parent and the child must have different session keyrings or
 | 
			
		||||
	 * there's no point */
 | 
			
		||||
	mycred = current_cred();
 | 
			
		||||
	pcred = __task_cred(parent);
 | 
			
		||||
	if (mycred == pcred ||
 | 
			
		||||
	    mycred->tgcred->session_keyring == pcred->tgcred->session_keyring)
 | 
			
		||||
		goto already_same;
 | 
			
		||||
	    mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) {
 | 
			
		||||
		ret = 0;
 | 
			
		||||
		goto unlock;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* the parent must have the same effective ownership and mustn't be
 | 
			
		||||
	 * SUID/SGID */
 | 
			
		||||
| 
						 | 
				
			
			@ -1507,50 +1514,40 @@ long keyctl_session_to_parent(void)
 | 
			
		|||
	    pcred->gid	!= mycred->egid	||
 | 
			
		||||
	    pcred->egid	!= mycred->egid	||
 | 
			
		||||
	    pcred->sgid	!= mycred->egid)
 | 
			
		||||
		goto not_permitted;
 | 
			
		||||
		goto unlock;
 | 
			
		||||
 | 
			
		||||
	/* the keyrings must have the same UID */
 | 
			
		||||
	if ((pcred->tgcred->session_keyring &&
 | 
			
		||||
	     pcred->tgcred->session_keyring->uid != mycred->euid) ||
 | 
			
		||||
	    mycred->tgcred->session_keyring->uid != mycred->euid)
 | 
			
		||||
		goto not_permitted;
 | 
			
		||||
		goto unlock;
 | 
			
		||||
 | 
			
		||||
	/* if there's an already pending keyring replacement, then we replace
 | 
			
		||||
	 * that */
 | 
			
		||||
	oldcred = parent->replacement_session_keyring;
 | 
			
		||||
	/* cancel an already pending keyring replacement */
 | 
			
		||||
	oldwork = task_work_cancel(parent, key_change_session_keyring);
 | 
			
		||||
 | 
			
		||||
	/* the replacement session keyring is applied just prior to userspace
 | 
			
		||||
	 * restarting */
 | 
			
		||||
	parent->replacement_session_keyring = cred;
 | 
			
		||||
	cred = NULL;
 | 
			
		||||
	set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME);
 | 
			
		||||
 | 
			
		||||
	ret = task_work_add(parent, newwork, true);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		newwork = NULL;
 | 
			
		||||
unlock:
 | 
			
		||||
	write_unlock_irq(&tasklist_lock);
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	if (oldcred)
 | 
			
		||||
		put_cred(oldcred);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
already_same:
 | 
			
		||||
	ret = 0;
 | 
			
		||||
not_permitted:
 | 
			
		||||
	write_unlock_irq(&tasklist_lock);
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	put_cred(cred);
 | 
			
		||||
	if (oldwork) {
 | 
			
		||||
		put_cred(oldwork->data);
 | 
			
		||||
		kfree(oldwork);
 | 
			
		||||
	}
 | 
			
		||||
	if (newwork) {
 | 
			
		||||
		put_cred(newwork->data);
 | 
			
		||||
		kfree(newwork);
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
error_newwork:
 | 
			
		||||
	kfree(newwork);
 | 
			
		||||
error_keyring:
 | 
			
		||||
	key_ref_put(keyring_r);
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
#else /* !TIF_NOTIFY_RESUME */
 | 
			
		||||
	/*
 | 
			
		||||
	 * To be removed when TIF_NOTIFY_RESUME has been implemented on
 | 
			
		||||
	 * m68k/xtensa
 | 
			
		||||
	 */
 | 
			
		||||
#warning TIF_NOTIFY_RESUME not implemented
 | 
			
		||||
	return -EOPNOTSUPP;
 | 
			
		||||
#endif /* !TIF_NOTIFY_RESUME */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -834,23 +834,17 @@ long join_session_keyring(const char *name)
 | 
			
		|||
 * Replace a process's session keyring on behalf of one of its children when
 | 
			
		||||
 * the target  process is about to resume userspace execution.
 | 
			
		||||
 */
 | 
			
		||||
void key_replace_session_keyring(void)
 | 
			
		||||
void key_change_session_keyring(struct task_work *twork)
 | 
			
		||||
{
 | 
			
		||||
	const struct cred *old;
 | 
			
		||||
	struct cred *new;
 | 
			
		||||
	const struct cred *old = current_cred();
 | 
			
		||||
	struct cred *new = twork->data;
 | 
			
		||||
 | 
			
		||||
	if (!current->replacement_session_keyring)
 | 
			
		||||
	kfree(twork);
 | 
			
		||||
	if (unlikely(current->flags & PF_EXITING)) {
 | 
			
		||||
		put_cred(new);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	write_lock_irq(&tasklist_lock);
 | 
			
		||||
	new = current->replacement_session_keyring;
 | 
			
		||||
	current->replacement_session_keyring = NULL;
 | 
			
		||||
	write_unlock_irq(&tasklist_lock);
 | 
			
		||||
 | 
			
		||||
	if (!new)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	old = current_cred();
 | 
			
		||||
	new->  uid	= old->  uid;
 | 
			
		||||
	new-> euid	= old-> euid;
 | 
			
		||||
	new-> suid	= old-> suid;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue