Bug 32791

Summary: FreeBSD's man(1) utility vulnerable to old catman attacks
Product: Base System Reporter: Tim J. Robbins <tim>
Component: binAssignee: ru <ru>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.4-STABLE   
Hardware: Any   
OS: Any   

Description Tim J. Robbins 2001-12-13 07:30:00 UTC
The catman system of the man(1) utility included with FreeBSD is vulnerable to
a whole bunch of attacks whereby the catpage's contents can be controlled
by an attacker. Discussions of the problem:
http://security-archive.merton.ox.ac.uk/security-audit-199908/
("SGID man", Solar Designer, Sun Aug 01 1999 .. and followups)
http://security-archive.merton.ox.ac.uk/security-audit-200010/0022.html
(more problems)

Fix: 

Remove the suid(!) bit from /usr/bin/man.
How-To-Repeat: There are too many ways to repeat the problem.. here's one:
$ ln -s /usr/share/man/cat1 cat1
$ mkdir man1
$ cd man1
$ cat >ls.1
oops! modified
^D
$ cd ..
$ man -M . ls     
Formatting page, please wait...Done.
oops! modified
Comment 1 ru freebsd_committer freebsd_triage 2001-12-13 13:38:04 UTC
On Thu, Dec 13, 2001 at 06:13:44PM +1100, Tim J. Robbins wrote:
> 
> The catman system of the man(1) utility included with FreeBSD is
> vulnerable to a whole bunch of attacks whereby the catpage's
> contents can be controlled by an attacker. Discussions of the
> problem:
> http://security-archive.merton.ox.ac.uk/security-audit-199908/
> ("SGID man", Solar Designer, Sun Aug 01 1999 .. and followups)
> http://security-archive.merton.ox.ac.uk/security-audit-200010/0022.html
> (more problems)
> 
> >How-To-Repeat:
> There are too many ways to repeat the problem.. here's one:
> $ ln -s /usr/share/man/cat1 cat1
> $ mkdir man1
> $ cd man1
> $ cat >ls.1
> oops! modified
> ^D
> $ cd ..
> $ man -M . ls     
> Formatting page, please wait...Done.
> oops! modified
> 
> >Fix:
> Remove the suid(!) bit from /usr/bin/man.
> 
Unfortunately, removing SUID bit from man(1) is not possible,
because it is used to create new or update obsolete catpages
in %manpath%/cat%section% directories which are usually owned
by the user ``man'', except private user directories.

The below patch doesn't allow man(1) to use its SUID powers
when the catpage's directory is accessed via symlink.

Index: man.c
===================================================================
RCS file: /home/ncvs/src/gnu/usr.bin/man/man/man.c,v
retrieving revision 1.49
diff -u -p -r1.49 man.c
--- man.c	2001/09/06 11:54:28	1.49
+++ man.c	2001/12/13 13:28:42
@@ -23,6 +23,7 @@
 #include <sys/param.h>
 #include <ctype.h>
 #include <errno.h>
+#include <libgen.h>
 #ifdef __FreeBSD__
 #include <locale.h>
 #include <langinfo.h>
@@ -1402,19 +1403,24 @@ format_and_display (path, man_file, cat_
 	    {
 
 #ifdef SETUID
-	      seteuid(euid);
-	      found = make_cat_file (path, man_file, cat_file, 1);
-	      seteuid(ruid);
-
-	      if (!found)
-	        {
-		  /* Try again as real user - see note below.
-		     By running with
-		       effective group (user) ID == real group (user) ID
-		     except for the call above, I believe the problems
-		     of reading private man pages is avoided.  */
-		  found = make_cat_file (path, man_file, cat_file, 0);
-	        }
+	      char *cat_dir = dirname(cat_file);
+	      struct stat sb;
+	      if (cat_dir != NULL && lstat(cat_dir, &sb) == 0 && S_ISDIR(sb.st_mode))
+		{
+		  seteuid(euid);
+		  found = make_cat_file (path, man_file, cat_file, 1);
+		  seteuid(ruid);
+    
+		  if (!found)
+		    {
+		      /* Try again as real user - see note below.
+			 By running with
+			   effective group (user) ID == real group (user) ID
+			 except for the call above, I believe the problems
+			 of reading private man pages is avoided.  */
+		      found = make_cat_file (path, man_file, cat_file, 0);
+		    }
+		}
 #else
 	      found = make_cat_file (path, man_file, cat_file, 0);
 #endif


Cheers,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age
Comment 2 ru freebsd_committer freebsd_triage 2001-12-13 13:38:04 UTC
On Thu, Dec 13, 2001 at 06:13:44PM +1100, Tim J. Robbins wrote:
> 
> The catman system of the man(1) utility included with FreeBSD is
> vulnerable to a whole bunch of attacks whereby the catpage's
> contents can be controlled by an attacker. Discussions of the
> problem:
> http://security-archive.merton.ox.ac.uk/security-audit-199908/
> ("SGID man", Solar Designer, Sun Aug 01 1999 .. and followups)
> http://security-archive.merton.ox.ac.uk/security-audit-200010/0022.html
> (more problems)
> 
> >How-To-Repeat:
> There are too many ways to repeat the problem.. here's one:
> $ ln -s /usr/share/man/cat1 cat1
> $ mkdir man1
> $ cd man1
> $ cat >ls.1
> oops! modified
> ^D
> $ cd ..
> $ man -M . ls     
> Formatting page, please wait...Done.
> oops! modified
> 
> >Fix:
> Remove the suid(!) bit from /usr/bin/man.
> 
Unfortunately, removing SUID bit from man(1) is not possible,
because it is used to create new or update obsolete catpages
in %manpath%/cat%section% directories which are usually owned
by the user ``man'', except private user directories.

The below patch doesn't allow man(1) to use its SUID powers
when the catpage's directory is accessed via symlink.

Index: man.c
===================================================================
RCS file: /home/ncvs/src/gnu/usr.bin/man/man/man.c,v
retrieving revision 1.49
diff -u -p -r1.49 man.c
--- man.c	2001/09/06 11:54:28	1.49
+++ man.c	2001/12/13 13:28:42
@@ -23,6 +23,7 @@
 #include <sys/param.h>
 #include <ctype.h>
 #include <errno.h>
+#include <libgen.h>
 #ifdef __FreeBSD__
 #include <locale.h>
 #include <langinfo.h>
@@ -1402,19 +1403,24 @@ format_and_display (path, man_file, cat_
 	    {
 
 #ifdef SETUID
-	      seteuid(euid);
-	      found = make_cat_file (path, man_file, cat_file, 1);
-	      seteuid(ruid);
-
-	      if (!found)
-	        {
-		  /* Try again as real user - see note below.
-		     By running with
-		       effective group (user) ID == real group (user) ID
-		     except for the call above, I believe the problems
-		     of reading private man pages is avoided.  */
-		  found = make_cat_file (path, man_file, cat_file, 0);
-	        }
+	      char *cat_dir = dirname(cat_file);
+	      struct stat sb;
+	      if (cat_dir != NULL && lstat(cat_dir, &sb) == 0 && S_ISDIR(sb.st_mode))
+		{
+		  seteuid(euid);
+		  found = make_cat_file (path, man_file, cat_file, 1);
+		  seteuid(ruid);
+    
+		  if (!found)
+		    {
+		      /* Try again as real user - see note below.
+			 By running with
+			   effective group (user) ID == real group (user) ID
+			 except for the call above, I believe the problems
+			 of reading private man pages is avoided.  */
+		      found = make_cat_file (path, man_file, cat_file, 0);
+		    }
+		}
 #else
 	      found = make_cat_file (path, man_file, cat_file, 0);
 #endif


Cheers,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message
Comment 3 Андрей Чернов 2001-12-13 16:07:13 UTC
On Thu, Dec 13, 2001 at 15:38:04 +0200, Ruslan Ermilov wrote:

> The below patch doesn't allow man(1) to use its SUID powers
> when the catpage's directory is accessed via symlink.

It breaks private cat pages (symlink check must not present for them)

-- 
Andrey A. Chernov
http://ache.pp.ru/
Comment 4 Tim J. Robbins 2001-12-14 00:57:55 UTC
On Thu, Dec 13, 2001 at 03:38:04PM +0200, Ruslan Ermilov wrote:

> Unfortunately, removing SUID bit from man(1) is not possible,
> because it is used to create new or update obsolete catpages
> in %manpath%/cat%section% directories which are usually owned
> by the user ``man'', except private user directories.

I think that making man sgid man instead of suid man would be a good
idea also; I remember Red Hat Linux used this same man utility in version 6.2
and they had it sgid. If an attacker gained uid man through a flaw in the
utility, they could plant a trojan horse and wait for root to run it.

I'll check out how it's been done in Redhat and see if I can come up
with a patch. I don't think this would break anything.

As for the catman issues, I think it's a flaw in the man utility that
it trusts the user running the command to format the manual pages.
I can't think of a good way to fix it.


Tim
Comment 5 ru freebsd_committer freebsd_triage 2001-12-14 07:56:19 UTC
On Thu, Dec 13, 2001 at 07:07:13PM +0300, Andrey A. Chernov wrote:
> On Thu, Dec 13, 2001 at 15:38:04 +0200, Ruslan Ermilov wrote:
> 
> > The below patch doesn't allow man(1) to use its SUID powers
> > when the catpage's directory is accessed via symlink.
> 
> It breaks private cat pages (symlink check must not present for them)
> 
Oops, right, wrongly placed closing brace:

Index: man.c
===================================================================
RCS file: /home/ncvs/src/gnu/usr.bin/man/man/man.c,v
retrieving revision 1.49
diff -u -p -r1.49 man.c
--- man.c	2001/09/06 11:54:28	1.49
+++ man.c	2001/12/14 07:57:03
@@ -23,6 +23,7 @@
 #include <sys/param.h>
 #include <ctype.h>
 #include <errno.h>
+#include <libgen.h>
 #ifdef __FreeBSD__
 #include <locale.h>
 #include <langinfo.h>
@@ -1402,10 +1403,15 @@ format_and_display (path, man_file, cat_
 	    {
 
 #ifdef SETUID
-	      seteuid(euid);
-	      found = make_cat_file (path, man_file, cat_file, 1);
-	      seteuid(ruid);
-
+	      char *cat_dir = dirname(cat_file);
+	      struct stat sb;
+	      if (cat_dir != NULL && lstat(cat_dir, &sb) == 0 && S_ISDIR(sb.st_mode))
+		{
+		  seteuid(euid);
+		  found = make_cat_file (path, man_file, cat_file, 1);
+		  seteuid(ruid);
+		}
+    
 	      if (!found)
 	        {
 		  /* Try again as real user - see note below.


Cheers,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age
Comment 6 ru freebsd_committer freebsd_triage 2001-12-14 07:56:19 UTC
On Thu, Dec 13, 2001 at 07:07:13PM +0300, Andrey A. Chernov wrote:
> On Thu, Dec 13, 2001 at 15:38:04 +0200, Ruslan Ermilov wrote:
> 
> > The below patch doesn't allow man(1) to use its SUID powers
> > when the catpage's directory is accessed via symlink.
> 
> It breaks private cat pages (symlink check must not present for them)
> 
Oops, right, wrongly placed closing brace:

Index: man.c
===================================================================
RCS file: /home/ncvs/src/gnu/usr.bin/man/man/man.c,v
retrieving revision 1.49
diff -u -p -r1.49 man.c
--- man.c	2001/09/06 11:54:28	1.49
+++ man.c	2001/12/14 07:57:03
@@ -23,6 +23,7 @@
 #include <sys/param.h>
 #include <ctype.h>
 #include <errno.h>
+#include <libgen.h>
 #ifdef __FreeBSD__
 #include <locale.h>
 #include <langinfo.h>
@@ -1402,10 +1403,15 @@ format_and_display (path, man_file, cat_
 	    {
 
 #ifdef SETUID
-	      seteuid(euid);
-	      found = make_cat_file (path, man_file, cat_file, 1);
-	      seteuid(ruid);
-
+	      char *cat_dir = dirname(cat_file);
+	      struct stat sb;
+	      if (cat_dir != NULL && lstat(cat_dir, &sb) == 0 && S_ISDIR(sb.st_mode))
+		{
+		  seteuid(euid);
+		  found = make_cat_file (path, man_file, cat_file, 1);
+		  seteuid(ruid);
+		}
+    
 	      if (!found)
 	        {
 		  /* Try again as real user - see note below.


Cheers,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message
Comment 7 ru freebsd_committer freebsd_triage 2001-12-14 08:04:00 UTC
On Fri, Dec 14, 2001 at 11:57:55AM +1100, Tim J. Robbins wrote:
> On Thu, Dec 13, 2001 at 03:38:04PM +0200, Ruslan Ermilov wrote:
> 
> > Unfortunately, removing SUID bit from man(1) is not possible,
> > because it is used to create new or update obsolete catpages
> > in %manpath%/cat%section% directories which are usually owned
> > by the user ``man'', except private user directories.
> 
> I think that making man sgid man instead of suid man would be a good
> idea also; I remember Red Hat Linux used this same man utility in version 6.2
> and they had it sgid. If an attacker gained uid man through a flaw in the
> utility, they could plant a trojan horse and wait for root to run it.
> 
> I'll check out how it's been done in Redhat and see if I can come up
> with a patch. I don't think this would break anything.
> 
Our man(1) uses its SUID bit only to write to catpages.

> As for the catman issues, I think it's a flaw in the man utility that
> it trusts the user running the command to format the manual pages.
> I can't think of a good way to fix it.
> 
Yeah, having in mind the other breakage, that the user is allowed
to supply his own ${GROFF_TMAC_PATH}, I think it would be a good
idea to disable this feature of man(1) to create catpages, like
it's done in OpenBSD and probably NetBSD.  Catpages are optional,
and if you have enough disk space, you can set MANBUILDCAT=YES
in your /etc/make.conf, and have ``make world'' build and install
then for you.  Also, we have a ${weekly_catman_enable} feature in
periodic.conf(5).  Removing catpaging feature of man(1) would
allow us to drop its SUIDness completely.

If there are no serious objections, I'm volunteering to do this
job after a 4.5-RELEASE.


Cheers,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age
Comment 8 ru freebsd_committer freebsd_triage 2001-12-14 08:04:00 UTC
On Fri, Dec 14, 2001 at 11:57:55AM +1100, Tim J. Robbins wrote:
> On Thu, Dec 13, 2001 at 03:38:04PM +0200, Ruslan Ermilov wrote:
> 
> > Unfortunately, removing SUID bit from man(1) is not possible,
> > because it is used to create new or update obsolete catpages
> > in %manpath%/cat%section% directories which are usually owned
> > by the user ``man'', except private user directories.
> 
> I think that making man sgid man instead of suid man would be a good
> idea also; I remember Red Hat Linux used this same man utility in version 6.2
> and they had it sgid. If an attacker gained uid man through a flaw in the
> utility, they could plant a trojan horse and wait for root to run it.
> 
> I'll check out how it's been done in Redhat and see if I can come up
> with a patch. I don't think this would break anything.
> 
Our man(1) uses its SUID bit only to write to catpages.

> As for the catman issues, I think it's a flaw in the man utility that
> it trusts the user running the command to format the manual pages.
> I can't think of a good way to fix it.
> 
Yeah, having in mind the other breakage, that the user is allowed
to supply his own ${GROFF_TMAC_PATH}, I think it would be a good
idea to disable this feature of man(1) to create catpages, like
it's done in OpenBSD and probably NetBSD.  Catpages are optional,
and if you have enough disk space, you can set MANBUILDCAT=YES
in your /etc/make.conf, and have ``make world'' build and install
then for you.  Also, we have a ${weekly_catman_enable} feature in
periodic.conf(5).  Removing catpaging feature of man(1) would
allow us to drop its SUIDness completely.

If there are no serious objections, I'm volunteering to do this
job after a 4.5-RELEASE.


Cheers,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message
Comment 9 ru freebsd_committer freebsd_triage 2002-01-09 10:21:32 UTC
Responsible Changed
From-To: freebsd-bugs->ru

I'm working on this.
Comment 10 ru freebsd_committer freebsd_triage 2002-01-15 14:11:42 UTC
State Changed
From-To: open->feedback

In FreeBSD 5.0-CURRENT, man(1) is no longer installed setuid ``man''.
Comment 11 ru freebsd_committer freebsd_triage 2005-09-28 16:59:37 UTC
State Changed
From-To: feedback->closed

After some years of thinking I decided that trusting the user 
to save formatted catpages is a misfeature.  As such, this PR 
is closed with SETUID code still in the sources but inactive.