A combination localhost+remote host security problem exists if a local user running a setuid binary causes a non-existant root .rhosts file to be created via a symbolic link with a specific kind of corefile, and then subsequently uses rsh/rlogin to enter the machine from remote.
A similar exploit might also be possible using sshd which lacks any code for
checking for deviations from the expected format in the .rhosts or .shosts
files, but we have not confirmed this yet. The following two fixes are
recommended:
(1) A kernel patch which adds a new sysctl option which permits the
administrator to decide whether setuid corefiles should be written or not.
Apply by doing
cd /sys
patch < nosuidcoredump.patch
install -c -m 444 -o root -g bin sys/sysctl.h /usr/include
cd /usr/src/usr.sbin/sysctl && make && make install
Index: kern/kern_sig.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sig.c,v
retrieving revision 1.22
retrieving revision 1.25
diff -u -r1.22 -r1.25
--- kern_sig.c 1997/11/06 05:58:18 1.22
+++ kern_sig.c 1998/01/09 16:41:09 1.25
@@ -1103,6 +1103,8 @@
/* NOTREACHED */
}
+int nosuidcoredump = 1;
+
/*
* Dump core, into a file named "progname.core", unless the process was
* setuid/setgid.
@@ -1127,6 +1129,8 @@
if ((p->p_flag & P_SUGID) &&
(error = suser(p->p_ucred, &p->p_acflag)) != 0)
return (error);
+ if ((p->p_flag & P_SUGID) && nosuidcoredump)
+ return (EPERM);
/* Don't dump if will exceed file size limit. */
if (USPACE + ctob(vm->vm_dsize + vm->vm_ssize) >=
Index: kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- kern_sysctl.c 1997/11/06 15:59:49 1.23
+++ kern_sysctl.c 1997/12/08 21:25:37 1.24
@@ -210,7 +210,7 @@
int error, level, inthostid;
extern char ostype[], osrelease[], osversion[], version[];
extern int somaxconn, sominconn;
- extern int usermount;
+ extern int usermount, nosuidcoredump;
/* all sysctl names at this level are terminal */
if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
@@ -305,6 +305,8 @@
case KERN_RND:
return (sysctl_rdstruct(oldp, oldlenp, newp, &rndstats,
sizeof(rndstats)));
+ case KERN_NOSUIDCOREDUMP:
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
&nosuidcoredump));
default:
return (EOPNOTSUPP);
}
Index: sys/sysctl.h
===================================================================
RCS file: /cvs/src/sys/sys/sysctl.h,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- sysctl.h 1997/11/06 15:59:52 1.22
+++ sysctl.h 1997/12/08 21:25:34 1.23
@@ -145,7 +145,8 @@
#define KERN_SOMINCONN 29 /* int: half-open controllable
param */
#define KERN_USERMOUNT 30 /* int: users may mount
filesystems */
#define KERN_RND 31 /* struct: rnd(4) statistics */
-#define KERN_MAXID 32 /* number of valid kern ids */
+#define KERN_NOSUIDCOREDUMP 32 /* int: no setuid coredumps ever */
+#define KERN_MAXID 33 /* number of valid kern ids */
#define CTL_KERN_NAMES { \
{ 0, 0 }, \
@@ -180,6 +181,7 @@
{ "sominconn", CTLTYPE_INT }, \
{ "usermount", CTLTYPE_INT }, \
{ "random", CTLTYPE_STRUCT }, \
+ { "nosuidcoredump", CTLTYPE_INT }, \
}
/*
(2) Replaces the libc ruserok() function with a more paranoid version which
detects bogus looking .rhosts files better.
If the first patch is used to stop setuid coredumps, then the second patch is
not as important. This problem is fixed much better in OpenBSD-current, where
the kernel's symbolic link handling has been improved such that coredumping
will not create a file on the other side of a symbolic link. Such a patch is
not possible for the 4.4lite1 VFS layer in the OpenBSD 2.2 kernel.
Apply by doing
cd /usr/src/lib/libc/net
patch -p0 < rcmd.patch
And then to reinstall libc:
cd /usr/src/lib/libc
make && make install
Index: rcmd.c
===================================================================
RCS file: /cvs/src/lib/libc/net/rcmd.c,v
retrieving revision 1.26
diff -u -r1.26 rcmd.c
--- rcmd.c 1997/07/09 01:08:47 1.26
+++ rcmd.c 1998/02/12 00:12:32
@@ -34,7 +34,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char *rcsid = "$OpenBSD: rcmd.c,v 1.26 1997/07/09 01:08:47 millert Exp
$";
+static char *rcsid = "$OpenBSD: rcmd.c,v 1.28 1998/02/11 05:28:52 deraadt Exp
$";
#endif /* LIBC_SCCS and not lint */
#include
@@ -403,39 +403,41 @@
{
register char *user, *p;
int ch;
- char buf[MAXHOSTNAMELEN + 128]; /* host + login */
+ char *buf;
const char *auser, *ahost;
int hostok, userok;
char *rhost = (char *)-1;
char domain[MAXHOSTNAMELEN];
u_int32_t raddr = (u_int32_t)raddrl;
+ size_t buflen;
getdomainname(domain, sizeof(domain));
- while (fgets(buf, sizeof(buf), hostf)) {
+ while ((buf = fgetln(hostf, &buflen))) {
p = buf;
- /* Skip lines that are too long. */
- if (strchr(p, '\n') == NULL) {
- while ((ch = getc(hostf)) != '\n' && ch != EOF)
- ;
- continue;
- }
if (*p == '#')
continue;
- while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
+ while (*p != '\n' && *p != ' ' && *p != '\t' && p < buf +
buflen) {
if (!isprint(*p))
goto bail;
*p = isupper(*p) ? tolower(*p) : *p;
p++;
}
+ if (p >= buf + buflen)
+ continue;
if (*p == ' ' || *p == '\t') {
*p++ = '\0';
- while (*p == ' ' || *p == '\t')
+ while (*p == ' ' || *p == '\t' && p < buf + buflen)
p++;
+ if (p >= buf + buflen)
+ continue;
user = p;
while (*p != '\n' && *p != ' ' &&
- *p != '\t' && *p != '\0')
+ *p != '\t' && p < buf + buflen) {
+ if (!isprint(*p))
+ goto bail;
p++;
+ }
} else
user = p;
*p = '\0';
@@ -445,6 +447,9 @@
auser = *user ? user : luser;
ahost = buf;
+
+ if (strlen(ahost) >= MAXHOSTNAMELEN)
+ continue;
/*
* innetgr() must lookup a hostname (we do not attempt)
The problem with the ruserok() function appears to also exist in ssh 1.2.21 and
previous (the ssh people have been alerted).