From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10827 invoked from network); 12 Apr 2004 19:44:02 +0000 Received: from smtp.gentoo.org (128.193.0.39) by eagle.gentoo.oregonstate.edu with DES-CBC3-SHA encrypted SMTP; 12 Apr 2004 19:44:02 +0000 Received: from lists.gentoo.org ([128.193.0.34] helo=eagle.gentoo.org) by smtp.gentoo.org with esmtp (Exim 4.24) id 1BD7Ld-0000WV-8t for arch-gentoo-portage-dev@lists.gentoo.org; Mon, 12 Apr 2004 19:44:01 +0000 Received: (qmail 6896 invoked by uid 50004); 12 Apr 2004 19:43:58 +0000 Mailing-List: contact gentoo-portage-dev-help@gentoo.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail Reply-To: gentoo-portage-dev@lists.gentoo.org X-BeenThere: gentoo-portage-dev@gentoo.org Received: (qmail 16398 invoked from network); 12 Apr 2004 19:43:58 +0000 Date: Mon, 12 Apr 2004 14:43:55 -0500 From: Nick Jones To: dev-portage@gentoo.org, scox@gentoo.org, gentoo-portage-dev@lists.gentoo.org Message-ID: <20040412194354.GA30727@twobit.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="FL5UXtIhxfXey3p5" Content-Disposition: inline User-Agent: Mutt/1.5.4i Subject: [gentoo-portage-dev] [gavin@vess.com: Hardening the Gentoo Portage Sandbox [rev 2 - edits re: glibc's use of weak aliases]] X-Archives-Salt: b2eef18f-e8f6-464c-af22-e00e95c4ad23 X-Archives-Hash: 44ae03055db8d3a7653614d6bbaf6873 --FL5UXtIhxfXey3p5 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Forward. --FL5UXtIhxfXey3p5 Content-Type: message/rfc822 Content-Disposition: inline Return-Path: Delivered-To: carpaski@twobit.net Received: (qmail 2235 invoked from network); 12 Apr 2004 12:46:32 -0500 Received: from unknown (HELO smtp.gentoo.org) (128.193.0.39) by host165.spe.iit.edu with SMTP; 12 Apr 2004 12:46:32 -0500 Received: from adsl-66-125-173-27.dsl.snfc21.pacbell.net ([66.125.173.27] helo=prism.goldenbluellc.com) by smtp.gentoo.org with esmtp (Exim 4.24) id 1BD5Vs-0000iV-Qi; Mon, 12 Apr 2004 17:46:29 +0000 Message-ID: <007901c420b6$153b48c0$0500a8c0@EPOX2> From: "Gavin" To: , "\"Martin Schlemmer\"" , "\"Nicholas Jones\"" Cc: Subject: Hardening the Gentoo Portage Sandbox [rev 2 - edits re: glibc's use of weak aliases] Date: Mon, 12 Apr 2004 10:46:22 -0700 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0073_01C4207B.6581AD00" X-Priority: 3 X-MSMail-Priority: Normal X-Bogosity: No, tests=bogofilter, spamicity=0.000000, version=0.17.2 This is a multi-part message in MIME format. ------=_NextPart_000_0073_01C4207B.6581AD00 Content-Type: text/plain; charset="Windows-1252" Content-Transfer-Encoding: quoted-printable Greetings, I found some weaknesses in the Gentoo Portage sandbox with consequences = similar to the recent posting about the critical issue with Portage and = /tmp. FYI, Chris posted an selinux one-liner solution =3D) > create_dir_notdevfile(portage_t,{ file_type = -user_tmp_t }) > Therefore, portage_t can modify all files, except = those created by users, in /tmp. Given this group's focus on hardening Gentoo, I am curious about your = opinions regarding hardening of Portage. For example, given the options = available with selinux and grsecurity patches, perhaps a more efficient = alternative exists to using the sandbox as implemented by libsandbox.so = and the sandbox binary in Portage? Also, if 1) Gentoo developers use = the sandbox when testing, 2) the sandbox works flawlessly for all = tested/installed packages, and 3) there were no sandbox violations, then = how much practical value does an end user forfeit if they don't use the = sandbox FEATURE, but continue using the userpriv FEATURE? Since a = user's unique configuration might result in different code executed = during installation, a user might benefit from using the sandbox, even = if the developers/ebuild maintainers did not witness any sandbox = violations, but, does this occur in practice? I hope the discussion below about Portage is constructive, informative, = and encouraging, without diminishing either the value and = accomplishments of the Portage team or the relevance/importance of = weaknesses (discussed below) to security-conscious Gentoo users and = administrators. I have invested a great deal of effort in switching our = software from Red Hat to Gentoo, and have a vested interest in improving = the security of Gentoo. I welcome all feedback. Thanks, Gavin Abstract =3D=3D=3D=3D=3D=3D=3D=3D=3D I reviewed some of Gentoo's sandbox code in preparation for integrating = an enhanced compiler-caching technology derived from ccache. Although I = personally believe the Portage sandbox is extremely helpful and useful, = I found that the sandbox is not completely self-enforcing and relies on = the cooperation of the installation code in source packages to maintain = the integrity of the sandbox during an emerge. Using the 'sandbox' FEATURE in /etc/make.conf without the FEATURES = userpriv, and usersandbox (i.e. emerging a package as the root user) is = not sufficient to prevent an ebuild from modifying sensitive files (e.g. = /etc/passwd) outside the sandbox while performing an ebuild. Similarly, = the use of all three FEATURES does not prevent an ebuild from writing to = any file writable by the portage user (subject to security context = limitations, etc. established by selinux/grsecurity/etc.). Conclusion =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 1) The attached patch helps detect and prevent "accidental" breakage of = the sandbox by "whitehat" package/ebuild authors. 2) Hardened Gentoo (either grsecurity or selinux) provides a = kernel-based capability to enforcing the sandbox. After this article = has been edited appropriately, perhaps the hardened team might want to = contribute some advice? 3) I suggest either updating Portage to eliminate the documented = weaknesses, or changing Portage documentation to reflect the weaknesses, = documented below, contradicting documentation claims like, ".. as long = as the package isn't installed on your system, the package cannot touch = any file outside the sandbox." = [http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=3D2&chap=3D3= ] =20 Personal Opinions =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D I've found the sandbox an invaluable part of Gentoo and whole-heartedly = recommend its continued use via FEATURES=3D"sandbox userpriv = usersandbox", but with an understanding for security-conscious = administrators that emerge'ing packages poses more risks than implied by = the documentation (e.g. "cannot touch any file outside the sandbox"). = However, a virtual sandbox enforced by the kernel might provide an = appealing alternative to reliance on the current pre-loaded library = method. I believe the Portage team has already created a "best in class" = solution. Weaknesses in Portage's Sandbox =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D The following weaknesses allow for the possibility of a similar type of = exploit as: http://bugs.gentoo.org/show_bug.cgi?id=3D21923=20 Essentially, a blackhat might be able to trick portage into installing = some form of a rootkit that the root user eventually executes = unknowingly. More specifically, a blackhat who is aware of the following = weakness might be able to find an existing ebuild that scribbles outside = the sandbox to some pre-determined location (e.g. /tmp), and then = hardlink/symlink that location to somewhere else under their control, = thus allowing them to insert code (i.e. a rootkit) during the emerge'ing = of a package. Regardless, such writable, vulnerable locations are not = supposed to exist at all on a secured/hardened system. First, since the correct operation of the sandbox depends on the = presence and definition of the LD_PRELOAD(7) and SANDBOX_* environment = variables to enable the sandbox and control its functioning, package = code executed during emerge can easily escape the sandbox by unsetting = these variables (e.g. SANDBOX_ON), as libsandbox.so lacks enforcement = (except for LD_PRELOAD with execve, which is practically useless if the = SANDBOX_* variables have been unset). Second, when the execve wrapper finds that libsandbox.so is not present = in LD_PRELOAD, it appends this library, instead of pre-pending it, = potentially allowing interception of further system calls by a library = other than libsandbox.so(6). Example(8): - - - b e g i n e x a m p l e m a k e f i l e - - - export LD_PRELOAD=3Dwhitehat_lib.so breaksandbox: env /bin/echo 'misc. conf. stuff' > /etc/whitehat.conf - - - e n d e x a m p l e m a k e f i l e - - - Third, when using a version of libc (e.g. recent versions of glibc) that = implements execv, execl, execlp, or execvp without calling execve, the = execve wrapper code in libsandbox.c is bypassed(2) by some executables = (e.g. GNU's make). Note that glibc's implementation of __execve defines = a weak alias, "weak_alias (__execve, execve)". When we provide our own = execve in libsandbox.so, glibc's execve is no longer "available for = reference from other files" [http://gcc.gnu.org/onlinedocs/gccint/]. = However, execl, execle, execv, and execvp (but not execlp which calls = execvp) all call __execve (glibc's "true" execve). When libsandbox.c = replaces execve, these other functions know nothing about the = libsandbox.so execve, and continue using __execve. From a practical = perspective, GNU's make uses execvp, while gcc's frontend uses both = execv and execvp. In contrast, the exec family in uClibc is written = using execvp and execve. Modifying libsandbox.c to wrap __execve might = work with glibc, but not with uClibc, unless additional changes are = made. Consider that glibc's implementation of __execve defines a weak alias, = "weak_alias (__execve, execve)", and implements execv as follows: int execv (const char *path, char *const argv[]) { return __execve (path, argv, __environ); } Thus, when libsandbox.so provides its own execve, execv continues to use = glibc's __execve(). The attached patch adds support for wrapping execvp = [the others are left as an "exercise" for the reader ;) ], factors = functionality common to the execve and execvp wrappers, and ensures that = libsandbox.so is listed first in LD_PRELOAD. As an example = demonstrating the consequences of a missing wrapper for execvp in = libsandbox.c, please consider a hypothetical Makefile in a package with = a corresponding ebuild: - - - b e g i n e x a m p l e m a k e f i l e - - - export LD_PRELOAD=3Dwhitehat_lib.so breaksandbox: /bin/echo 'blackhat was here' > /etc/passwd /bin/echo 'misc. conf. stuff' > /etc/whitehat.conf env - ./scribble_anywhere_portage_user_can_scribble.sh - - - e n d e x a m p l e m a k e f i l e - - - The script "scribble_anywhere_portage_user_can_scribble.sh" runs as the = portage user ('root', unless FEATURES=3D"sandbox usersandbox userpriv = ..." in /etc/make.conf). The first and second rules for the breaksandbox(1) target above exploit = the missing execvp wrapper weakness, while the third rule exploits the = lack of enforcement of the sandbox due to missing "SANDBOX_*" = environment variables. The second rule also highlights how easily a = package author might accidentally break the sandbox. Proposed Changes =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D The attached example patch(5) addresses the execvp weakness (the first = of the two example rules above), and ensures that libsandbox.so is = listed first in LD_PRELOAD. The "env - script" weakness might be avoided by storing the data in the = SANDBOX_* environment variables somewhere that the portage user lacks = write access to. However, that would necessitate other changes totaling = a non-trivial effort. Although one might endeavor to enforce application of sandbox = protections requested via the SANDBOX_* environment variables, other = weaknesses in relying on the LD_PRELOAD tactic might ameliorate the = value of such endeavors. Since the hardened Gentoo project team = provides hardened solutions that specifically include the capability of = isolating a user using ACLs enforced by the kernel, leveraging their = work might prove more efficient in seeking a self-enforcing sandbox = capable of preventing one emerge from affecting unrelated files owned by = the portage user. Notes =3D=3D=3D=3D=3D=3D=3D 1) The "breaksandbox" Makefile rule also breaks anything depending on = other preloaded shared objects (via LD_PRELOAD), but the code in = libsandbox.c was already broken anyway for IA32/gcc 3.3/glibc 2.3 combo = with multiple shared objects in LD_PRELOAD [50-r3 just fixed that bug]. 2) The execvp problem can be hidden in a "generation skip", where a = process uses execvp (e.g. GNU make), but its child uses one of the = exec's implemented by execve. In the latter case, the sandbox resumes = functioning normally, even though the sandbox execve wrapper code was = skipped by the parent using execvp. The use of the terms 'child' and = 'parent' are inappropriate to examples where there was a pure exec = without a fork, but this is already too wordy. 3) Unlike glibc, uClibc implements execvp using execve. I have not = tried to determine whether versions of glibc older than glibc-2.3.3 = implement execvp using execve. 4) Why hasn't this problem been noticed before? Perhaps it has, and I = haven't heard. Also, see #2 above. Perhaps most programs that use = execvp during an ebuild don't alter the environment (i.e. clean up the = environment / alter LD_PRELOAD environment variable) before executing = execvp? Perhaps the practical consequences are minimal. I'm not aware = of any practical, already-existing examples exploiting these sandbox = weaknesses. 5) The patch contains some code inappropriate for most any purpose other = than testing/evaluating the sandbox system. However, it shouldn't = require much effort to integrate and adapt the patch to one's own = preferences and style. Also, some debugging statements left in the = patch require /tmp/jlog to exist before emerg'ing and belong to the = portage user and group. These debugging statements are left = intentionally in the patch to highlight how much GNU's make uses execvp = (see the log file /tmp/jlog after performing an emerge using a patched = version of libsandbox using the supplied patch). The list of SANDBOX_* environment variables checked by the patch for = non-empty definitions should be tuned, and possibly extended to check = for unreasonable combinations. Also what is reported and how needs = "adjusting" to suit the typical Gentoo user. The patch also includes an = experimental performance tweak for x86 architectures that is = automatically selected if ARCH =3D=3D 'x86'. The patch uses a different = (experimental) method of wrapping execve and execvp using assembly. I've = only tested the patch on a single system (x86, the latest version of = almost everything). #include 6) Prior to 50-r3, this weakness was limited to special cases where an = ebuild explicitly set 'LD_PRELOAD=3D/mylib.so /lib/libsandbox.so', since = libsandbox.so was partly broken when using multiple libraries in = LD_PRELOAD, at least for the current version of GNU's ld that requires = spaces between libs(prior versions of libsandbox.c used a ':' instead of = ' ' when appending). Thus, prior to 50-r3, 'export = LD_PRELOAD=3D/mylib.so' resulted in something like = 'LD_PRELOAD=3D/mylib.so:/lib/libsandbox.so', causing ld to report an = error. 7) Actually, an LD_SO_PRELOAD option exists in sandbox.c that tries to = enforce the preloading of libsandbox.so via /etc/ld.so.preload. = However, if the sandbox executable is interrupted at an inopportune = time, the contents of ld.so.preload could be corrupted. Also, negative = consequences might arise for unrelated system processes that happen to = start while the sandbox exists. Perhaps if ld.so were tweaked to = provide for enforced, per-user versions of ld.so.preload ... = Regardless, the portage ebuild states this approach has been deprecated, = and it still doesn't prevent installation code from unsetting = SANDBOX_ON. 8) If we append ' /lib/libsandbox.so' to the 'export = LD_PRELOAD=3Dwhitehat_lib.so' in the first makefile example, the = supplied patch does not check to make sure that libsandbox.so is listed = first. I consider that a "todo" item. ------=_NextPart_000_0073_01C4207B.6581AD00 Content-Type: application/octet-stream; name="portage-2.0.50-r3.GB.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="portage-2.0.50-r3.GB.patch" diff -ruN portage-2.0.50-r3/src/sandbox-1.1/Makefile = portage-2.0.50-r3.GB/src/sandbox-1.1/Makefile=0A= --- portage-2.0.50-r3/src/sandbox-1.1/Makefile 2004-03-21 = 17:40:58.000000000 -0800=0A= +++ portage-2.0.50-r3.GB/src/sandbox-1.1/Makefile 2004-04-07 = 15:33:50.699788600 -0700=0A= @@ -31,6 +31,10 @@=0A= TARGETS =3D libsandbox.so sandbox=0A= endif=0A= =0A= +ifeq ($(ARCH),"x86")=0A= + ARCH_CFLAGS +=3D -DARCH_X86=0A= +endif=0A= +=0A= all: $(TARGETS)=0A= =0A= sandbox: sandbox.o sandbox_futils.o getcwd.c=0A= diff -ruN portage-2.0.50-r3/src/sandbox-1.1/libsandbox.c = portage-2.0.50-r3.GB/src/sandbox-1.1/libsandbox.c=0A= --- portage-2.0.50-r3/src/sandbox-1.1/libsandbox.c 2004-03-21 = 17:40:58.000000000 -0800=0A= +++ portage-2.0.50-r3.GB/src/sandbox-1.1/libsandbox.c 2004-04-07 = 15:43:02.163953304 -0700=0A= @@ -24,6 +24,7 @@=0A= * Partly Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro = ,=0A= * as some of the InstallWatch code was used.=0A= *=0A= + * Partly Copyright (C) 2004 GoldenBlue, LLC. = http://www.goldenbluellc.com/=0A= *=0A= * $Header: = /home/cvsroot/gentoo-src/portage/src/sandbox-1.1/libsandbox.c,v 1.16 = 2004/03/22 01:40:58 carpaski Exp $=0A= *=0A= @@ -200,6 +201,8 @@=0A= =0A= extern int execve(const char *filename, char *const argv[], char *const = envp[]);=0A= static int (*true_execve) (const char *, char *const[], char *const[]);=0A= +extern int execvp(const char *filename, char *const argv[]);=0A= +static int (*true_execvp) (const char *, char *const[]);=0A= =0A= /*=0A= * Initialize the shabang=0A= @@ -244,6 +247,7 @@=0A= #endif=0A= =0A= true_execve =3D dlsym(libc_handle, "execve");=0A= + true_execvp =3D dlsym(libc_handle, "execvp");=0A= }=0A= =0A= void=0A= @@ -725,93 +729,140 @@=0A= =0A= #endif /* GLIBC_MINOR >=3D 1 */=0A= =0A= +char *=0A= +get_new_ldp(char *orig_ldp)=0A= +/* Usage: orig_ldp can be NULL, returns malloc'd new LD_PRELOAD with = sandbox lib prepended.=0A= + * Bug not fixed: the relative position of sandbox_lib amongst other = libs in=0A= + * LD_PRELOAD can alter the program's behavior, but we merely check for = presence!=0A= + */=0A= +{=0A= + int orig_ldp_len =3D 0;=0A= + if (orig_ldp)=0A= + {=0A= + if (!strncmp(orig_ldp, "LD_PRELOAD=3D", 11)) orig_ldp +=3D 11;=0A= + orig_ldp_len =3D strlen(orig_ldp);=0A= + }=0A= + char *new_ldp =3D NULL;=0A= + int sandbox_lib_len =3D strlen(sandbox_lib);=0A= + /* new_ldp_len =3D 'LD_PRELOAD=3D' + sanboxlib + space + original = libs + null + fudge */=0A= + int new_ldp_len =3D 11 + sandbox_lib_len + 1 + orig_ldp_len + 1 = + 1;=0A= + if ((new_ldp_len >=3D 4096) || (NULL =3D=3D (new_ldp =3D = malloc(new_ldp_len * sizeof(char)))))=0A= + {=0A= + perror("LD_PRELOAD exceeds hard-coded limit of 4096 characters, or = malloc failed!");=0A= + errno =3D ENOMEM;=0A= + return NULL;=0A= + }=0A= +=0A= + /* If the sanbox.so is appended, then the sandbox might easily break, = without=0A= + * the user knowing. Also, the semantics of the sandbox suggest it = should=0A= + * have higher priority than other libs in LD_PRELOAD. Default to = prepend.=0A= + */ =0A= + strcpy(new_ldp, "LD_PRELOAD=3D");=0A= +#ifndef APPEND_SANDBOX_SO=0A= + strncpy(&(new_ldp[11]), sandbox_lib, sandbox_lib_len +1);=0A= + /* PREPEND sandbox.so to the beginning of the LD_PRELOAD environment = variable */=0A= + if (orig_ldp_len)=0A= + {=0A= + new_ldp[sandbox_lib_len + 11] =3D ' ';=0A= + /* automatically null-terminated by strncpy, if sandbox_lib is */=0A= + strncpy(&(new_ldp[sandbox_lib_len + 12]), orig_ldp, orig_ldp_len = +1);=0A= + }=0A= +fprintf(stderr, "libsandbox.so: DEBUG: orig_ldp=3D'%s'/%d; = new_ldp=3D'%s'/%d\n", orig_ldp, orig_ldp_len, new_ldp, new_ldp_len);=0A= +#else=0A= + if (orig_ldp_len)=0A= + {=0A= + strncpy(&(new_ldp[11]), orig_ldp, orig_ldp_len +1);=0A= + new_ldp[orig_ldp_len +11] =3D ' '; /* append sandbox.so */=0A= + }=0A= + else orig_ldp_len--;=0A= + strncpy(&(new_ldp[orig_ldp_len +11 +1]), sandbox_lib, = sandbox_lib_len +1);=0A= +# endif=0A= + return new_ldp;=0A= +}=0A= +=0A= /*=0A= * Exec Wrappers=0A= */=0A= =0A= int=0A= -execve(const char *filename, char *const argv[], char *const envp[])=0A= +follow_execve(const char *filename, char *const argv[], char *const = envp[])=0A= {=0A= int old_errno =3D errno;=0A= int result =3D -1;=0A= int count =3D 0;=0A= - int env_len =3D 0;=0A= char canonic[SB_PATH_MAX];=0A= - char **my_env =3D NULL;=0A= - /* We limit the size LD_PRELOAD can be here, but it should be enough */=0A= - char tmp_str[4096];=0A= =0A= canonicalize_int(filename, canonic);=0A= =0A= if FUNCTION_SANDBOX_SAFE=0A= - ("execve", canonic) {=0A= - while (envp[count] !=3D NULL) {=0A= - if (strstr(envp[count], "LD_PRELOAD=3D") =3D=3D envp[count]) {=0A= - if (NULL !=3D strstr(envp[count], sandbox_lib)) {=0A= - my_env =3D (char **) envp;=0A= - break;=0A= - } else {=0A= - int i =3D 0;=0A= - const int max_envp_len =3D=0A= - strlen(envp[count]) + strlen(sandbox_lib) + 1;=0A= -=0A= - /* Fail safe ... */=0A= - if (max_envp_len > 4096) {=0A= - fprintf(stderr, "sandbox: max_envp_len too big!\n");=0A= - errno =3D ENOMEM;=0A= - return result;=0A= - }=0A= -=0A= - /* Calculate envp size */=0A= - my_env =3D (char **) envp;=0A= - do=0A= - env_len +=3D 1;=0A= - while (*my_env++);=0A= -=0A= - my_env =3D (char **) malloc((env_len + 2) * sizeof (char *));=0A= - if (NULL =3D=3D my_env) {=0A= - errno =3D ENOMEM;=0A= - return result;=0A= - }=0A= - /* Copy envp to my_env */=0A= - do=0A= - my_env[i] =3D envp[i];=0A= - while (envp[i++]);=0A= -=0A= - /* Set tmp_str to envp[count] */=0A= - strncpy(tmp_str, envp[count], max_envp_len - 1);=0A= -=0A= - /* LD_PRELOAD already have variables other than sandbox_lib,=0A= - * thus we have to add sandbox_lib seperated via a whitespace. */=0A= - if (0 !=3D strncmp(envp[count], "LD_PRELOAD=3D", max_envp_len - = 1)) {=0A= - strncat(tmp_str, " ", max_envp_len - strlen(tmp_str));=0A= - strncat(tmp_str, sandbox_lib, max_envp_len - strlen(tmp_str));=0A= - } else {=0A= - strncat(tmp_str, sandbox_lib, max_envp_len - strlen(tmp_str));=0A= - }=0A= -=0A= - /* Valid string? */=0A= - tmp_str[max_envp_len] =3D '\0';=0A= -=0A= - /* Ok, replace my_env[count] with our version that contains=0A= - * sandbox_lib ... */=0A= - my_env[count] =3D tmp_str;=0A= -=0A= - break;=0A= + ("execve", canonic)=0A= + {=0A= + /* 4 cases:=0A= + * (1) LD_PRELOAD already contains libsandbox.so,=0A= + * (2) LD_PRELOAD does not contain libsandbox.so, but does have other = "stuff"=0A= + * (3) LD_PRELOAD ~ /^LD_PRELOAD=3D *$/, (sub-case of #2)=0A= + * (4) LD_PRELOAD is not defined (case ignored by code below)=0A= + */=0A= + char **my_envp =3D (char**)envp;=0A= + char *new_ldp =3D NULL; /* our modified = "LD_PRELOAD=3D/lib/libsandbox.so ..." */=0A= + char *orig_ldp =3D NULL; /* original ptr containing = "LD_PRELOAD=3D..." */=0A= +# ifdef ARCH_X86=0A= + char **orig_ldp_ptr =3D NULL; /* ptr to ptr in envp for LD_PRELOAD = */=0A= +# endif=0A= +=0A= + while ((orig_ldp =3D envp[count]) && strncmp(orig_ldp, = "LD_PRELOAD=3D", 11)) count++;=0A= + if (orig_ldp && !strstr(orig_ldp, sandbox_lib))=0A= + {=0A= + new_ldp =3D get_new_ldp(orig_ldp);=0A= + if (new_ldp =3D=3D NULL) return result;=0A= +# ifdef ARCH_X86=0A= + orig_ldp_ptr =3D (char**)&(envp[count]);=0A= + *orig_ldp_ptr =3D new_ldp;=0A= +# else /* Martin's fix for Bug #42290 */=0A= + /* Calculate envp size */=0A= + int env_len =3D 0, i =3D 0;=0A= + do=0A= + env_len +=3D 1;=0A= + while (*my_envp++);=0A= +=0A= + my_envp =3D (char **) malloc((env_len + 2) * sizeof (char *));=0A= + if (NULL =3D=3D my_envp)=0A= + {=0A= + errno =3D ENOMEM;=0A= + return result;=0A= }=0A= - }=0A= - count++;=0A= + /* Copy envp to my_env */=0A= + do=0A= + my_envp[i] =3D envp[i];=0A= + while (envp[i++]);=0A= +=0A= + my_envp[count] =3D new_ldp;=0A= +# endif=0A= }=0A= =0A= +FILE *log=3Dfopen("/tmp/jlog", "a"); // writing to stdout would mean = that ebuild's use of `cmd` would capture this output as well=0A= +fprintf(log,"INFO: pid=3D%d true_execve(filename=3D%s; envp[%d] =3D = '%s', new_ldp=3D%s: = ",(int)getpid(),filename,count,my_envp[count],new_ldp);=0A= +int i=3D0;=0A= +while (argv[++i]) fprintf(log,"%s,",argv[i]);=0A= +fputs("\n", log);=0A= +fflush(log);=0A= errno =3D old_errno;=0A= check_dlsym(execve);=0A= - result =3D true_execve(filename, argv, my_env);=0A= + result =3D true_execve(filename, argv, my_envp);=0A= old_errno =3D errno;=0A= +fprintf(log,"ERROR: after true_execve()\n");=0A= +fclose(log);=0A= =0A= - if (my_env) {=0A= - free(my_env);=0A= - my_env =3D NULL;=0A= - }=0A= + if (new_ldp)=0A= + {=0A= + free(new_ldp);=0A= +# ifdef ARCH_X86=0A= + *orig_ldp_ptr =3D orig_ldp;=0A= +# else=0A= + free(my_envp);=0A= + my_envp =3D NULL;=0A= +# endif=0A= + }=0A= }=0A= =0A= errno =3D old_errno;=0A= @@ -1270,6 +1321,8 @@=0A= is_sandbox_on()=0A= {=0A= int old_errno =3D errno;=0A= + char *tmp_on =3D NULL;=0A= + char *tmp_active =3D NULL;=0A= =0A= /* $SANDBOX_ACTIVE is an env variable that should ONLY=0A= * be used internal by sandbox.c and libsanbox.c. External=0A= @@ -1279,21 +1332,26 @@=0A= *=0A= * Azarah (3 Aug 2002)=0A= */=0A= - if ((NULL !=3D getenv("SANDBOX_ON")) &&=0A= - (0 =3D=3D strncmp(getenv("SANDBOX_ON"), "1", 1)) &&=0A= - (NULL !=3D getenv("SANDBOX_ACTIVE")) &&=0A= - (0 =3D=3D strncmp(getenv("SANDBOX_ACTIVE"), "armedandready", 13))=0A= + if ((NULL !=3D (tmp_on =3D getenv("SANDBOX_ON"))) &&=0A= + (0 =3D=3D strncmp(tmp_on, "1", 1)) &&=0A= + (NULL !=3D (tmp_active =3D getenv("SANDBOX_ACTIVE"))) &&=0A= + (0 =3D=3D strncmp(tmp_active, "armedandready", 13))=0A= ) {=0A= - errno =3D old_errno;=0A= -=0A= + errno =3D old_errno;=0A= return 1;=0A= - } else {=0A= - errno =3D old_errno;=0A= -=0A= - return 0;=0A= - }=0A= + }=0A= +/* .. too noisy to notice any real violations of the sandbox,=0A= + * such as the 'env - script.sh' rule in a Makefile.=0A= + } else {=0A= + if (tmp_on =3D=3D NULL) fputs(tmp_on, stderr);=0A= + fputs("INFO: SANDBOX_ON not defined", stderr);=0A= + }=0A= +*/=0A= + errno =3D old_errno;=0A= + return 0;=0A= }=0A= =0A= +=0A= static int=0A= before_syscall(const char *func, const char *file)=0A= {=0A= @@ -1360,4 +1418,97 @@=0A= #include "getcwd.c"=0A= #include "canonicalize.c"=0A= =0A= +#ifndef DEBUG=0A= +#ifdef __GNUC__=0A= +#if __GNUC_MINOR__ >=3D 3=0A= +# define HIDDEN __attribute__((visibility ("hidden")))=0A= +# define USED __attribute__((__used__))=0A= +#else=0A= +# define USED __attribute__((__unused__))=0A= +#endif=0A= +#endif=0A= +#endif=0A= +=0A= +#ifndef HIDDEN=0A= +#define HIDDEN=0A= +#endif=0A= +=0A= +#ifndef USED=0A= +#define USED=0A= +#endif=0A= +=0A= +static USED void __follow_alias_execve()=0A= +{=0A= + asm("\t .global execve");=0A= + asm("\t .global _execve");=0A= + asm("\t .global __execve");=0A= + asm("\t execve =3D follow_execve");=0A= + asm("\t _execve =3D follow_execve");=0A= + asm("\t __execve =3D follow_execve");=0A= +}=0A= +=0A= +#ifndef __linux=0A= + You are not using Linux. I have only tested Athlon-XP with=0A= + Linux 2.6 kernel, gcc-3.3.3, and glibc-2.3.3_pre20040207.=0A= +#else=0A= +/*=0A= + * x86 platforms with Linux and glibc 2.? directly calls the kernel=0A= + * from execvp, instead of execve. Thus, we need the following:=0A= + */=0A= +=0A= +=0A= +extern char **__environ;=0A= +=0A= +static USED int follow_execvp(char *file, char *argv[])=0A= +{=0A= + int old_errno =3D errno;=0A= + int result =3D -1;=0A= + char *new_ldp =3D NULL; /* our modified = "LD_PRELOAD=3D/lib/libsandbox.so ..." */=0A= + char *orig_ldp =3D NULL; /* original ptr containing = "LD_PRELOAD=3D..." */=0A= + orig_ldp =3D getenv("LD_PRELOAD");=0A= + if (orig_ldp =3D=3D NULL || !strstr(orig_ldp, sandbox_lib))=0A= + {=0A= + new_ldp =3D get_new_ldp(orig_ldp);=0A= + if (new_ldp =3D=3D NULL) return -1;=0A= + if (putenv(new_ldp))=0A= + {=0A= + perror("Unable to putenv new/fixed LD_PRELOAD");=0A= + return -1;=0A= + }=0A= + }=0A= +=0A= +FILE *log=3Dfopen("/tmp/jlog", "a"); // writing to stdout would mean = that ebuild's use of `cmd` would capture this output as well=0A= +fprintf(log,"INFO: pid=3D%d true_execVP(filename=3D%s; orig_ldp=3D%s, = new_ldp=3D%s, getenv(LDP)=3D%s: = ",(int)getpid(),file,orig_ldp,new_ldp,getenv("LD_PRELOAD"));=0A= +int i=3D0;=0A= +while (argv[++i]) fprintf(log,"%s, ",argv[i]);=0A= +fputs("\n", log);=0A= +fclose(log);=0A= + errno =3D old_errno;=0A= + check_dlsym(execvp);=0A= + result =3D true_execvp(file, argv);=0A= + old_errno =3D errno;=0A= +fputs("ERROR:\e[31;01mafter real_execvp()\033[0m \n", stderr);=0A= +=0A= +/* Since new_ldp has become part of the live environment, we should = restore before free'ing it.=0A= + * Why write this code, since we exec'd above (if successful)?=0A= + * if (new_ldp)=0A= + * free(new_ldp);=0A= + */=0A= + errno =3D old_errno;=0A= + return result;=0A= +}=0A= +=0A= +static USED void __follow_alias_execvp()=0A= +{=0A= + asm("\t .global execvp");=0A= + asm("\t .global _execvp");=0A= + asm("\t .global __execvp");=0A= + asm("\t execvp =3D follow_execvp");=0A= + asm("\t _execvp =3D follow_execvp");=0A= + asm("\t __execvp =3D follow_execvp");=0A= +}=0A= +=0A= +=0A= +#endif=0A= +=0A= // vim:expandtab noai:cindent ai=0A= diff -ruN portage-2.0.50-r3/src/sandbox-1.1/sandbox.c = portage-2.0.50-r3.GB/src/sandbox-1.1/sandbox.c=0A= --- portage-2.0.50-r3/src/sandbox-1.1/sandbox.c 2004-04-04 = 13:37:21.000000000 -0700=0A= +++ portage-2.0.50-r3.GB/src/sandbox-1.1/sandbox.c 2004-04-07 = 14:54:41.130977352 -0700=0A= @@ -35,7 +35,7 @@=0A= =0A= int preload_adaptable =3D 1;=0A= int cleaned_up =3D 0;=0A= -int print_debug =3D 0;=0A= +int print_debug =3D 1;=0A= =0A= /* Read pids file, and load active pids into an array. Return number = of pids in array */=0A= int=0A= @@ -462,7 +462,7 @@=0A= //printf("%s\n", argv_bash[i]);=0A= i++;=0A= }=0A= - printf("%s\n", sh);=0A= + printf("spawn_shell(): %s\n", sh);=0A= ret =3D system(sh);=0A= if (sh)=0A= free(sh);=0A= @@ -480,10 +480,18 @@=0A= =0A= pid =3D fork();=0A= =0A= +//FILE *log=3Dfopen("/tmp/jlog2", "a");=0A= +//fprintf(log,">>>pid=3D%d sandbox BEFORE execv(",(int)getpid());=0A= +//fflush(log);=0A= /* Child's process */=0A= if (0 =3D=3D pid) {=0A= # endif=0A= - execv(argv_bash[0], argv_bash);=0A= +//int i=3D-1;=0A= +//while (argv_bash[++i]) fprintf(log,"%s,",argv_bash[i]);=0A= +//fputs("\n", log);=0A= +//fflush(log);=0A= + execv(argv_bash[0], argv_bash);=0A= +//fputs("*** ERROR: AFTER execv\n", log);=0A= # ifndef NO_FORK=0A= return 0;=0A= } else if (pid < 0) {=0A= @@ -491,7 +499,13 @@=0A= }=0A= ret =3D waitpid(pid, &status, 0);=0A= if ((-1 =3D=3D ret) || (status > 0))=0A= + {=0A= + if (WIFEXITED(status))=0A= + fprintf(stderr, "sandbox ERROR: waitpid reported error: = ret=3D%d; status=3D%d\n", ret, WEXITSTATUS(status));=0A= return 0;=0A= + }=0A= +//fprintf(log, "sandbox: After waitpid for execv(%s,..)\n", = argv_bash[0]);=0A= +//fclose(log);=0A= # endif=0A= return 1;=0A= #endif=0A= @@ -728,7 +742,7 @@=0A= =0A= argv_bash =3D (char **) malloc(6 * sizeof (char *));=0A= argv_bash[0] =3D strdup("/bin/bash");=0A= - argv_bash[1] =3D strdup("-rcfile");=0A= + argv_bash[1] =3D strdup("--rcfile");=0A= argv_bash[2] =3D strdup(sandbox_rc);=0A= =0A= if (argc < 2)=0A= @@ -906,5 +920,3 @@=0A= return 0;=0A= }=0A= }=0A= -=0A= -// vim:expandtab noai:cindent ai=0A= ------=_NextPart_000_0073_01C4207B.6581AD00-- --FL5UXtIhxfXey3p5 Content-Type: text/plain; charset=us-ascii -- gentoo-portage-dev@gentoo.org mailing list --FL5UXtIhxfXey3p5--