From nobody@FreeBSD.org  Wed Oct 30 19:43:52 2013
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115])
	(using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by hub.freebsd.org (Postfix) with ESMTP id 3AEA625F
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 30 Oct 2013 19:43:52 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from oldred.freebsd.org (oldred.freebsd.org [8.8.178.121])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by mx1.freebsd.org (Postfix) with ESMTPS id 25B8D2E23
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 30 Oct 2013 19:43:52 +0000 (UTC)
Received: from oldred.freebsd.org ([127.0.1.6])
	by oldred.freebsd.org (8.14.5/8.14.7) with ESMTP id r9UJhp03016191
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 30 Oct 2013 19:43:51 GMT
	(envelope-from nobody@oldred.freebsd.org)
Received: (from nobody@localhost)
	by oldred.freebsd.org (8.14.5/8.14.5/Submit) id r9UJhpll016188;
	Wed, 30 Oct 2013 19:43:51 GMT
	(envelope-from nobody)
Message-Id: <201310301943.r9UJhpll016188@oldred.freebsd.org>
Date: Wed, 30 Oct 2013 19:43:51 GMT
From: Richard Naill <rich@enterprisesystems.net>
To: freebsd-gnats-submit@FreeBSD.org
Subject: utx.active not being updated correctly
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         183495
>Category:       misc
>Synopsis:       utx.active not being updated correctly
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    jilles
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Oct 30 19:50:00 UTC 2013
>Closed-Date:    Thu Apr 10 21:58:15 UTC 2014
>Last-Modified:  Thu Apr 10 21:58:15 UTC 2014
>Originator:     Richard Naill
>Release:        i386 9.2
>Organization:
Enterprise Systems Inc
>Environment:
FreeBSD framesbsd.entprs 9.2-RELEASE FreeBSD 9.2-RELEASE #0
>Description:
utx.active file not marking processes as terminated.

if the login process is terminated this causes the trouble.
>How-To-Repeat:
login as root
ps
find your login process
kill -9 thatprocess

login as root   again

w
will show two logins active on ttyv0 for root

problem did not exist before 9.0

some ports (doinkd) kill off all processes for an idle user
this also can create this problem


>Fix:


>Release-Note:
>Audit-Trail:

From: Ed Schouten <ed@80386.nl>
To: bug-followup@FreeBSD.org, rich@enterprisesystems.net
Cc: freebsd-hackers@freebsd.org
Subject: Re: misc/183495: utx.active not being updated correctly
Date: Wed, 13 Nov 2013 21:58:32 +0100

 Hi there,
 
 [ +freebsd-hackers, to see whether this change would go in the right direction ]
 
 It seems that the regression described in misc/183495 is unrelated to
 utmpx alone. Unlike utmp, utmpx allows multiple entries per TTY. This
 causes the issue to become actually visible.
 
 telnetd uses login(1) to provide a login prompt, interactive shell,
 etc. Looking at the source code of login(1), it seems that it never
 attempts to call pam_cleanup() whenever the process terminates with
 SIGHUP, nor does it protect itself against SIGTERM properly. The
 following patch should fix this issue partially:
 
 http://80386.nl/pub/login-signal-fix.txt
 
 Still, one issue that remains is that the parent process can still be
 killed using SIGKILL, thereby allowing you to circumvent
 pam_cleanup(). What would be the right approach to fix this? Changing
 the effective UID would solve this, but I don't feel really
 comfortable to modify these kind of pieces of software. It's easy to
 introduce security bugs.
 
 Thoughts?
 
 -- 
 Ed Schouten <ed@80386.nl>

From: Jilles Tjoelker <jilles@stack.nl>
To: Ed Schouten <ed@80386.nl>
Cc: bug-followup@FreeBSD.org, rich@enterprisesystems.net,
	freebsd-hackers@freebsd.org
Subject: Re: misc/183495: utx.active not being updated correctly
Date: Thu, 14 Nov 2013 00:36:09 +0100

 On Wed, Nov 13, 2013 at 09:58:32PM +0100, Ed Schouten wrote:
 > [ +freebsd-hackers, to see whether this change would go in the right direction ]
 
 > It seems that the regression described in misc/183495 is unrelated to
 > utmpx alone. Unlike utmp, utmpx allows multiple entries per TTY. This
 > causes the issue to become actually visible.
 
 In some sense, having at most one entry per TTY is correct. Multiple
 entries arise mostly by bugs that do not delete an entry on logout or by
 (ab)use of /usr/bin/login's setuid bit. Also, it is not possible to
 isolate two users properly if they are using the same TTY.
 
 > telnetd uses login(1) to provide a login prompt, interactive shell,
 > etc. Looking at the source code of login(1), it seems that it never
 > attempts to call pam_cleanup() whenever the process terminates with
 > SIGHUP, nor does it protect itself against SIGTERM properly. The
 > following patch should fix this issue partially:
 
 > http://80386.nl/pub/login-signal-fix.txt
 
 > Still, one issue that remains is that the parent process can still be
 > killed using SIGKILL, thereby allowing you to circumvent
 > pam_cleanup(). What would be the right approach to fix this? Changing
 > the effective UID would solve this, but I don't feel really
 > comfortable to modify these kind of pieces of software. It's easy to
 > introduce security bugs.
 
 At least on stable/9, the login [pam] process has all UIDs equal to 0
 and cannot be killed by a normal user. However, it can receive SIGHUP if
 the connection is closed. This should not lead to immediate termination,
 so the SIGHUP part of the patch seems correct, although I have not
 tested it.
 
 I am less sure about the SIGTERM part. Killing a login [pam] process may
 be a "doctor it hurts if I do this" thing. If SIGTERM is not left at its
 default action, perhaps it should kill process(es) associated with the
 session somehow (most simply, by cleaning up PAM and audit and exiting,
 which shuts down the session).
 
 The only way to avoid problems with SIGKILL would be to put the PAM and
 audit cleanup in a constantly running daemon such as init. I don't think
 this is worth it. Root should not kill -9 login [pam] processes.
 
 -- 
 Jilles Tjoelker

From: Jilles Tjoelker <jilles@stack.nl>
To: Ed Schouten <ed@80386.nl>
Cc: freebsd-hackers@freebsd.org, rich@enterprisesystems.net,
	bug-followup@FreeBSD.org
Subject: Re: misc/183495: utx.active not being updated correctly
Date: Mon, 9 Dec 2013 23:44:27 +0100

 On Thu, Nov 14, 2013 at 12:36:09AM +0100, Jilles Tjoelker wrote:
 > At least on stable/9, the login [pam] process has all UIDs equal to 0
 > and cannot be killed by a normal user. However, it can receive SIGHUP if
 > the connection is closed. This should not lead to immediate termination,
 > so the SIGHUP part of the patch seems correct, although I have not
 > tested it.
 
 > I am less sure about the SIGTERM part. Killing a login [pam] process may
 > be a "doctor it hurts if I do this" thing. If SIGTERM is not left at its
 > default action, perhaps it should kill process(es) associated with the
 > session somehow (most simply, by cleaning up PAM and audit and exiting,
 > which shuts down the session).
 
 > The only way to avoid problems with SIGKILL would be to put the PAM and
 > audit cleanup in a constantly running daemon such as init. I don't think
 > this is worth it. Root should not kill -9 login [pam] processes.
 
 After testing by Richard Naill and some more deliberation, I think the
 proper direction is to exit login(1) cleanly when SIGHUP or SIGTERM are
 received (shutting down utmpx and audit properly). This keeps the
 situation for "hung" processes after the connection is closed the same
 way as it was with the default action for SIGHUP and SIGTERM.
 
 The below patch (lightly tested) does this. I also replaced all use of
 the obsolete signal() function with sigaction() (not only the part where
 it is actually required: SIGHUP and SIGTERM must mask the other as well
 when caught).
 
 Index: usr.bin/login/login.c
 ===================================================================
 --- usr.bin/login/login.c	(revision 259027)
 +++ usr.bin/login/login.c	(working copy)
 @@ -94,6 +94,7 @@ static void		 refused(const char *, const char *,
  static const char	*stypeof(char *);
  static void		 sigint(int);
  static void		 timedout(int);
 +static void		 bail_sig(int);
  static void		 usage(void);
  
  #define	TTYGRPNAME		"tty"			/* group to own ttys */
 @@ -172,13 +173,18 @@ main(int argc, char *argv[])
  	login_cap_t *lc = NULL;
  	login_cap_t *lc_user = NULL;
  	pid_t pid;
 +	sigset_t mask, omask;
 +	struct sigaction sa;
  #ifdef USE_BSM_AUDIT
  	char auditsuccess = 1;
  #endif
  
 -	(void)signal(SIGQUIT, SIG_IGN);
 -	(void)signal(SIGINT, SIG_IGN);
 -	(void)signal(SIGHUP, SIG_IGN);
 +	sa.sa_flags = SA_RESTART;
 +	(void)sigfillset(&sa.sa_mask);
 +	sa.sa_handler = SIG_IGN;
 +	(void)sigaction(SIGQUIT, &sa, NULL);
 +	(void)sigaction(SIGINT, &sa, NULL);
 +	(void)sigaction(SIGHUP, &sa, NULL);
  	if (setjmp(timeout_buf)) {
  		if (failures)
  			badlogin(username);
 @@ -186,7 +192,8 @@ main(int argc, char *argv[])
  		    timeout);
  		bail(NO_SLEEP_EXIT, 0);
  	}
 -	(void)signal(SIGALRM, timedout);
 +	sa.sa_handler = timedout;
 +	(void)sigaction(SIGALRM, &sa, NULL);
  	(void)alarm(timeout);
  	(void)setpriority(PRIO_PROCESS, 0, 0);
  
 @@ -370,8 +377,15 @@ main(int argc, char *argv[])
  
  	/* committed to login -- turn off timeout */
  	(void)alarm((u_int)0);
 -	(void)signal(SIGHUP, SIG_DFL);
  
 +	(void)sigemptyset(&mask);
 +	(void)sigaddset(&mask, SIGHUP);
 +	(void)sigaddset(&mask, SIGTERM);
 +	(void)sigprocmask(SIG_BLOCK, &mask, &omask);
 +	sa.sa_handler = bail_sig;
 +	(void)sigaction(SIGHUP, &sa, NULL);
 +	(void)sigaction(SIGTERM, &sa, NULL);
 +
  	endpwent();
  
  #ifdef USE_BSM_AUDIT
 @@ -550,10 +564,17 @@ main(int argc, char *argv[])
  		/*
  		 * Parent: wait for child to finish, then clean up
  		 * session.
 +		 *
 +		 * If we get SIGHUP or SIGTERM, clean up the session
 +		 * and exit right away. This will make the terminal
 +		 * inaccessible and send SIGHUP to the foreground
 +		 * process group.
  		 */
  		int status;
  		setproctitle("-%s [pam]", getprogname());
 +		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  		waitpid(pid, &status, 0);
 +		(void)sigprocmask(SIG_BLOCK, &mask, NULL);
  		bail(NO_SLEEP_EXIT, 0);
  	}
  
 @@ -627,10 +648,15 @@ main(int argc, char *argv[])
  	login_close(lc_user);
  	login_close(lc);
  
 -	(void)signal(SIGALRM, SIG_DFL);
 -	(void)signal(SIGQUIT, SIG_DFL);
 -	(void)signal(SIGINT, SIG_DFL);
 -	(void)signal(SIGTSTP, SIG_IGN);
 +	sa.sa_handler = SIG_DFL;
 +	(void)sigaction(SIGALRM, &sa, NULL);
 +	(void)sigaction(SIGQUIT, &sa, NULL);
 +	(void)sigaction(SIGINT, &sa, NULL);
 +	(void)sigaction(SIGTERM, &sa, NULL);
 +	(void)sigaction(SIGHUP, &sa, NULL);
 +	sa.sa_handler = SIG_IGN;
 +	(void)sigaction(SIGTSTP, &sa, NULL);
 +	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  
  	/*
  	 * Login shells have a leading '-' in front of argv[0]
 @@ -847,7 +873,7 @@ sigint(int signo __unused)
  static int
  motd(const char *motdfile)
  {
 -	sig_t oldint;
 +	struct sigaction newint, oldint;
  	FILE *f;
  	int ch;
  
 @@ -854,10 +880,13 @@ motd(const char *motdfile)
  	if ((f = fopen(motdfile, "r")) == NULL)
  		return (-1);
  	motdinterrupt = 0;
 -	oldint = signal(SIGINT, sigint);
 +	newint.sa_handler = sigint;
 +	newint.sa_flags = 0;
 +	sigfillset(&newint.sa_mask);
 +	sigaction(SIGINT, &newint, &oldint);
  	while ((ch = fgetc(f)) != EOF && !motdinterrupt)
  		putchar(ch);
 -	signal(SIGINT, oldint);
 +	sigaction(SIGINT, &oldint, NULL);
  	if (ch != EOF || ferror(f)) {
  		fclose(f);
  		return (-1);
 @@ -972,6 +1001,8 @@ pam_cleanup(void)
  void
  bail(int sec, int eval)
  {
 +	struct sigaction sa;
 +	int signo;
  
  	pam_cleanup();
  #ifdef USE_BSM_AUDIT
 @@ -979,5 +1010,28 @@ bail(int sec, int eval)
  		audit_logout();
  #endif
  	(void)sleep(sec);
 -	exit(eval);
 +	if (eval < 256)
 +		exit(eval);
 +	else {
 +		signo = eval - 256;
 +		sa.sa_handler = SIG_DFL;
 +		sa.sa_flags = 0;
 +		(void)sigemptyset(&sa.sa_mask);
 +		(void)sigaction(signo, &sa, NULL);
 +		(void)sigaddset(&sa.sa_mask, signo);
 +		(void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
 +		raise(signo);
 +		exit(128 + signo);
 +	}
  }
 +
 +/*
 + * Exit because of a signal.
 + * This is not async-signal safe, so only call async-signal safe functions
 + * while the signal is unmasked.
 + */
 +static void
 +bail_sig(int signo)
 +{
 +	bail(NO_SLEEP_EXIT, 256 + signo);
 +}
 
 -- 
 Jilles Tjoelker

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: misc/183495: commit references a PR
Date: Sun, 26 Jan 2014 22:49:33 +0000 (UTC)

 Author: jilles
 Date: Sun Jan 26 22:49:24 2014
 New Revision: 261193
 URL: http://svnweb.freebsd.org/changeset/base/261193
 
 Log:
   login: Clean up PAM and audit, then exit, on SIGHUP and SIGTERM.
   
   This avoids leaving stale entries in utmpx after the connection is closed on
   an open login session. It also allows a clean way (SIGTERM) to forcibly
   terminate a user's terminal session.
   
   This does not affect the situation for "hung" processes after the connection
   is closed. The foreground process group receives SIGHUP and the tty becomes
   inaccessible.
   
   Also replace all use of the obsolete signal() function with sigaction() (not
   only the part where it is actually required: SIGHUP and SIGTERM must mask
   the other as well when caught).
   
   PR:		misc/183495
   Reviewed by:	ed
 
 Modified:
   head/usr.bin/login/login.c
 
 Modified: head/usr.bin/login/login.c
 ==============================================================================
 --- head/usr.bin/login/login.c	Sun Jan 26 21:19:33 2014	(r261192)
 +++ head/usr.bin/login/login.c	Sun Jan 26 22:49:24 2014	(r261193)
 @@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
  
  static int		 auth_pam(void);
  static void		 bail(int, int);
 +static void		 bail_internal(int, int, int);
  static int		 export(const char *);
  static void		 export_pam_environment(void);
  static int		 motd(const char *);
 @@ -94,6 +95,7 @@ static void		 refused(const char *, cons
  static const char	*stypeof(char *);
  static void		 sigint(int);
  static void		 timedout(int);
 +static void		 bail_sig(int);
  static void		 usage(void);
  
  #define	TTYGRPNAME		"tty"			/* group to own ttys */
 @@ -172,13 +174,18 @@ main(int argc, char *argv[])
  	login_cap_t *lc = NULL;
  	login_cap_t *lc_user = NULL;
  	pid_t pid;
 +	sigset_t mask, omask;
 +	struct sigaction sa;
  #ifdef USE_BSM_AUDIT
  	char auditsuccess = 1;
  #endif
  
 -	(void)signal(SIGQUIT, SIG_IGN);
 -	(void)signal(SIGINT, SIG_IGN);
 -	(void)signal(SIGHUP, SIG_IGN);
 +	sa.sa_flags = SA_RESTART;
 +	(void)sigfillset(&sa.sa_mask);
 +	sa.sa_handler = SIG_IGN;
 +	(void)sigaction(SIGQUIT, &sa, NULL);
 +	(void)sigaction(SIGINT, &sa, NULL);
 +	(void)sigaction(SIGHUP, &sa, NULL);
  	if (setjmp(timeout_buf)) {
  		if (failures)
  			badlogin(username);
 @@ -186,7 +193,8 @@ main(int argc, char *argv[])
  		    timeout);
  		bail(NO_SLEEP_EXIT, 0);
  	}
 -	(void)signal(SIGALRM, timedout);
 +	sa.sa_handler = timedout;
 +	(void)sigaction(SIGALRM, &sa, NULL);
  	(void)alarm(timeout);
  	(void)setpriority(PRIO_PROCESS, 0, 0);
  
 @@ -370,7 +378,14 @@ main(int argc, char *argv[])
  
  	/* committed to login -- turn off timeout */
  	(void)alarm((u_int)0);
 -	(void)signal(SIGHUP, SIG_DFL);
 +
 +	(void)sigemptyset(&mask);
 +	(void)sigaddset(&mask, SIGHUP);
 +	(void)sigaddset(&mask, SIGTERM);
 +	(void)sigprocmask(SIG_BLOCK, &mask, &omask);
 +	sa.sa_handler = bail_sig;
 +	(void)sigaction(SIGHUP, &sa, NULL);
 +	(void)sigaction(SIGTERM, &sa, NULL);
  
  	endpwent();
  
 @@ -550,10 +565,17 @@ main(int argc, char *argv[])
  		/*
  		 * Parent: wait for child to finish, then clean up
  		 * session.
 +		 *
 +		 * If we get SIGHUP or SIGTERM, clean up the session
 +		 * and exit right away. This will make the terminal
 +		 * inaccessible and send SIGHUP to the foreground
 +		 * process group.
  		 */
  		int status;
  		setproctitle("-%s [pam]", getprogname());
 +		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  		waitpid(pid, &status, 0);
 +		(void)sigprocmask(SIG_BLOCK, &mask, NULL);
  		bail(NO_SLEEP_EXIT, 0);
  	}
  
 @@ -627,10 +649,15 @@ main(int argc, char *argv[])
  	login_close(lc_user);
  	login_close(lc);
  
 -	(void)signal(SIGALRM, SIG_DFL);
 -	(void)signal(SIGQUIT, SIG_DFL);
 -	(void)signal(SIGINT, SIG_DFL);
 -	(void)signal(SIGTSTP, SIG_IGN);
 +	sa.sa_handler = SIG_DFL;
 +	(void)sigaction(SIGALRM, &sa, NULL);
 +	(void)sigaction(SIGQUIT, &sa, NULL);
 +	(void)sigaction(SIGINT, &sa, NULL);
 +	(void)sigaction(SIGTERM, &sa, NULL);
 +	(void)sigaction(SIGHUP, &sa, NULL);
 +	sa.sa_handler = SIG_IGN;
 +	(void)sigaction(SIGTSTP, &sa, NULL);
 +	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  
  	/*
  	 * Login shells have a leading '-' in front of argv[0]
 @@ -847,17 +874,20 @@ sigint(int signo __unused)
  static int
  motd(const char *motdfile)
  {
 -	sig_t oldint;
 +	struct sigaction newint, oldint;
  	FILE *f;
  	int ch;
  
  	if ((f = fopen(motdfile, "r")) == NULL)
  		return (-1);
  	motdinterrupt = 0;
 -	oldint = signal(SIGINT, sigint);
 +	newint.sa_handler = sigint;
 +	newint.sa_flags = 0;
 +	sigfillset(&newint.sa_mask);
 +	sigaction(SIGINT, &newint, &oldint);
  	while ((ch = fgetc(f)) != EOF && !motdinterrupt)
  		putchar(ch);
 -	signal(SIGINT, oldint);
 +	sigaction(SIGINT, &oldint, NULL);
  	if (ch != EOF || ferror(f)) {
  		fclose(f);
  		return (-1);
 @@ -966,12 +996,10 @@ pam_cleanup(void)
  	}
  }
  
 -/*
 - * Exit, optionally after sleeping a few seconds
 - */
 -void
 -bail(int sec, int eval)
 +static void
 +bail_internal(int sec, int eval, int signo)
  {
 +	struct sigaction sa;
  
  	pam_cleanup();
  #ifdef USE_BSM_AUDIT
 @@ -979,5 +1007,36 @@ bail(int sec, int eval)
  		audit_logout();
  #endif
  	(void)sleep(sec);
 -	exit(eval);
 +	if (signo == 0)
 +		exit(eval);
 +	else {
 +		sa.sa_handler = SIG_DFL;
 +		sa.sa_flags = 0;
 +		(void)sigemptyset(&sa.sa_mask);
 +		(void)sigaction(signo, &sa, NULL);
 +		(void)sigaddset(&sa.sa_mask, signo);
 +		(void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
 +		raise(signo);
 +		exit(128 + signo);
 +	}
 +}
 +
 +/*
 + * Exit, optionally after sleeping a few seconds
 + */
 +static void
 +bail(int sec, int eval)
 +{
 +	bail_internal(sec, eval, 0);
 +}
 +
 +/*
 + * Exit because of a signal.
 + * This is not async-signal safe, so only call async-signal safe functions
 + * while the signal is unmasked.
 + */
 +static void
 +bail_sig(int signo)
 +{
 +	bail_internal(NO_SLEEP_EXIT, 0, signo);
  }
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: jilles 
State-Changed-When: Sun Jan 26 23:00:35 UTC 2014 
State-Changed-Why:  
Fixed in 11-current. Thanks for the report. 


Responsible-Changed-From-To: freebsd-bugs->jilles 
Responsible-Changed-By: jilles 
Responsible-Changed-When: Sun Jan 26 23:00:35 UTC 2014 
Responsible-Changed-Why:  
I committed the fix. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=183495 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: misc/183495: commit references a PR
Date: Sun,  6 Apr 2014 10:56:32 +0000 (UTC)

 Author: jilles
 Date: Sun Apr  6 10:56:27 2014
 New Revision: 264192
 URL: http://svnweb.freebsd.org/changeset/base/264192
 
 Log:
   login: Clean up PAM and audit, then exit, on SIGHUP and SIGTERM.
   
   This avoids leaving stale entries in utmpx after the connection is closed on
   an open login session. It also allows a clean way (SIGTERM) to forcibly
   terminate a user's terminal session.
   
   This does not affect the situation for "hung" processes after the connection
   is closed. The foreground process group receives SIGHUP and the tty becomes
   inaccessible.
   
   Also replace all use of the obsolete signal() function with sigaction() (not
   only the part where it is actually required: SIGHUP and SIGTERM must mask
   the other as well when caught).
   
   PR:		misc/183495
 
 Modified:
   stable/10/usr.bin/login/login.c
 Directory Properties:
   stable/10/   (props changed)
 
 Modified: stable/10/usr.bin/login/login.c
 ==============================================================================
 --- stable/10/usr.bin/login/login.c	Sun Apr  6 10:13:14 2014	(r264191)
 +++ stable/10/usr.bin/login/login.c	Sun Apr  6 10:56:27 2014	(r264192)
 @@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
  
  static int		 auth_pam(void);
  static void		 bail(int, int);
 +static void		 bail_internal(int, int, int);
  static int		 export(const char *);
  static void		 export_pam_environment(void);
  static int		 motd(const char *);
 @@ -94,6 +95,7 @@ static void		 refused(const char *, cons
  static const char	*stypeof(char *);
  static void		 sigint(int);
  static void		 timedout(int);
 +static void		 bail_sig(int);
  static void		 usage(void);
  
  #define	TTYGRPNAME		"tty"			/* group to own ttys */
 @@ -172,13 +174,18 @@ main(int argc, char *argv[])
  	login_cap_t *lc = NULL;
  	login_cap_t *lc_user = NULL;
  	pid_t pid;
 +	sigset_t mask, omask;
 +	struct sigaction sa;
  #ifdef USE_BSM_AUDIT
  	char auditsuccess = 1;
  #endif
  
 -	(void)signal(SIGQUIT, SIG_IGN);
 -	(void)signal(SIGINT, SIG_IGN);
 -	(void)signal(SIGHUP, SIG_IGN);
 +	sa.sa_flags = SA_RESTART;
 +	(void)sigfillset(&sa.sa_mask);
 +	sa.sa_handler = SIG_IGN;
 +	(void)sigaction(SIGQUIT, &sa, NULL);
 +	(void)sigaction(SIGINT, &sa, NULL);
 +	(void)sigaction(SIGHUP, &sa, NULL);
  	if (setjmp(timeout_buf)) {
  		if (failures)
  			badlogin(username);
 @@ -186,7 +193,8 @@ main(int argc, char *argv[])
  		    timeout);
  		bail(NO_SLEEP_EXIT, 0);
  	}
 -	(void)signal(SIGALRM, timedout);
 +	sa.sa_handler = timedout;
 +	(void)sigaction(SIGALRM, &sa, NULL);
  	(void)alarm(timeout);
  	(void)setpriority(PRIO_PROCESS, 0, 0);
  
 @@ -370,7 +378,14 @@ main(int argc, char *argv[])
  
  	/* committed to login -- turn off timeout */
  	(void)alarm((u_int)0);
 -	(void)signal(SIGHUP, SIG_DFL);
 +
 +	(void)sigemptyset(&mask);
 +	(void)sigaddset(&mask, SIGHUP);
 +	(void)sigaddset(&mask, SIGTERM);
 +	(void)sigprocmask(SIG_BLOCK, &mask, &omask);
 +	sa.sa_handler = bail_sig;
 +	(void)sigaction(SIGHUP, &sa, NULL);
 +	(void)sigaction(SIGTERM, &sa, NULL);
  
  	endpwent();
  
 @@ -550,10 +565,17 @@ main(int argc, char *argv[])
  		/*
  		 * Parent: wait for child to finish, then clean up
  		 * session.
 +		 *
 +		 * If we get SIGHUP or SIGTERM, clean up the session
 +		 * and exit right away. This will make the terminal
 +		 * inaccessible and send SIGHUP to the foreground
 +		 * process group.
  		 */
  		int status;
  		setproctitle("-%s [pam]", getprogname());
 +		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  		waitpid(pid, &status, 0);
 +		(void)sigprocmask(SIG_BLOCK, &mask, NULL);
  		bail(NO_SLEEP_EXIT, 0);
  	}
  
 @@ -627,10 +649,15 @@ main(int argc, char *argv[])
  	login_close(lc_user);
  	login_close(lc);
  
 -	(void)signal(SIGALRM, SIG_DFL);
 -	(void)signal(SIGQUIT, SIG_DFL);
 -	(void)signal(SIGINT, SIG_DFL);
 -	(void)signal(SIGTSTP, SIG_IGN);
 +	sa.sa_handler = SIG_DFL;
 +	(void)sigaction(SIGALRM, &sa, NULL);
 +	(void)sigaction(SIGQUIT, &sa, NULL);
 +	(void)sigaction(SIGINT, &sa, NULL);
 +	(void)sigaction(SIGTERM, &sa, NULL);
 +	(void)sigaction(SIGHUP, &sa, NULL);
 +	sa.sa_handler = SIG_IGN;
 +	(void)sigaction(SIGTSTP, &sa, NULL);
 +	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  
  	/*
  	 * Login shells have a leading '-' in front of argv[0]
 @@ -847,17 +874,20 @@ sigint(int signo __unused)
  static int
  motd(const char *motdfile)
  {
 -	sig_t oldint;
 +	struct sigaction newint, oldint;
  	FILE *f;
  	int ch;
  
  	if ((f = fopen(motdfile, "r")) == NULL)
  		return (-1);
  	motdinterrupt = 0;
 -	oldint = signal(SIGINT, sigint);
 +	newint.sa_handler = sigint;
 +	newint.sa_flags = 0;
 +	sigfillset(&newint.sa_mask);
 +	sigaction(SIGINT, &newint, &oldint);
  	while ((ch = fgetc(f)) != EOF && !motdinterrupt)
  		putchar(ch);
 -	signal(SIGINT, oldint);
 +	sigaction(SIGINT, &oldint, NULL);
  	if (ch != EOF || ferror(f)) {
  		fclose(f);
  		return (-1);
 @@ -966,12 +996,10 @@ pam_cleanup(void)
  	}
  }
  
 -/*
 - * Exit, optionally after sleeping a few seconds
 - */
 -void
 -bail(int sec, int eval)
 +static void
 +bail_internal(int sec, int eval, int signo)
  {
 +	struct sigaction sa;
  
  	pam_cleanup();
  #ifdef USE_BSM_AUDIT
 @@ -979,5 +1007,36 @@ bail(int sec, int eval)
  		audit_logout();
  #endif
  	(void)sleep(sec);
 -	exit(eval);
 +	if (signo == 0)
 +		exit(eval);
 +	else {
 +		sa.sa_handler = SIG_DFL;
 +		sa.sa_flags = 0;
 +		(void)sigemptyset(&sa.sa_mask);
 +		(void)sigaction(signo, &sa, NULL);
 +		(void)sigaddset(&sa.sa_mask, signo);
 +		(void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
 +		raise(signo);
 +		exit(128 + signo);
 +	}
 +}
 +
 +/*
 + * Exit, optionally after sleeping a few seconds
 + */
 +static void
 +bail(int sec, int eval)
 +{
 +	bail_internal(sec, eval, 0);
 +}
 +
 +/*
 + * Exit because of a signal.
 + * This is not async-signal safe, so only call async-signal safe functions
 + * while the signal is unmasked.
 + */
 +static void
 +bail_sig(int signo)
 +{
 +	bail_internal(NO_SLEEP_EXIT, 0, signo);
  }
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: misc/183495: commit references a PR
Date: Wed,  9 Apr 2014 21:19:52 +0000 (UTC)

 Author: jilles
 Date: Wed Apr  9 21:19:46 2014
 New Revision: 264309
 URL: http://svnweb.freebsd.org/changeset/base/264309
 
 Log:
   MFC r261193: login: Clean up PAM and audit, then exit, on SIGHUP and SIGTERM
   
   This avoids leaving stale entries in utmpx after the connection is closed on
   an open login session. It also allows a clean way (SIGTERM) to forcibly
   terminate a user's terminal session.
   
   This does not affect the situation for "hung" processes after the connection
   is closed. The foreground process group receives SIGHUP and the tty becomes
   inaccessible.
   
   Also replace all use of the obsolete signal() function with sigaction() (not
   only the part where it is actually required: SIGHUP and SIGTERM must mask
   the other as well when caught).
   
   PR:		misc/183495
 
 Modified:
   stable/9/usr.bin/login/login.c
 Directory Properties:
   stable/9/usr.bin/login/   (props changed)
 
 Modified: stable/9/usr.bin/login/login.c
 ==============================================================================
 --- stable/9/usr.bin/login/login.c	Wed Apr  9 20:42:00 2014	(r264308)
 +++ stable/9/usr.bin/login/login.c	Wed Apr  9 21:19:46 2014	(r264309)
 @@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
  
  static int		 auth_pam(void);
  static void		 bail(int, int);
 +static void		 bail_internal(int, int, int);
  static int		 export(const char *);
  static void		 export_pam_environment(void);
  static int		 motd(const char *);
 @@ -94,6 +95,7 @@ static void		 refused(const char *, cons
  static const char	*stypeof(char *);
  static void		 sigint(int);
  static void		 timedout(int);
 +static void		 bail_sig(int);
  static void		 usage(void);
  
  #define	TTYGRPNAME		"tty"			/* group to own ttys */
 @@ -172,13 +174,18 @@ main(int argc, char *argv[])
  	login_cap_t *lc = NULL;
  	login_cap_t *lc_user = NULL;
  	pid_t pid;
 +	sigset_t mask, omask;
 +	struct sigaction sa;
  #ifdef USE_BSM_AUDIT
  	char auditsuccess = 1;
  #endif
  
 -	(void)signal(SIGQUIT, SIG_IGN);
 -	(void)signal(SIGINT, SIG_IGN);
 -	(void)signal(SIGHUP, SIG_IGN);
 +	sa.sa_flags = SA_RESTART;
 +	(void)sigfillset(&sa.sa_mask);
 +	sa.sa_handler = SIG_IGN;
 +	(void)sigaction(SIGQUIT, &sa, NULL);
 +	(void)sigaction(SIGINT, &sa, NULL);
 +	(void)sigaction(SIGHUP, &sa, NULL);
  	if (setjmp(timeout_buf)) {
  		if (failures)
  			badlogin(username);
 @@ -186,7 +193,8 @@ main(int argc, char *argv[])
  		    timeout);
  		bail(NO_SLEEP_EXIT, 0);
  	}
 -	(void)signal(SIGALRM, timedout);
 +	sa.sa_handler = timedout;
 +	(void)sigaction(SIGALRM, &sa, NULL);
  	(void)alarm(timeout);
  	(void)setpriority(PRIO_PROCESS, 0, 0);
  
 @@ -370,7 +378,14 @@ main(int argc, char *argv[])
  
  	/* committed to login -- turn off timeout */
  	(void)alarm((u_int)0);
 -	(void)signal(SIGHUP, SIG_DFL);
 +
 +	(void)sigemptyset(&mask);
 +	(void)sigaddset(&mask, SIGHUP);
 +	(void)sigaddset(&mask, SIGTERM);
 +	(void)sigprocmask(SIG_BLOCK, &mask, &omask);
 +	sa.sa_handler = bail_sig;
 +	(void)sigaction(SIGHUP, &sa, NULL);
 +	(void)sigaction(SIGTERM, &sa, NULL);
  
  	endpwent();
  
 @@ -550,10 +565,17 @@ main(int argc, char *argv[])
  		/*
  		 * Parent: wait for child to finish, then clean up
  		 * session.
 +		 *
 +		 * If we get SIGHUP or SIGTERM, clean up the session
 +		 * and exit right away. This will make the terminal
 +		 * inaccessible and send SIGHUP to the foreground
 +		 * process group.
  		 */
  		int status;
  		setproctitle("-%s [pam]", getprogname());
 +		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  		waitpid(pid, &status, 0);
 +		(void)sigprocmask(SIG_BLOCK, &mask, NULL);
  		bail(NO_SLEEP_EXIT, 0);
  	}
  
 @@ -627,10 +649,15 @@ main(int argc, char *argv[])
  	login_close(lc_user);
  	login_close(lc);
  
 -	(void)signal(SIGALRM, SIG_DFL);
 -	(void)signal(SIGQUIT, SIG_DFL);
 -	(void)signal(SIGINT, SIG_DFL);
 -	(void)signal(SIGTSTP, SIG_IGN);
 +	sa.sa_handler = SIG_DFL;
 +	(void)sigaction(SIGALRM, &sa, NULL);
 +	(void)sigaction(SIGQUIT, &sa, NULL);
 +	(void)sigaction(SIGINT, &sa, NULL);
 +	(void)sigaction(SIGTERM, &sa, NULL);
 +	(void)sigaction(SIGHUP, &sa, NULL);
 +	sa.sa_handler = SIG_IGN;
 +	(void)sigaction(SIGTSTP, &sa, NULL);
 +	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  
  	/*
  	 * Login shells have a leading '-' in front of argv[0]
 @@ -847,17 +874,20 @@ sigint(int signo __unused)
  static int
  motd(const char *motdfile)
  {
 -	sig_t oldint;
 +	struct sigaction newint, oldint;
  	FILE *f;
  	int ch;
  
  	if ((f = fopen(motdfile, "r")) == NULL)
  		return (-1);
  	motdinterrupt = 0;
 -	oldint = signal(SIGINT, sigint);
 +	newint.sa_handler = sigint;
 +	newint.sa_flags = 0;
 +	sigfillset(&newint.sa_mask);
 +	sigaction(SIGINT, &newint, &oldint);
  	while ((ch = fgetc(f)) != EOF && !motdinterrupt)
  		putchar(ch);
 -	signal(SIGINT, oldint);
 +	sigaction(SIGINT, &oldint, NULL);
  	if (ch != EOF || ferror(f)) {
  		fclose(f);
  		return (-1);
 @@ -966,12 +996,10 @@ pam_cleanup(void)
  	}
  }
  
 -/*
 - * Exit, optionally after sleeping a few seconds
 - */
 -void
 -bail(int sec, int eval)
 +static void
 +bail_internal(int sec, int eval, int signo)
  {
 +	struct sigaction sa;
  
  	pam_cleanup();
  #ifdef USE_BSM_AUDIT
 @@ -979,5 +1007,36 @@ bail(int sec, int eval)
  		audit_logout();
  #endif
  	(void)sleep(sec);
 -	exit(eval);
 +	if (signo == 0)
 +		exit(eval);
 +	else {
 +		sa.sa_handler = SIG_DFL;
 +		sa.sa_flags = 0;
 +		(void)sigemptyset(&sa.sa_mask);
 +		(void)sigaction(signo, &sa, NULL);
 +		(void)sigaddset(&sa.sa_mask, signo);
 +		(void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
 +		raise(signo);
 +		exit(128 + signo);
 +	}
 +}
 +
 +/*
 + * Exit, optionally after sleeping a few seconds
 + */
 +static void
 +bail(int sec, int eval)
 +{
 +	bail_internal(sec, eval, 0);
 +}
 +
 +/*
 + * Exit because of a signal.
 + * This is not async-signal safe, so only call async-signal safe functions
 + * while the signal is unmasked.
 + */
 +static void
 +bail_sig(int signo)
 +{
 +	bail_internal(NO_SLEEP_EXIT, 0, signo);
  }
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: jilles 
State-Changed-When: Thu Apr 10 21:57:47 UTC 2014 
State-Changed-Why:  
Fixed in stable/9, stable/10 and head. 
No MFC planned to earlier branches. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=183495 
>Unformatted:
