At 08:04 AM 8/27/00, Michael Yount wrote:
>A quick search yesterday turned up a somewhat dated explanation of
>potential linking problems with LD_LIBRARY_PATH and LD_PRELOAD on linux.
> http://lwn.net/lwn/980212/ldconfusion.html
>I'd be interested to see the modified wrapper.c. Perhaps
>it contains some useful ideas.
Below is forwarded text and a copy of the suggested C source code.
I believe the issue has evoked religious fervor, so I don't know if
it's worth pursuing. I'm kind of sorry I asked, but will press on
given that there has been one request for information (even though
there has also been a rejection before it has been reviewed).
The "useful idea" you're looking for is either
- complete control of the environment BEFORE starting the perl script
- checking of UID/GID to make sure they are as the installer intended
Jason says all shared lib and environment exploits would happen
before your wrapper code gets to execute. Is that true? Then the
wrapper executes a perl script with an unknown environment and
another chance for shared lib exploits. The C file below takes
complete control before the scripts start firing up the perl
processor... where things like the perl module include path are
up for grabs with uncontrolled environment variables. Please
don't take my word for it. I'm just ASKING, not TELLING, and I
am guessing (from the strength of the response) that this question
has been asked before. Just think about it with an open mind, and
I'll believe whatever you and Jason decide. I'm not contributing
much code to Mj2, mostly help files and a bit of sanity checking.
One last thing: Keep in mind that I installed a usable copy of Mj2
WITHOUT EVER BEING ROOT. That wasn't supposed to be possible, but
it's running as we speak. I haven't turned real users loose on it
because I'm doing this sanity check first, but I'm still asking
whether the Mj2 install procedure should recommend running as root
or recommend running as the server (su to the UID that the wrappers
will use when they are executed). It appears, at least on FreeBSD,
that a regular user can create wrappers that setuid to that user
when they are executed by anyone: Is there any reason to be root
when building the wrappers? No answer yet.
>Attached please find a modified copy of "wrapper.c" which came with the
>original majordomo. You can use this to generate a setuid wrapper by
>(example is mj_shell, you need one per program going into /etc/aliases):
>
>1) Compiling like so:
>
>cc -DPROG=\"/path/to/mj_shell\" -DPOSIX_UID=<X> -DPOSIX_GID=<Y> -o mj_shell wrapper.c
>
>where X is the UID and Y is the GID that you want mj_shell to -really- run under.
>
>2) Manually setuid the wrapper to root.
>
>The wrapper will now execute the specified program with a sane environment vector.
/*
* WRAPPER.C - Originally derived from majordomo v1.xx source - See Majordomo v1.xx source
* for licensing stuff...as long as you are freeware or open source I don't think there will
* be a problem. Don't try to sell this, it's not cool, and very easy to write something similar
* from scratch for that purpose.
*
* Pretty standard stuff here, allows execution of arbitrary programs from /etc/aliases
* where YOU pick the setuid owner. Sanitizes environment variables
*
* Modified 01/12/98 - dave@jetcafe.org - add old RUID and RGID to do even more security checks
*
*/
#include <stdio.h>
#include <sysexits.h>
#include <sys/types.h>
#include <pwd.h>
#if defined(sun) && defined(sparc)
#include <stdlib.h>
#endif
#ifndef STRCHR
# include <string.h>
# define STRCHR(s,c) strchr(s,c)
#endif
#ifndef BIN
# define BIN "/usr/local/bin"
#endif
#ifndef PATH
# define PATH "PATH=/bin:/usr/bin:/usr/ucb:/usr/local"
#endif
#ifndef HOME
# define HOME "HOME=/"
#endif
#ifndef SHELL
# define SHELL "SHELL=/bin/sh"
#endif
#ifndef PROG
# define PROG "YouDidNotDefineAProgram,Dummy!"
#endif
char * new_env[] = {
HOME, /* 0 */
PATH, /* 1 */
SHELL, /* 2 */
0, /* possibly for USER or LOGNAME */
0, /* possible for LOGNAME */
0, /* possibly for timezone */
0, /* other */
0, /* other */
0, /* other */
0, /* other */
0, /* other */
0, /* other */
0, /* other */
0, /* other */
0, /* other */
0
};
int new_env_size = 14; /* to prevent overflow problems */
main(argc, argv, env)
int argc;
char * argv[];
char * env[];
{
char * prog, * ticket;
int e, i;
struct passwd *userent;
if (argv[1] == NULL) {
fprintf(stderr,"usage: complete <arg>\n");
exit(EX_OSERR);
}
if ((prog = (char *) malloc(strlen(BIN) + strlen(PROG) + 2)) == NULL) {
fprintf(stderr, "%s: error: malloc failed\n", argv[0]);
exit(EX_OSERR);
}
sprintf(prog, "%s/%s", BIN, PROG);
/* copy the "USER=" and "LOGNAME=" envariables into the new environment,
* if they exist.
*/
e = 3; /* the first unused slot in new_env[] */
for (i = 0 ; env[i] != NULL && e <= new_env_size; i++) {
if ((strncmp(env[i], "USER=", 5) == 0) ||
(strncmp(env[i], "TZ=", 3) == 0) ||
(strncmp(env[i], "LOGNAME=", 8) == 0)
) {
new_env[e++] = env[i];
}
}
if ((ticket = (char *) malloc(strlen(argv[1]) + 10)) == NULL) {
fprintf(stderr, "%s: error: malloc failed\n", argv[0]);
exit(EX_OSERR);
}
/*
* Add old real and effective ids to env for future use
*/
userent = getpwuid(getuid());
if (userent != NULL) {
char *entry;
if ((entry = (char *) malloc(strlen(userent->pw_name) + 10)) == NULL) {
fprintf(stderr, "%s: error: malloc failed\n", argv[0]);
exit(EX_OSERR);
}
sprintf(entry,"RUID=%s",userent->pw_name);
new_env[e++] = entry;
}
userent = getpwuid(geteuid());
if (userent != NULL) {
char *entry;
if ((entry = (char *) malloc(strlen(userent->pw_name) + 10)) == NULL) {
fprintf(stderr, "%s: error: malloc failed\n", argv[0]);
exit(EX_OSERR);
}
sprintf(entry,"EUID=%s",userent->pw_name);
new_env[e++] = entry;
}
#if defined(SETGROUP)
/* renounce any previous group memberships if we are running as root */
if (geteuid() == 0) { /* Should I exit if this test fails? */
char *setgroups_used = "setgroups_was_included"; /* give strings a hint */
#if defined(MAIL_GID)
int groups[] = { POSIX_GID, MAIL_GID, 0 };
if (setgroups(2, groups) == -1) {
#else
int groups[] = { POSIX_GID, 0 };
if (setgroups(1, groups) == -1) {
#endif
extern int errno;
fprintf(stderr, "%s: error setgroups failed errno %d", argv[0],
errno);
}
}
#endif
#ifdef POSIX_GID
setgid(POSIX_GID);
#else
setgid(getegid());
#endif
#ifdef POSIX_UID
setuid(POSIX_UID);
#else
setuid(geteuid());
#endif
if ((getuid() != geteuid()) || (getgid() != getegid())) {
fprintf(stderr, "%s: error: Not running with proper UID and GID.\n", argv[0]);
fprintf(stderr, " Make certain that wrapper is installed setuid, and if so,\n");
fprintf(stderr, " recompile with POSIX flags.\n");
exit(EX_SOFTWARE);
}
execve(prog, argv, new_env);
/* the exec should never return */
fprintf(stderr, "wrapper: Trying to exec %s failed: ", prog);
perror(NULL);
fprintf(stderr, " HOME is %s,\n", HOME);
fprintf(stderr, " PATH is %s,\n", PATH);
fprintf(stderr, " SHELL is %s,\n", SHELL);
fprintf(stderr, " PROG is %s\n", PROG);
fprintf(stderr, " BIN is %s\n", BIN);
exit(EX_OSERR);
}
SRE
mailto:eckert@climber.org | http://www.climber.org/eckert/
Info on peak climbing email lists mailto:info@climber.org
"A free society is one where it is safe to be unpopular."
-- Adlai Stevenson
References:
|
|