Module Name:    src
Committed By:   martin
Date:           Sat Nov  6 13:35:43 UTC 2021

Modified Files:
        src/bin/sh [netbsd-9]: main.c memalloc.c memalloc.h options.c sh.1
            shell.h

Log Message:
Pull up following revision(s) (requested by kre in ticket #1371):

        bin/sh/main.c: revision 1.87
        bin/sh/main.c: revision 1.88
        bin/sh/memalloc.h: revision 1.20
        bin/sh/sh.1: revision 1.235
        bin/sh/memalloc.c: revision 1.34
        bin/sh/memalloc.c: revision 1.35
        bin/sh/memalloc.h: revision 1.19
        bin/sh/shell.h: revision 1.31
        bin/sh/options.c: revision 1.56

PR bin/56464

After almost 30 years, finally do the right thing and read $HOME/.profile
rather than .profile in the initial directory (it was that way in version
1.1 ...)   All other ash descendants seem to have fixed this long ago.
While here, copy a feature from FreeBSD which allows "set +p" (if a
shell run by a setuid process with the -p flag is privileged) to reset
the privileges.  Once done (the set +p) it cannot be undone (a later
set -p sets the 'p' flag, but that's all it does) - that just becomes a
one bit storage location.

We do this, as (also copying from FreeBSD, and because it is the right
thing to do) we don't run .profile in a privileged shell - FreeBSD run
/etc/suid_profile in that case (not a good name, it also applies to setgid
shells) but I see no real need for that, we run /etc/profile in any case,
anything that would go in /etc/suid_profile can just go in /etc/profile
instead (with suitable guards so the commands only run in priv'd shells).

One or two minor DEBUG mode changes (notably having priv'd shells identify
themselves in the DEBUG trace) and sh.1 changes with doc of the "set +p"
change, the effect that has on $PSc and a few other wording tweaks.

XXX pullup -9   (not -8, this isn't worth it for the short lifetime
that has left - if it took 28+ years for anyone to notice this, it
cannot be having all that much effect).

Use a type-correct end marker for strstrcat() rather than NULL, as
for a function with unknown number & types of args, the compiler isn't
able to automatically convert to the correct type.   Issue pointed out
in off list e-mail by Rolland Illig ... Thanks.

The first arg (pointer to where to put length of result) is of a known
type, so doesn't have the same issue - we can keep using NULL for that
one when the length isn't needed.
Also, make sure to return a correctly null terminated null string in
the (absurd) case that there are no non-null args to strstrcat() (though
there are much better ways to generate "" on the stack).  Since there is
currently just one call in the code, and it has real string args, this
isn't an issue for now, but who knows, some day.

NFCI - if there is any real change, then it is a change that is required.

XXX pullup -9 (together with the previous changes)


To generate a diff of this commit:
cvs rdiff -u -r1.82.2.1 -r1.82.2.2 src/bin/sh/main.c
cvs rdiff -u -r1.33 -r1.33.2.1 src/bin/sh/memalloc.c
cvs rdiff -u -r1.18 -r1.18.2.1 src/bin/sh/memalloc.h
cvs rdiff -u -r1.53 -r1.53.2.1 src/bin/sh/options.c
cvs rdiff -u -r1.223 -r1.223.2.1 src/bin/sh/sh.1
cvs rdiff -u -r1.29 -r1.29.2.1 src/bin/sh/shell.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/sh/main.c
diff -u src/bin/sh/main.c:1.82.2.1 src/bin/sh/main.c:1.82.2.2
--- src/bin/sh/main.c:1.82.2.1	Mon Feb 10 18:54:14 2020
+++ src/bin/sh/main.c	Sat Nov  6 13:35:43 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.82.2.1 2020/02/10 18:54:14 martin Exp $	*/
+/*	$NetBSD: main.c,v 1.82.2.2 2021/11/06 13:35:43 martin Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -42,7 +42,7 @@ __COPYRIGHT("@(#) Copyright (c) 1991, 19
 #if 0
 static char sccsid[] = "@(#)main.c	8.7 (Berkeley) 7/19/95";
 #else
-__RCSID("$NetBSD: main.c,v 1.82.2.1 2020/02/10 18:54:14 martin Exp $");
+__RCSID("$NetBSD: main.c,v 1.82.2.2 2021/11/06 13:35:43 martin Exp $");
 #endif
 #endif /* not lint */
 
@@ -51,6 +51,7 @@ __RCSID("$NetBSD: main.c,v 1.82.2.1 2020
 #include <signal.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <locale.h>
 #include <fcntl.h>
@@ -85,6 +86,7 @@ int rootpid;
 int rootshell;
 struct jmploc main_handler;
 int max_user_fd;
+bool privileged;
 #if PROFILE
 short profile_buf[16384];
 extern int etext();
@@ -109,6 +111,7 @@ main(int argc, char **argv)
 	uid_t uid;
 	gid_t gid;
 	sigset_t mask;
+	bool waspriv;
 
 	/*
 	 * If we happen to be invoked with SIGCHLD ignored, we cannot
@@ -128,6 +131,8 @@ main(int argc, char **argv)
 	uid = getuid();
 	gid = getgid();
 
+	waspriv = privileged = (uid != geteuid()) || (gid != getegid());
+
 	max_user_fd = fcntl(0, F_MAXFD);
 	if (max_user_fd < 2)
 		max_user_fd = 2;
@@ -192,6 +197,8 @@ main(int argc, char **argv)
 	debug = 1;	/* this may be reset by procargs() later */
 #endif
 	opentrace();
+	if (privileged)
+		trputs("Privileged ");
 	trputs("Shell args:  ");  trargs(argv);
 #if DEBUG >= 3
 	set_debug(((DEBUG)==3 ? "_@" : "++"), 1);
@@ -204,6 +211,7 @@ main(int argc, char **argv)
 	setstackmark(&smark);
 	procargs(argc, argv);
 
+#if 0	/* This now happens (indirectly) in the procargs() just above */
 	/*
 	 * Limit bogus system(3) or popen(3) calls in setuid binaries,
 	 * by requiring the -p flag
@@ -214,18 +222,35 @@ main(int argc, char **argv)
 		/* PS1 might need to be changed accordingly. */
 		choose_ps1();
 	}
+#else	/* except for this one little bit */
+	if (waspriv && !privileged)
+		choose_ps1();
+#endif
 
 	if (argv[0] && argv[0][0] == '-') {
 		state = 1;
 		read_profile("/etc/profile");
  state1:
 		state = 2;
-		read_profile(".profile");
+		if (!privileged) {
+			char *profile;
+			const char *home;
+
+			home = lookupvar("HOME");
+			if (home == NULL)
+				home = nullstr;
+			profile = ststrcat(NULL, home, "/.profile", STSTRC_END);
+			read_profile(profile);
+			stunalloc(profile);
+		}
+#if 0	/* FreeBSD does (effectively) ...*/
+		else
+			read_profile("/etc/suid_profile");
+#endif
 	}
  state2:
 	state = 3;
-	if ((iflag || !posix) &&
-	    getuid() == geteuid() && getgid() == getegid()) {
+	if ((iflag || !posix) && !privileged) {
 		struct stackmark env_smark;
 
 		setstackmark(&env_smark);
@@ -254,6 +279,8 @@ main(int argc, char **argv)
 		    setsignal(sigs[i], 0);
 	}
 
+	rststackmark(&smark);	/* this one is never popped */
+
 	if (minusc)
 		evalstring(minusc, sflag ? 0 : EV_EXIT);
 

Index: src/bin/sh/memalloc.c
diff -u src/bin/sh/memalloc.c:1.33 src/bin/sh/memalloc.c:1.33.2.1
--- src/bin/sh/memalloc.c:1.33	Sat Feb  9 03:35:55 2019
+++ src/bin/sh/memalloc.c	Sat Nov  6 13:35:43 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: memalloc.c,v 1.33 2019/02/09 03:35:55 kre Exp $	*/
+/*	$NetBSD: memalloc.c,v 1.33.2.1 2021/11/06 13:35:43 martin Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,10 +37,12 @@
 #if 0
 static char sccsid[] = "@(#)memalloc.c	8.3 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: memalloc.c,v 1.33 2019/02/09 03:35:55 kre Exp $");
+__RCSID("$NetBSD: memalloc.c,v 1.33.2.1 2021/11/06 13:35:43 martin Exp $");
 #endif
 #endif /* not lint */
 
+#include <limits.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <unistd.h>
 
@@ -338,3 +340,66 @@ ungrabstackstr(char *s, char *p)
 	stacknxt = s;
 	sstrnleft = stacknleft - (p - s);
 }
+
+/*
+ * Save the concat of a sequence of strings in stack space
+ *
+ * The first arg (if not NULL) is a pointer to where the final string
+ * length will be returned.
+ *
+ * Remaining args are pointers to strings - sufficient space to hold
+ * the concat of the strings is allocated on the stack, the strings
+ * are copied into that space, and a pointer to its start is retured.
+ * The arg list is terminated with STSTRC_END.
+ *
+ * Use stunalloc(string) (in proper sequence) to release the string
+ */
+char *
+ststrcat(size_t *lp, ...)
+{
+	va_list ap;
+	const char *arg;
+	size_t len, tlen = 0, alen[8];
+	char *str, *nxt;
+	unsigned int n;
+
+	n = 0;
+	va_start(ap, lp);
+	arg = va_arg(ap, const char *);
+	while (arg != STSTRC_END) {
+		len = strlen(arg);
+		if (n < sizeof(alen)/sizeof(alen[0]))
+			alen[n++] = len;
+		tlen += len;
+		arg = va_arg(ap, const char *);
+	}
+	va_end(ap);
+
+	if (lp != NULL)
+		*lp = tlen;
+
+	if (tlen >= INT_MAX)
+		error("ststrcat() over length botch");
+	str = (char *)stalloc((int)tlen + 1);	/* 1 for \0 */
+	str[tlen] = '\0';	/* in case of no args  */
+
+	n = 0;
+	nxt = str;
+	va_start(ap, lp);
+	arg = va_arg(ap, const char *);
+	while (arg != STSTRC_END) {
+		if (n < sizeof(alen)/sizeof(alen[0]))
+			len = alen[n++];
+		else
+			len = strlen(arg);
+
+		scopy(arg, nxt);
+		nxt += len;
+
+		arg = va_arg(ap, const char *);
+	}
+	va_end(ap);
+
+	return str;
+}
+

Index: src/bin/sh/memalloc.h
diff -u src/bin/sh/memalloc.h:1.18 src/bin/sh/memalloc.h:1.18.2.1
--- src/bin/sh/memalloc.h:1.18	Wed Aug 22 20:08:54 2018
+++ src/bin/sh/memalloc.h	Sat Nov  6 13:35:43 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: memalloc.h,v 1.18 2018/08/22 20:08:54 kre Exp $	*/
+/*	$NetBSD: memalloc.h,v 1.18.2.1 2021/11/06 13:35:43 martin Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -62,6 +62,9 @@ char *growstackstr(void);
 char *makestrspace(void);
 void ungrabstackstr(char *, char *);
 
+char *ststrcat(size_t *, ...);
+#define STSTRC_END	((const char *)0)
+
 
 
 #define stackblock() stacknxt

Index: src/bin/sh/options.c
diff -u src/bin/sh/options.c:1.53 src/bin/sh/options.c:1.53.2.1
--- src/bin/sh/options.c:1.53	Fri Jul 13 22:43:44 2018
+++ src/bin/sh/options.c	Sat Nov  6 13:35:43 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: options.c,v 1.53 2018/07/13 22:43:44 kre Exp $	*/
+/*	$NetBSD: options.c,v 1.53.2.1 2021/11/06 13:35:43 martin Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)options.c	8.2 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: options.c,v 1.53 2018/07/13 22:43:44 kre Exp $");
+__RCSID("$NetBSD: options.c,v 1.53.2.1 2021/11/06 13:35:43 martin Exp $");
 #endif
 #endif /* not lint */
 
@@ -171,6 +171,13 @@ optschanged(void)
 	histedit();
 #endif
 	setjobctl(mflag);
+
+	if (privileged && !pflag) {
+		setuid(getuid());
+		setgid(getgid());
+		privileged = 0;
+		setvarsafe("PSc", (getuid() == 0 ? "#" : "$"), 0);
+	}
 }
 
 /*

Index: src/bin/sh/sh.1
diff -u src/bin/sh/sh.1:1.223 src/bin/sh/sh.1:1.223.2.1
--- src/bin/sh/sh.1:1.223	Mon Apr 22 04:10:33 2019
+++ src/bin/sh/sh.1	Sat Nov  6 13:35:43 2021
@@ -1,4 +1,4 @@
-.\"	$NetBSD: sh.1,v 1.223 2019/04/22 04:10:33 kre Exp $
+.\"	$NetBSD: sh.1,v 1.223.2.1 2021/11/06 13:35:43 martin Exp $
 .\" Copyright (c) 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
 .\"
@@ -31,7 +31,7 @@
 .\"
 .\"	@(#)sh.1	8.6 (Berkeley) 5/4/95
 .\"
-.Dd April 22, 2019
+.Dd October 25, 2021
 .Dt SH 1
 .\" everything except c o and s (keep them ordered)
 .ds flags abCEeFfhIiLmnpquVvXx
@@ -317,7 +317,7 @@ and there is no form using
 Enable the built-in emacs style
 command line editor (disables
 .Fl V
-if it has been set).
+if it had been set).
 (See the
 .Sx Command Line Editing
 section below.)
@@ -368,7 +368,7 @@ Functions defined while this option is s
 commands to be executed by the function at the time of the definition.
 When off when a function is defined,
 the file system is searched for commands each time the function is invoked.
-(Not implemented.)
+(Obsolete and not implemented.)
 .It Fl I Em ignoreeof
 Ignore EOFs from input when interactive.
 (After a large number of consecutive EOFs the shell will exit anyway.)
@@ -404,18 +404,28 @@ cleared just before the next time the co
 is written.
 .It Fl p Em nopriv
 Do not attempt to reset effective UID if it does not match UID.
+The same applies to effective and real GIDs.
 This is not set by default to help avoid incorrect usage by setuid
 root programs via
 .Xr system 3
 or
 .Xr popen 3 .
+This option is effective only when set on the command line,
+but can be reset to drop privileges, once, at any time.
+If
+.Fl p
+is cleared, those privileges can never be regained,
+however much the
+.Fl p
+option is manipulated.
 .It Fl q Em quietprofile
 If the
 .Fl v
 or
 .Fl x
-options have been set, do not apply them when reading
-initialization files, these being
+options have been set,
+temporarily disable them before reading initialization files,
+these being
 .Pa /etc/profile ,
 .Pa .profile ,
 and the file specified by the
@@ -458,7 +468,7 @@ Enable the built-in
 .Xr vi 1
 command line editor (disables
 .Fl E
-if it has been set).
+if it had been set).
 (See the
 .Sx Command Line Editing
 section below.)
@@ -4290,7 +4300,7 @@ After expansion (as for
 it is written whenever more input is required to complete the
 current command.
 .It Ev PS4
-is Output, after expansion like
+is output, after expansion as described for
 .Ev PS1 ,
 as a prefix for each line when execution trace
 .Ic ( set Fl x )
@@ -4307,6 +4317,16 @@ or
 depending upon whether the current user is the superuser or not.
 This is intended for use when building a custom
 .Ev PS1 .
+If a privileged shell has its privileges removed by
+clearing the
+.Fl p
+option, an attempt will be made to be reset
+.Ev PSc
+to
+.Dq \&#
+or
+.Dq \&$ ,
+as appropriate for its new privilege level.
 .It Ev PSlit
 Defines the character which may be embedded in pairs, in
 .Ev PS1
@@ -4633,6 +4653,10 @@ It was replaced in
 .At v7
 with a version that introduced the basis of the current syntax.
 That was, however, unmaintainable so we wrote this one.
+This
+.Nx
+.Nm
+is a much modified descendant of the ash shell written by Ken Almquist.
 .Sh BUGS
 Setuid shell scripts should be avoided at all costs, as they are a
 significant security risk.

Index: src/bin/sh/shell.h
diff -u src/bin/sh/shell.h:1.29 src/bin/sh/shell.h:1.29.2.1
--- src/bin/sh/shell.h:1.29	Tue Jan 22 13:48:28 2019
+++ src/bin/sh/shell.h	Sat Nov  6 13:35:43 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: shell.h,v 1.29 2019/01/22 13:48:28 kre Exp $	*/
+/*	$NetBSD: shell.h,v 1.29.2.1 2021/11/06 13:35:43 martin Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -76,9 +76,11 @@ typedef void *pointer;
 #endif
 #define MKINIT	/* empty */
 
+#include <stdbool.h>
 #include <sys/cdefs.h>
 
 extern const char nullstr[1];		/* null string */
+extern bool privileged;
 
 #ifdef	SMALL
 #undef	DEBUG

Reply via email to