mirror of
https://github.com/fdiskyou/Zines.git
synced 2025-03-09 00:00:00 +01:00
1400 lines
44 KiB
Text
1400 lines
44 KiB
Text
![]() |
---[ Phrack Magazine Volume 8, Issue 54 Dec 25th, 1998, article 06 of 12
|
||
|
|
||
|
|
||
|
-------------------------[ The Belt And Suspenders Approach (September 1998)
|
||
|
|
||
|
|
||
|
--------[ route|daemon9 <route@infonexus.com>
|
||
|
|
||
|
|
||
|
|
||
|
----[ Introduction and Impetus
|
||
|
|
||
|
|
||
|
The OpenBSD project team. Purveyors of a FREE, multi-platform 4.4BSD-based
|
||
|
UNIX-like operating system. Their efforts place emphasis on portability,
|
||
|
standardization, correctness, security, and cryptography. And OpenBSD
|
||
|
really concentrates on those last two. OpenBSD is simply the best choice
|
||
|
for multi-user environments.
|
||
|
|
||
|
It is the flawed assumption that security mechanisms can be adequately
|
||
|
provided in layers above the operating system. A perfect security application
|
||
|
cannot make up for flawed or absent security features within the OS kernel.
|
||
|
It is the classic example of building a castle on a swamp. You can build
|
||
|
a strong fortress, but it makes no difference if it slowly sinks into the
|
||
|
ground. In this article, we retrofit the OpenBSD kernel with some additional
|
||
|
security.
|
||
|
|
||
|
This article is about cracking the whip. It's a prime example of security
|
||
|
being (possibly) inconvenient. But by making things potentially a bit more
|
||
|
difficult for normal users, we hope to severely hamper would-be attackers.
|
||
|
Two effective ways of doing this are through limited program execution via
|
||
|
path and credential checks and privacy restrictions.
|
||
|
|
||
|
This article is a follow-up to my P52-06 article on hardening the Linux
|
||
|
kernel. Herein the reader will find several patches designed to harden a
|
||
|
multi-user OpenBSD box. These patches can be broken down into two areas:
|
||
|
privacy restriction and execution restriction (more on these below). The
|
||
|
patches contained here should be used in conjunction with a savvy for
|
||
|
intelligent administration; if you can't recompile a kernel, stop here.
|
||
|
|
||
|
|
||
|
----[ Getting Sources
|
||
|
|
||
|
You will need an OpenBSD 2.4 box with full kernel sources for your
|
||
|
architecture and sources for the following programs: w, who, ps, fstat, and
|
||
|
ld.so. Below are sample instructions for getting the sources you'll need
|
||
|
through anonymous CVS.
|
||
|
|
||
|
I. Pick a server and set the appropriate environment variables:
|
||
|
(assuming csh or tcsh)
|
||
|
1. setenv CVSROOT anoncvs@anoncvs3.usa.openbsd.org:/cvs
|
||
|
2. setenv CVS_RSH /usr/local/bin/ssh
|
||
|
3. cd /usr
|
||
|
|
||
|
II. Get the sources:
|
||
|
1. cvs get src/usr.bin/fstat
|
||
|
2. cvs get src/bin/ps
|
||
|
3. cvs get src/usr.bin/w
|
||
|
4. cvs get src/usr.bin/who
|
||
|
5. cvs get src/gnu/usr.bin/ld/
|
||
|
6. cvs get src/lib/libc/stdio/
|
||
|
|
||
|
III. If you need kernel sources:
|
||
|
(for i386-based machines, other architectures vary slightly)
|
||
|
1. cvs get ksrc-i386 ksrc-common
|
||
|
|
||
|
|
||
|
----[ Privacy Patches
|
||
|
|
||
|
Tested on: 2.4-SNAP (Current as of 12.10.98)
|
||
|
Author: route
|
||
|
|
||
|
Why should we allow anyone to be able to view information on processes they do
|
||
|
not own?
|
||
|
|
||
|
Normally, when a process wants system-wide process table information, it
|
||
|
retrieves it from the kernel virtual memory interface by making calls to a
|
||
|
kvm_*(3) derivative. All that is required is that the process have
|
||
|
permissions to read from /dev/kmem (usually meaning the program file needs to
|
||
|
be sgid kmem). I am of the school of thought that, unless you are really
|
||
|
cool, you don't need to see everyone else's processes on a host. The
|
||
|
privacy patches work towards this end.
|
||
|
|
||
|
|
||
|
----[ Privacy Patches Modus Operandi
|
||
|
|
||
|
Simple credential check. Before the command is allowed to dump savory
|
||
|
information, a UID check is made. If you're not root, you're not going to
|
||
|
see other users' information. Due to the somewhat lazy way this is
|
||
|
implemented, a savvy hacker could defeat this. I leave this as an exercise to
|
||
|
the reader.
|
||
|
|
||
|
|
||
|
----[ Privacy Patches Installation
|
||
|
|
||
|
I. Extract the code from this article:
|
||
|
1. extract P54-06
|
||
|
2. cd PP/
|
||
|
|
||
|
II. Apply the userland diffs:
|
||
|
1. cp Patch/PP-diff /usr/src
|
||
|
2. cd /usr/src
|
||
|
3. patch < PP-diff
|
||
|
|
||
|
III. Next, cd to the relevant directories and build the executables:
|
||
|
1. cd usr.bin/fstat; make; make install
|
||
|
2. cd usr.bin/who; make; make install
|
||
|
3. cd usr.bin/w; make; make install
|
||
|
4. cd bin/ps; make; make install
|
||
|
|
||
|
|
||
|
----[ Trusted Path / ACL Execution Patches
|
||
|
|
||
|
Tested on: 2.4-SNAP (Current as of 12.10.98)
|
||
|
Author: route
|
||
|
|
||
|
Why should we allow arbitrary code execution rights?
|
||
|
|
||
|
Before any call to sys_execve() is allowed to proceed, we take the vnode of
|
||
|
the parent directory that the targeted file lives in and grab the file
|
||
|
attributes via the VOP_GETATTR() macro. We then check to see if the path
|
||
|
is trusted (root owned directory that isn't group or world writable) and,
|
||
|
barring that, we check to see if the user is trusted (on the kernel's trust
|
||
|
list). If the last check fails, the file is denied execution privileges.
|
||
|
|
||
|
Oops! By setting certain environment variables, users can still preload
|
||
|
libraries and modules filled with all sorts of arbitrary code. This is a
|
||
|
no-no. To prevent this, we provide a mechanism to effectively ignore
|
||
|
LD_PRELOAD and LD_LIBRARY_PATH environment variables.
|
||
|
|
||
|
|
||
|
----[ TPE Implementation Overview
|
||
|
|
||
|
The tpe suite consists of 4 components: the in-kernel mechanisms, a system
|
||
|
call, a userland agent and an ld.so component. The kernel resident components
|
||
|
handle the path and credential verification as well as list maintenance.
|
||
|
The system call is the vessel used to convey information from userland to
|
||
|
the kernel and vice versa. The userland agent consists of the tpe
|
||
|
administrative program used to manipulate the trust list (and enable/disable
|
||
|
the ld.so environment checker). The ld.so piece is responsible for grooming
|
||
|
the environment of any illegal variables.
|
||
|
|
||
|
|
||
|
----[ TPE Trust List Kernel Interface and Abstract Data Types
|
||
|
|
||
|
The trust list inside the kernel is a static array of type `uid_t`. The
|
||
|
decision was the made to use a static array to hold the trusted IDs for both
|
||
|
convenience and runtime efficiency. By default, the list is elements long.
|
||
|
If this for some reason is not sufficient, it can be increased by changing the
|
||
|
CPP symbolic constant TPE_ACL_SIZE (however, you should first probably ask
|
||
|
yourself why you need more than 80 trusted users).
|
||
|
|
||
|
The speed in which user ID verification is done is absolutely essential, as
|
||
|
this check will be done for every call to exec that does not originate from a
|
||
|
trusted path. This has the potential to be a huge bottle neck. This was
|
||
|
taken into consideration and the bulk of processing overhead is offloaded to
|
||
|
list initialization and modification.
|
||
|
|
||
|
The list is kept ordered after all insertions and deletions via insertion sort.
|
||
|
Sorting is relatively costly (insertion sort has a running time of about
|
||
|
O(n^2)) and is done when response time is not absolutely critical, during list
|
||
|
additions and deletions.
|
||
|
|
||
|
Speed is essential when the lookups are done, and, since the list is ordered,
|
||
|
a binary search can be done in a worst case of O(lg N). In fact, with the
|
||
|
default list size of 80 elements, we can be guaranteed no more than 7
|
||
|
comparisons will be done. Compare that with a sequential search in an
|
||
|
ordered list which has a worst case of O(N) (80 comparisons).
|
||
|
|
||
|
|
||
|
----[ TPE ld.so protection
|
||
|
|
||
|
The dynamic linker is a great tool that allows us to write small programs
|
||
|
that load external code at runtime. On a macro scale, ld.so allows processes
|
||
|
to load arbitrary external code for execution. This can be used to bypass
|
||
|
our execution restrictions. A user could bypass path trust by simply loading
|
||
|
code dynamically via library or object code redirection. This is against
|
||
|
our best interests. To prevent this, we patch ld.so to strip the
|
||
|
LD_PRELOAD and LD_LIBRARY_PATH environment variables.
|
||
|
|
||
|
There is a global int, tpe_ld_check, that is set, cleared and checked via
|
||
|
the system call. When set, ld.so checks the environment of any non UID 0
|
||
|
process and calls unsetenv if LD_PRELOAD and/or LD_LIBRARY_PATH exist. The
|
||
|
variables still exist in the user's environment, but they are ignored
|
||
|
during the dynamic linking.
|
||
|
|
||
|
|
||
|
----[ What TPE will do
|
||
|
|
||
|
Trusted path execution will prevent arbitrary users from executing arbitrary
|
||
|
code. This means that malicious users cannot execute exploit programs to
|
||
|
try and break root on your machine. This also means that they can't execute
|
||
|
exploit programs and try to hack from your machine. It affords an
|
||
|
administrator an extra level of confidence that her system is secure.
|
||
|
|
||
|
|
||
|
----[ What TPE will not do
|
||
|
|
||
|
TPE relies on auditing a call to one of exec(2) family of functions. It
|
||
|
ensures that the program file that contains the code to be executed resides
|
||
|
in a trusted directory or is being executed by a trusted user. Programs
|
||
|
living in a trusted directory that interpret symbolic code and link and
|
||
|
assemble at runtime (and call exec from a trusted path) can bypass our
|
||
|
TPE security mandate and must be audited differently. These are programs
|
||
|
such as perl, any of the shell interpreters, sed, awk, etc... While a
|
||
|
malicious user cannot just whip up a script in her home directory (it would be
|
||
|
denied execution rights because it lives in an untrusted directory) she could
|
||
|
specify the code on the command line or redirect it from a file.
|
||
|
|
||
|
There are different ways to tackle this problem, none of them very elegant.
|
||
|
Changing the file permissions and ownership to allow only members of a
|
||
|
certain group access to these files is a simple effort and an obvious
|
||
|
choice, but will not work for the shell interpreters. Moving all of these
|
||
|
programs to a special non-trusted directory would also work (normal users
|
||
|
would not be able to execute them, but trusted users would), but again,
|
||
|
this will not work for the shell programs.
|
||
|
|
||
|
To prevent the shell programs from being to execute arbitrary code it seems
|
||
|
like the only real solution would be to patch them. This way you can prevent
|
||
|
naughty activity and still get desired functionality.
|
||
|
|
||
|
Another area of trouble is command line buffer overflows. If a trusted
|
||
|
program happens to contain a buffer overflow that is exploitable from the
|
||
|
command line, an attacker can bypass the TPE and get arbitrary code executed.
|
||
|
The overflow shellcode is passed in as standard command line argument and
|
||
|
is not illegal as far as TPE sees. One possible fix is to audit or sanitize
|
||
|
the command arguments before granting execution rights.
|
||
|
|
||
|
The other noteworthy issue regarding TPE is the fact that it generally does not
|
||
|
protect the machine from remote attacks. Daemons running as root or as a
|
||
|
trusted user id (usually the case -- otherwise how would it be started in the
|
||
|
first place?) will be allowed execution rites. If this code contains
|
||
|
remotely exploitable buffer overflows, TPE cannot prevent arbitrary code
|
||
|
execution.
|
||
|
|
||
|
|
||
|
----[ tpe_adm
|
||
|
|
||
|
The userland agent is painfully simple to use. To show the kernel's trusted
|
||
|
user list:
|
||
|
|
||
|
resentment:~# tpe_adm -s
|
||
|
trusted users: root diablerie
|
||
|
|
||
|
To add a user to the list:
|
||
|
|
||
|
resentment:~# tpe_adm -a devilish
|
||
|
UID 1000 added to trust list
|
||
|
resentment:~# tpe_adm -s
|
||
|
trusted users: root diablerie devilish
|
||
|
|
||
|
To remove a user from the list:
|
||
|
|
||
|
resentment:~# tpe_adm -d diablerie
|
||
|
UID 1000 removed from trust list
|
||
|
resentment:~# tpe_adm -s
|
||
|
trusted users: root diablerie
|
||
|
|
||
|
To enable/disable ld.so environment checking:
|
||
|
|
||
|
resentment:~# tpe_adm -le
|
||
|
ld.so environment protection enabled
|
||
|
resentment:~# tpe_adm -ls
|
||
|
ld.so environment protection is currently on
|
||
|
resentment:~# tpe_adm -ld
|
||
|
ld.so environment protection disabled
|
||
|
resentment:~# tpe_adm -ls
|
||
|
ld.so environment protection is currently off
|
||
|
|
||
|
|
||
|
----[ TPE Installation
|
||
|
|
||
|
I. Extract the code from this article:
|
||
|
1. extract P54-06
|
||
|
2. cd TPE/
|
||
|
|
||
|
II. Apply the kernel diffs:
|
||
|
1. cp Core/Patch/TPE-diff /usr/src/sys
|
||
|
2. cd /usr/src/sys/
|
||
|
3. patch < TPE-diff
|
||
|
4. note any errors. hope they are benign.
|
||
|
|
||
|
III. Apply the ld.so diff:
|
||
|
1. cp Core/Patch/ld.so-diff /usr/src/
|
||
|
2. cd /usr/src/
|
||
|
3. patch < ld.so-diff
|
||
|
|
||
|
IV. Copy over the tpe core files:
|
||
|
1. cp Core/kern/kern_tpe.c /usr/src/sys/kern
|
||
|
2. cp Core/kern/kern_tpe_sys.c /usr/src/sys/kern
|
||
|
3. cp Core/sys/kern_tpe.h /usr/src/sys/sys
|
||
|
|
||
|
V. Rebuild your syscall table:
|
||
|
1. cd /usr/src/sys/kern
|
||
|
2. make
|
||
|
|
||
|
VI. Copy over the syscall include files:
|
||
|
1. cp /usr/src/sys/sys/syscall.h /usr/include/sys
|
||
|
2. cp /usr/src/sys/sys/syscallargs.h /usr/include/sys
|
||
|
|
||
|
VII. Reconfigure your kernel:
|
||
|
(This step assumes you have a previously configured kernel named
|
||
|
YOUR_KERNEL. If you haven't, you need to config a kernel. Refer
|
||
|
to OpenBSD documentation on how to do this.)
|
||
|
1. cd /usr/src/sys/arch/YOUR_ARCH/conf
|
||
|
2. config YOUR_KERNEL
|
||
|
|
||
|
VIII. Remake the dependencies and rebuild the kernel:
|
||
|
1. cd /usr/src/sys/arch/YOUR_ARCH/compile/YOUR_KERNEL
|
||
|
2. make depend ; make clean ; make
|
||
|
3. note any errors. hope you can fix them.
|
||
|
3. cp /bsd /bsd.old ; cp bsd /
|
||
|
4. reboot
|
||
|
|
||
|
IX. Build the new ld.so
|
||
|
1. cd /usr/src
|
||
|
2. cp lib/libc/stdio/vfprintf.c /usr/src/gnu/usr.bin/ld/rtld
|
||
|
3. cp lib/libc/stdio/local.h /usr/src/gnu/usr.bin/ld/rtld
|
||
|
4. cp lib/libc/stdio/fvwrite.h /usr/src/gnu/usr.bin/ld/rtld
|
||
|
5. cd /usr/src/gnu/usr.bin/ld/rtld
|
||
|
6. make ; make install
|
||
|
|
||
|
X. Build the TPE admin program:
|
||
|
1. cd Core/Admin/ ; make
|
||
|
2. make install
|
||
|
|
||
|
XI. Test it out:
|
||
|
1. As root, dump the current trust list:
|
||
|
(Only UID 0 should be on it.)
|
||
|
tpe_adm -s
|
||
|
trusted users: root
|
||
|
|
||
|
2. Try the following as an untrusted user (i.e. UID=1000):
|
||
|
cat > foo.c << EOF ; gcc foo.c
|
||
|
int main(int argc, char **argv){ printf("Hello world\n"); }
|
||
|
EOF
|
||
|
./a.out
|
||
|
EPERM should result.
|
||
|
|
||
|
3. Now add the user to the trust list:
|
||
|
tpe_adm -a UID
|
||
|
|
||
|
4. Dump the list again:
|
||
|
(You should see the user on the list.)
|
||
|
tpe_adm -s
|
||
|
|
||
|
5. Try to execute the command again as the user:
|
||
|
./a.out
|
||
|
Hello world
|
||
|
|
||
|
6. Add only the necessary UIDs to the list.
|
||
|
|
||
|
7. NOTE TO QMAIL USERS:
|
||
|
You may find that you will need to explicitly add the qmailq
|
||
|
UID to the trust list. Do this in an rc startup script that
|
||
|
runs before the qmail daemons start.
|
||
|
|
||
|
8. As root, ensure that ld.so environment protection is enabled:
|
||
|
tpe_adm -le
|
||
|
ld.so environment protection enabled
|
||
|
|
||
|
9. As an unprivileged user:
|
||
|
setenv LD_PRELOAD test.o
|
||
|
ls -l
|
||
|
Your environment contains illegal variables which are being
|
||
|
stripped out for the execution of this program
|
||
|
a.out fo.c foo.c
|
||
|
|
||
|
10. As root, ensure that ld.so environment protection is disabled:
|
||
|
tpe_adm -ld
|
||
|
ld.so environment protection disabled
|
||
|
|
||
|
11. As an unprivileged user:
|
||
|
ls
|
||
|
/usr/libexec/ld.so: preload: test.o: cannot map object
|
||
|
|
||
|
12. You're done. Pat yourself on the back and buy something from
|
||
|
Precious Roy.
|
||
|
|
||
|
|
||
|
----[ The Code
|
||
|
|
||
|
<++> TPE/Core/Admin/Makefile
|
||
|
# $Id: P54-06,v 1.16 1998/12/10 00:01:28 route Exp $
|
||
|
# Trusted path ACL implementation for OpenBSD 2.4
|
||
|
# Copyright (c) 1998 route|daemon9 and Mike D. Schiffman
|
||
|
# All rights reserved.
|
||
|
#
|
||
|
# Originally published in Phrack Magazine (http://www.phrack.com).
|
||
|
|
||
|
tpe_adm:
|
||
|
$(CC) tpe_adm.c -o tpe_adm
|
||
|
|
||
|
install: tpe_adm
|
||
|
install -m 711 -o 0 tpe_adm /usr/local/sbin
|
||
|
|
||
|
clean:
|
||
|
rm -rf core a.out tpe_adm
|
||
|
|
||
|
# EOF
|
||
|
<-->
|
||
|
<++> TPE/Core/Admin/tpe_adm.c
|
||
|
/*
|
||
|
* $Id: P54-06,v 1.16 1998/12/10 00:01:28 route Exp $
|
||
|
* Trusted path ACL userland administrative agent for OpenBSD 2.4
|
||
|
*
|
||
|
* Copyright (c) 1998 route|daemon9 and Mike D. Schiffman
|
||
|
* All rights reserved.
|
||
|
* Originally published in Phrack Magazine (http://www.phrack.com).
|
||
|
*
|
||
|
* Thanks to nirva for helping me choose an ADT.
|
||
|
* See <sys/kern_tpe.h> for more info.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
|
* SUCH DAMAGE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/syscall.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <pwd.h>
|
||
|
#include "../sys/kern_tpe.h"
|
||
|
|
||
|
void usage();
|
||
|
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
uid_t list[TPE_ACL_SIZE];
|
||
|
int c, i, mode;
|
||
|
uid_t candidate;
|
||
|
struct passwd *pwd;
|
||
|
|
||
|
if (geteuid() && getuid())
|
||
|
{
|
||
|
fprintf(stderr, "root access required\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
if (argc == 1 || argc > 3)
|
||
|
{
|
||
|
usage();
|
||
|
exit(EXIT_SUCCESS);
|
||
|
}
|
||
|
|
||
|
while ((c = getopt(argc, argv, "a:d:l:s")) != EOF)
|
||
|
{
|
||
|
switch (c)
|
||
|
{
|
||
|
case 'a':
|
||
|
if (isalpha(optarg[0]))
|
||
|
{
|
||
|
pwd = getpwnam(optarg);
|
||
|
if(!pwd)
|
||
|
{
|
||
|
fprintf(stderr, "Unknown user: \"%s\"\n", optarg);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
candidate = pwd->pw_uid;
|
||
|
}
|
||
|
else if (!(candidate = (uid_t)atol(optarg)))
|
||
|
{
|
||
|
fprintf(stderr, "invalid UID: \"%s\"\n", optarg);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
if (syscall(SYS_tpe_adm, TPE_ADD, candidate, NULL) == -1)
|
||
|
{
|
||
|
printf("Full trust list\n");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
printf("UID %d added to trust list\n", candidate);
|
||
|
break;
|
||
|
case 'd':
|
||
|
if (isalpha(optarg[0]))
|
||
|
{
|
||
|
pwd = getpwnam(optarg);
|
||
|
if(!pwd)
|
||
|
{
|
||
|
fprintf(stderr, "Unknown user: \"%s\"\n", optarg);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
candidate = pwd->pw_uid;
|
||
|
}
|
||
|
else if (!(candidate = (uid_t)atol(optarg)))
|
||
|
{
|
||
|
fprintf(stderr, "invalid UID: \"%s\"\n", optarg);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
if (syscall(SYS_tpe_adm, TPE_REMOVE, candidate, NULL) == -1)
|
||
|
{
|
||
|
printf("UID %d not found on trust list\n", candidate);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
printf("UID %d removed from trust list\n", candidate);
|
||
|
break;
|
||
|
case 'l':
|
||
|
if (optarg[0] == 'e')
|
||
|
{
|
||
|
if (syscall(SYS_tpe_adm, TPE_LDCHECK_E, -1, NULL) == -1)
|
||
|
{
|
||
|
printf("Unknown internal error\n"); /* should NOT fail */
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
printf("ld.so environment protection enabled\n");
|
||
|
}
|
||
|
else if (optarg[0] == 'd')
|
||
|
{
|
||
|
if (syscall(SYS_tpe_adm, TPE_LDCHECK_D, -1, NULL) == -1)
|
||
|
{
|
||
|
printf("Unknown internal error\n"); /* should NOT fail */
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
printf("ld.so environment protection disabled\n");
|
||
|
}
|
||
|
else if (optarg[0] == 's')
|
||
|
{
|
||
|
if (syscall(SYS_tpe_adm, TPE_LDCHECK_S, -1, list) == -1)
|
||
|
{
|
||
|
printf("Unknown internal error\n"); /* should NOT fail */
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
printf("ld.so environment protection is currently %s\n",
|
||
|
list[0] ? "on" : "off");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fprintf(stderr, "Huh?\n");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
break;
|
||
|
case 's':
|
||
|
/*
|
||
|
* It is Very Important that `list` is an array of size
|
||
|
* TPE_ACL_SIZE. The kernel expects this. Failure to do
|
||
|
* so can result in a panic. However, only root can issue
|
||
|
* the tpe_adm system call.
|
||
|
*/
|
||
|
if (syscall(SYS_tpe_adm, TPE_SHOW, -1, list) == -1)
|
||
|
{
|
||
|
/*
|
||
|
* Should NOT fail.
|
||
|
*/
|
||
|
printf("Hideous internal error\n");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
printf("trusted users: ");
|
||
|
for (i = 0; list[i] != TPE_INITIALIZER; i++)
|
||
|
{
|
||
|
pwd = getpwuid(list[i]);
|
||
|
if (pwd)
|
||
|
{
|
||
|
printf("%s ", pwd->pw_name);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("%d ", (int)list[i]);
|
||
|
}
|
||
|
}
|
||
|
printf("\n");
|
||
|
break;
|
||
|
default:
|
||
|
usage();
|
||
|
exit(EXIT_SUCCESS);
|
||
|
}
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
usage()
|
||
|
{
|
||
|
fprintf(stderr, "usage: tpe_adm [-a UID] Add a UID to the trust list\n"
|
||
|
"[-d UID] Delete a UID from the list\n"
|
||
|
"[-l e|n] Toggle LD_* usage\n"
|
||
|
"[-l s] Show status of ld.so protection\n"
|
||
|
"[-s] Show the current list\n");
|
||
|
}
|
||
|
<-->
|
||
|
<++> TPE/Core/Patch/TPE-diff
|
||
|
--- ./kern/init_main.c Tue Sep 15 23:21:08 1998
|
||
|
+++ ../Core/kern/init_main.c Sun Oct 18 12:26:24 1998
|
||
|
@@ -80,6 +80,7 @@
|
||
|
|
||
|
#include <sys/syscall.h>
|
||
|
#include <sys/syscallargs.h>
|
||
|
+#include <sys/kern_tpe.h>
|
||
|
|
||
|
#include <ufs/ufs/quota.h>
|
||
|
|
||
|
@@ -424,6 +425,16 @@
|
||
|
srandom((u_long)(rtv.tv_sec ^ rtv.tv_usec));
|
||
|
|
||
|
randompid = 1;
|
||
|
+
|
||
|
+ tpe_init();
|
||
|
+ printf("Trusted patch execution list initialized\n");
|
||
|
+ /*
|
||
|
+ * root must be added hard at this point. For safey's sake, the
|
||
|
+ * userland agent can't do anything with UID 0 to prevent morons
|
||
|
+ * from locking themselves out of their machines.
|
||
|
+ */
|
||
|
+ tpe_add(0);
|
||
|
+
|
||
|
/* The scheduler is an infinite loop. */
|
||
|
scheduler();
|
||
|
/* NOTREACHED */
|
||
|
--- ./kern/syscalls.master Thu Sep 17 13:54:04 1998
|
||
|
+++ ../Core/kern/syscalls.master Sun Oct 18 12:35:59 1998
|
||
|
@@ -479,7 +479,8 @@
|
||
|
242 UNIMPL
|
||
|
243 UNIMPL
|
||
|
244 UNIMPL
|
||
|
-245 UNIMPL
|
||
|
+245 STD { int sys_tpe_adm(int mode, uid_t candidate, \
|
||
|
+ uid_t *list); }
|
||
|
246 UNIMPL
|
||
|
247 UNIMPL
|
||
|
248 UNIMPL
|
||
|
--- ./kern/kern_exec.c Thu Sep 24 11:49:31 1998
|
||
|
+++ ../Core/kern/kern_exec.c Sun Oct 18 12:32:03 1998
|
||
|
@@ -51,12 +51,16 @@
|
||
|
#include <sys/mman.h>
|
||
|
#include <sys/signalvar.h>
|
||
|
#include <sys/stat.h>
|
||
|
+#include <ufs/ufs/quota.h>
|
||
|
+#include <ufs/ufs/inode.h>
|
||
|
#ifdef SYSVSHM
|
||
|
#include <sys/shm.h>
|
||
|
#endif
|
||
|
|
||
|
#include <sys/syscallargs.h>
|
||
|
-
|
||
|
+#include <sys/kern_tpe.h>
|
||
|
+#include <sys/systm.h>
|
||
|
+
|
||
|
#include <vm/vm.h>
|
||
|
#include <vm/vm_kern.h>
|
||
|
|
||
|
@@ -93,6 +97,7 @@
|
||
|
struct exec_package *epp;
|
||
|
{
|
||
|
int error, i;
|
||
|
+ struct vattr at;
|
||
|
struct vnode *vp;
|
||
|
struct nameidata *ndp;
|
||
|
size_t resid;
|
||
|
@@ -146,6 +151,30 @@
|
||
|
if (error)
|
||
|
goto bad2;
|
||
|
epp->ep_hdrvalid = epp->ep_hdrlen - resid;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Get the file attributes of the parent directory that the
|
||
|
+ * executable lives in.
|
||
|
+ */
|
||
|
+ if ((error = VOP_GETATTR(ndp->ni_dvp, &at, NULL, NULL)) != 0)
|
||
|
+ {
|
||
|
+ goto bad2;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Trusted path check.
|
||
|
+ */
|
||
|
+ if (!TRUSTED_PATH(at))
|
||
|
+ {
|
||
|
+ /*
|
||
|
+ * Trusted user check.
|
||
|
+ */
|
||
|
+ if (!TRUSTED_USER(p->p_ucred->cr_uid))
|
||
|
+ {
|
||
|
+ error = EACCES;
|
||
|
+ goto bad2;
|
||
|
+ }
|
||
|
+ }
|
||
|
|
||
|
/*
|
||
|
* set up the vmcmds for creation of the process
|
||
|
--- ./conf/files Sun Sep 27 19:43:22 1998
|
||
|
+++ ../Core/conf/files Sun Oct 18 12:40:28 1998
|
||
|
@@ -209,6 +209,8 @@
|
||
|
file kern/kern_sysctl.c
|
||
|
file kern/kern_synch.c
|
||
|
file kern/kern_time.c
|
||
|
+file kern/kern_tpe.c
|
||
|
+file kern/kern_tpe_sys.c
|
||
|
file kern/kern_xxx.c
|
||
|
file kern/subr_autoconf.c
|
||
|
file kern/subr_disk.c
|
||
|
<-->
|
||
|
<++> TPE/Core/kern/kern_tpe.c
|
||
|
/*
|
||
|
* $Id: P54-06,v 1.16 1998/12/10 00:01:28 route Exp $
|
||
|
* Trusted path ACL implementation for OpenBSD 2.4
|
||
|
*
|
||
|
* Copyright (c) 1998 route|daemon9 and Mike D. Schiffman
|
||
|
* All rights reserved.
|
||
|
* Originally published in Phrack Magazine (http://www.phrack.com).
|
||
|
*
|
||
|
* Thanks to nirva for helping me choose an ADT.
|
||
|
* See <sys/kern_tpe.h> for more info.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
|
* SUCH DAMAGE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <sys/kern_tpe.h>
|
||
|
|
||
|
void
|
||
|
tpe_init()
|
||
|
{
|
||
|
memset(tpe_acl, TPE_INITIALIZER, sizeof(uid_t) * TPE_ACL_SIZE);
|
||
|
tpe_acl_candidates = 0;
|
||
|
tpe_ld_check = 1;
|
||
|
#if (AUTO_ADD_ROOT)
|
||
|
tpe_acl[0] = 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
tpe_show()
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
printf("%d trusted users: ", tpe_acl_candidates);
|
||
|
for (i = 0; i < tpe_acl_candidates; i++)
|
||
|
{
|
||
|
printf("%d ", tpe_acl[i]);
|
||
|
}
|
||
|
printf("\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
tpe_add(uid_t candidate)
|
||
|
{
|
||
|
if (tpe_acl_candidates == TPE_ACL_SIZE)
|
||
|
{
|
||
|
/*
|
||
|
* Full list.
|
||
|
*/
|
||
|
return (NACK);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Don't add duplicates.
|
||
|
*/
|
||
|
if ((tpe_search(candidate, 0, tpe_acl_candidates)) == NACK)
|
||
|
{
|
||
|
/*
|
||
|
* Add to the end of the list, then sort.
|
||
|
*/
|
||
|
tpe_acl_candidates++;
|
||
|
tpe_acl[tpe_acl_candidates] = candidate;
|
||
|
tpe_sort(0, tpe_acl_candidates);
|
||
|
|
||
|
printf("tpe: UID %d added to trust list\n", candidate);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("tpe: duplicate UID %d not added\n", candidate);
|
||
|
}
|
||
|
return (ACK);
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
tpe_remove(uid_t candidate)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
if (tpe_acl_candidates == 0)
|
||
|
{
|
||
|
/*
|
||
|
* Empty list.
|
||
|
*/
|
||
|
return (NACK);
|
||
|
}
|
||
|
if ((n = tpe_search(candidate, 0, tpe_acl_candidates)) != NACK)
|
||
|
{
|
||
|
/*
|
||
|
* Remove the candidate (mark the slot as unused), resort the list.
|
||
|
*/
|
||
|
tpe_acl[n] = TPE_INITIALIZER;
|
||
|
tpe_acl_candidates--;
|
||
|
tpe_sort(0, tpe_acl_candidates);
|
||
|
|
||
|
printf("tpe: UID %d removed from trust list\n", candidate);
|
||
|
return (ACK);
|
||
|
}
|
||
|
/*
|
||
|
* Not found.
|
||
|
*/
|
||
|
return (NACK);
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
tpe_verify(uid_t candidate)
|
||
|
{
|
||
|
if ((tpe_search(candidate, 0, tpe_acl_candidates)) != NACK)
|
||
|
{
|
||
|
return (ACK);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (NACK);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
tpe_sort(int low, int high)
|
||
|
{
|
||
|
int i, j, n;
|
||
|
|
||
|
/*
|
||
|
* Standard insertion sort.
|
||
|
*/
|
||
|
for (i = low + 1; i <= high; i++)
|
||
|
{
|
||
|
COMPSWAP(tpe_acl[low], tpe_acl[i]);
|
||
|
}
|
||
|
|
||
|
for (i = low + 2; i <= high; i++)
|
||
|
{
|
||
|
j = i;
|
||
|
n = tpe_acl[i];
|
||
|
while (LESS(n, tpe_acl[j - 1]))
|
||
|
{
|
||
|
tpe_acl[j] = tpe_acl[j - 1];
|
||
|
j--;
|
||
|
}
|
||
|
tpe_acl[j] = n;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
tpe_search(uid_t candidate, int low, int high)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
/*
|
||
|
* Standard binary search. XXX - should be iterative.
|
||
|
*/
|
||
|
n = (low + high) / 2;
|
||
|
|
||
|
if (low > high)
|
||
|
{
|
||
|
return (NACK);
|
||
|
}
|
||
|
if (candidate == tpe_acl[n])
|
||
|
{
|
||
|
return (n);
|
||
|
}
|
||
|
if (low == high)
|
||
|
{
|
||
|
return (NACK);
|
||
|
}
|
||
|
if (LESS(candidate, tpe_acl[n]))
|
||
|
{
|
||
|
return (tpe_search(candidate, low, n - 1));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (tpe_search(candidate, n + 1, high));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* EOF */
|
||
|
<-->
|
||
|
<++> TPE/Core/kern/kern_tpe_sys.c
|
||
|
/*
|
||
|
* $Id: P54-06,v 1.16 1998/12/10 00:01:28 route Exp $
|
||
|
* Trusted path ACL syscall implementation for OpenBSD 2.4
|
||
|
*
|
||
|
* Copyright (c) 1998 route|daemon9 and Mike D. Schiffman
|
||
|
* All rights reserved.
|
||
|
* Originally published in Phrack Magazine (http://www.phrack.com).
|
||
|
*
|
||
|
* Thanks to nirva for helping me choose an ADT.
|
||
|
* See <sys/kern_tpe.h> for more info.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
|
* SUCH DAMAGE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <sys/kern_tpe.h>
|
||
|
#include <sys/systm.h>
|
||
|
|
||
|
#include <sys/mount.h>
|
||
|
#include <sys/syscallargs.h>
|
||
|
|
||
|
|
||
|
int
|
||
|
sys_tpe_adm(p, v, retval)
|
||
|
struct proc *p;
|
||
|
void *v;
|
||
|
register_t *retval;
|
||
|
{
|
||
|
struct sys_tpe_adm_args /* {
|
||
|
syscallarg(int) mode;
|
||
|
syscallarg(uid_t) candidate;
|
||
|
syscallarg(uid_t *) list;
|
||
|
} */ *uap = v;
|
||
|
register struct pcred *pc = p->p_cred;
|
||
|
register int i;
|
||
|
register uid_t *lp;
|
||
|
|
||
|
/*
|
||
|
* The only thing a non root user can do is check the status of the
|
||
|
* ld.so environment protection. This is necessary because ld.so
|
||
|
* runs without elevated privilidges and needs to check this.
|
||
|
*/
|
||
|
if (suser(pc->pc_ucred, &p->p_acflag) && SCARG(uap, mode) != TPE_LDCHECK_S)
|
||
|
{
|
||
|
return (EPERM);
|
||
|
}
|
||
|
|
||
|
switch (SCARG(uap, mode))
|
||
|
{
|
||
|
case TPE_ADD:
|
||
|
if (tpe_add(SCARG(uap, candidate)) == ACK)
|
||
|
{
|
||
|
return (0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (ENOSPC); /* Ugh. Best we can do. */
|
||
|
}
|
||
|
case TPE_REMOVE:
|
||
|
if (tpe_remove(SCARG(uap, candidate)) == ACK)
|
||
|
{
|
||
|
return (0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (ENOSPC); /* Ugh. */
|
||
|
}
|
||
|
case TPE_SHOW:
|
||
|
lp = SCARG(uap, list);
|
||
|
if (lp == NULL)
|
||
|
{
|
||
|
return (ENOSPC);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i = 0; i < TPE_ACL_SIZE; i++)
|
||
|
{
|
||
|
lp[i] = tpe_acl[i];
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
case TPE_LDCHECK_E:
|
||
|
tpe_ld_check = 1;
|
||
|
return (0);
|
||
|
case TPE_LDCHECK_D:
|
||
|
tpe_ld_check = 0;
|
||
|
return (0);
|
||
|
case TPE_LDCHECK_S:
|
||
|
lp = SCARG(uap, list);
|
||
|
if (lp == NULL)
|
||
|
{
|
||
|
return (ENOSPC);
|
||
|
}
|
||
|
else /* XXX - sysctl would be cleaner. */
|
||
|
{
|
||
|
lp[0] = tpe_ld_check;
|
||
|
return (0);
|
||
|
}
|
||
|
default:
|
||
|
return (ENXIO); /* Ugh. */
|
||
|
}
|
||
|
return (ENXIO);
|
||
|
}
|
||
|
<-->
|
||
|
<++> TPE/Core/sys/kern_tpe.h
|
||
|
/*
|
||
|
* $Id: P54-06,v 1.16 1998/12/10 00:01:28 route Exp $
|
||
|
* Trusted path ACL implementation for OpenBSD 2.4
|
||
|
*
|
||
|
* Copyright (c) 1998 route|daemon9 and Mike D. Schiffman
|
||
|
* All rights reserved.
|
||
|
* Originally published in Phrack Magazine (http://www.phrack.com).
|
||
|
*
|
||
|
* Thanks to nirva for helping me choose an ADT.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
|
* SUCH DAMAGE.
|
||
|
*
|
||
|
* Trusted path ACL implementation for OpenBSD 2.4
|
||
|
*
|
||
|
* For the full write-up please see Phrack Magazine, issue 54, article 6
|
||
|
* http://www.phrack.com
|
||
|
*
|
||
|
* Overview:
|
||
|
*
|
||
|
* A trusted path/ACL execution implementation for OpenBSD. We consider
|
||
|
* a path to be trusted if the parent directory is owned by root and is not
|
||
|
* group or world writable. We consider a user to be trusted if she is on
|
||
|
* the kernels trust list.
|
||
|
*
|
||
|
* Implementation details:
|
||
|
*
|
||
|
* Inside the kern_exec function, we first check the path for trust, if that
|
||
|
* fails, we then check the user's credentials to see if she is able to run
|
||
|
* binaries in an untrusted path. Untrusted users are not allowed to execute
|
||
|
* programs from untrusted pathes.
|
||
|
*
|
||
|
* The decision was the made to use a static array to hold the trusted IDs
|
||
|
* for both convienience and runtime efficiency. We keep the list ordered
|
||
|
* after all insertions and deletions, and therefore, we can search the list
|
||
|
* (where speed is critical) in a worst case of O(lg N). Compare that with a
|
||
|
* sequential search in an ordered list which has a worst case of O(N).
|
||
|
*
|
||
|
* The speed in which user ID verification is done is absolutely essential,
|
||
|
* as this check will be done for every call to exec that does not originate
|
||
|
* from a trusted path. This has the potential to be a huge bottle neck.
|
||
|
* This was taken into consideration and the bulk of processing overhead is
|
||
|
* offloaded to list initialization and modification.
|
||
|
*/
|
||
|
|
||
|
#ifndef __KERN_TPE_H
|
||
|
#define __KERN_TPE_H
|
||
|
|
||
|
#ifdef _KERNEL
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/cdefs.h>
|
||
|
#include <sys/systm.h>
|
||
|
#include <sys/param.h>
|
||
|
#include <sys/ucred.h>
|
||
|
#include <sys/proc.h>
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* syscall stuff
|
||
|
*/
|
||
|
#define TPE_ADD 0 /* add an entry */
|
||
|
#define TPE_REMOVE 1 /* delete an entry */
|
||
|
#define TPE_SHOW 2 /* show the list */
|
||
|
#define TPE_LDCHECK_E 3 /* enable ld.so environment checking */
|
||
|
#define TPE_LDCHECK_D 4 /* disable ld.so environment checking */
|
||
|
#define TPE_LDCHECK_S 5 /* show ld.so environment check status */
|
||
|
|
||
|
#define TPE_ACL_SIZE 80 /* Shouldn't need to be larger */
|
||
|
#define TPE_INITIALIZER -1 /* A UID that isn't used */
|
||
|
|
||
|
#define ACK 1 /* positive acknowledgement */
|
||
|
#define NACK -1 /* negative acknowledgement */
|
||
|
|
||
|
#define LESS(X, Y) (X < Y)
|
||
|
#define SWAP(X, Y) (X ^= Y, Y ^= X, X ^= Y)
|
||
|
#define COMPSWAP(X, Y) if (LESS(Y, X)) SWAP(X, Y)
|
||
|
|
||
|
/*
|
||
|
* Verify the path. This macro is passed a filled in attr struct via
|
||
|
* VOP_GETATTR.
|
||
|
*/
|
||
|
#define TRUSTED_PATH(AT) \
|
||
|
(!(AT.va_mode & (S_IWGRP | S_IWOTH)) && (AT.va_uid == 0))
|
||
|
|
||
|
/*
|
||
|
* Verify the user. This macro is passed the user's ID from the u_cred
|
||
|
* struct.
|
||
|
*/
|
||
|
#define TRUSTED_USER(UID) (tpe_verify(UID) == ACK)
|
||
|
|
||
|
uid_t tpe_acl[TPE_ACL_SIZE]; /* trusted user list */
|
||
|
int tpe_acl_candidates; /* number of users on the list */
|
||
|
int tpe_ld_check; /* check ld.so env */
|
||
|
|
||
|
/*
|
||
|
* Initialize the array with default values (TPE_INITIALIZER).
|
||
|
*/
|
||
|
void
|
||
|
tpe_init __P((
|
||
|
void
|
||
|
));
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Dump the list.
|
||
|
*/
|
||
|
void
|
||
|
tpe_show __P((
|
||
|
void
|
||
|
));
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Attempt to add a candidate to the list. Only fails if the list is full.
|
||
|
*/
|
||
|
int
|
||
|
tpe_add __P((
|
||
|
uid_t /* candidate user for addition */
|
||
|
));
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Attempt to remove a candidate from the list. Only fails if the entry is
|
||
|
* not there.
|
||
|
*/
|
||
|
int
|
||
|
tpe_remove __P((
|
||
|
uid_t /* candidate user for deletion */
|
||
|
));
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Verify a candidate user.
|
||
|
*/
|
||
|
int
|
||
|
tpe_verify __P((
|
||
|
uid_t /* candidate user for verification */
|
||
|
));
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Insertion sort the list.
|
||
|
*/
|
||
|
void
|
||
|
tpe_sort __P((
|
||
|
int, /* list low element */
|
||
|
int /* list high high element */
|
||
|
));
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Locate a uid in the list, standard recursive binary search, running in
|
||
|
* worst case of lg N.
|
||
|
*/
|
||
|
int
|
||
|
tpe_search __P((
|
||
|
uid_t, /* candidate user to search for */
|
||
|
int, /* list low element */
|
||
|
int /* list high high element */
|
||
|
));
|
||
|
|
||
|
#endif /* __KERN_TPE_H */
|
||
|
/* EOF */
|
||
|
<-->
|
||
|
<++> PP/Patch/PP-diff
|
||
|
--- ./usr.bin/fstat/fstat.c.orig Tue Oct 20 10:43:58 1998
|
||
|
+++ ./usr.bin/fstat/fstat.c Tue Oct 20 10:47:22 1998
|
||
|
@@ -158,6 +158,7 @@
|
||
|
char *memf, *nlistf;
|
||
|
char buf[_POSIX2_LINE_MAX];
|
||
|
int cnt;
|
||
|
+ pid_t __uid;
|
||
|
|
||
|
arg = 0;
|
||
|
what = KERN_PROC_ALL;
|
||
|
@@ -248,7 +249,12 @@
|
||
|
else
|
||
|
putchar('\n');
|
||
|
|
||
|
+ __uid = getuid();
|
||
|
for (plast = &p[cnt]; p < plast; ++p) {
|
||
|
+ if (__uid)
|
||
|
+ {
|
||
|
+ if (p->kp_eproc.e_pcred.p_ruid != __uid) continue;
|
||
|
+ }
|
||
|
if (p->kp_proc.p_stat == SZOMB)
|
||
|
continue;
|
||
|
dofiles(p);
|
||
|
--- ./bin/ps/ps.c.orig Tue Oct 20 10:48:40 1998
|
||
|
+++ ./bin/ps/ps.c Tue Oct 20 10:51:26 1998
|
||
|
@@ -112,6 +112,7 @@
|
||
|
dev_t ttydev;
|
||
|
pid_t pid;
|
||
|
uid_t uid;
|
||
|
+ uid_t __uid;
|
||
|
int all, ch, flag, i, fmt, lineno, nentries;
|
||
|
int prtheader, wflag, what, xflg;
|
||
|
char *nlistf, *memf, *swapf, errbuf[_POSIX2_LINE_MAX];
|
||
|
@@ -281,6 +282,8 @@
|
||
|
if (!all && ttydev == NODEV && pid == -1) /* XXX - should be cleaner */
|
||
|
uid = getuid();
|
||
|
|
||
|
+ __uid = getuid();
|
||
|
+
|
||
|
/*
|
||
|
* scan requested variables, noting what structures are needed,
|
||
|
* and adjusting header widths as appropiate.
|
||
|
@@ -330,6 +333,20 @@
|
||
|
for (i = lineno = 0; i < nentries; i++) {
|
||
|
KINFO *ki = &kinfo[i];
|
||
|
|
||
|
+ /*
|
||
|
+ * root gets to see the whole proccess list.
|
||
|
+ */
|
||
|
+ if (__uid)
|
||
|
+ {
|
||
|
+ /*
|
||
|
+ * If the process in question is not our own, we do not
|
||
|
+ * get to see it.
|
||
|
+ */
|
||
|
+ if (kinfo[i].ki_p->kp_eproc.e_pcred.p_ruid != __uid)
|
||
|
+ {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ }
|
||
|
if (xflg == 0 && (KI_EPROC(ki)->e_tdev == NODEV ||
|
||
|
(KI_PROC(ki)->p_flag & P_CONTROLT ) == 0))
|
||
|
continue;
|
||
|
--- ./usr.bin/w/w.c.orig Tue Oct 20 10:52:02 1998
|
||
|
+++ ./usr.bin/w/w.c Tue Oct 20 10:54:46 1998
|
||
|
@@ -131,6 +131,7 @@
|
||
|
int ch, i, nentries, nusers, wcmd;
|
||
|
char *memf, *nlistf, *p, *x;
|
||
|
char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX];
|
||
|
+ uid_t __uid;
|
||
|
|
||
|
/* Are we w(1) or uptime(1)? */
|
||
|
p = __progname;
|
||
|
@@ -332,6 +333,14 @@
|
||
|
ep->utmp.ut_host + UT_HOSTSIZE - x, x);
|
||
|
p = buf;
|
||
|
}
|
||
|
+ __uid = getuid();
|
||
|
+ if (__uid)
|
||
|
+ (void)printf("%-*.*s %-2.2s %-*.*s ",
|
||
|
+ UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
|
||
|
+ strncmp(ep->utmp.ut_line, "tty", 3) ?
|
||
|
+ ep->utmp.ut_line : ep->utmp.ut_line + 3,
|
||
|
+ UT_HOSTSIZE, UT_HOSTSIZE, "<skulking about>");
|
||
|
+ else
|
||
|
(void)printf("%-*.*s %-2.2s %-*.*s ",
|
||
|
UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
|
||
|
strncmp(ep->utmp.ut_line, "tty", 3) ?
|
||
|
@@ -339,7 +348,14 @@
|
||
|
UT_HOSTSIZE, UT_HOSTSIZE, *p ? p : "-");
|
||
|
pr_attime(&ep->utmp.ut_time, &now);
|
||
|
pr_idle(ep->idle);
|
||
|
- pr_args(ep->kp);
|
||
|
+ if (__uid)
|
||
|
+ {
|
||
|
+ printf("<this n' that>");
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ pr_args(ep->kp);
|
||
|
+ }
|
||
|
printf("\n");
|
||
|
}
|
||
|
exit(0);
|
||
|
--- ./usr.bin/who/who.c.orig Tue Aug 19 22:37:21 1997
|
||
|
+++ ./usr.bin/who/who.c Tue Oct 20 10:57:04 1998
|
||
|
@@ -227,6 +227,7 @@
|
||
|
char state = '?';
|
||
|
static time_t now = 0;
|
||
|
time_t idle = 0;
|
||
|
+ uid_t __uid;
|
||
|
|
||
|
if (show_term || show_idle) {
|
||
|
if (now == 0)
|
||
|
@@ -265,8 +266,15 @@
|
||
|
(void)printf(" old ");
|
||
|
}
|
||
|
|
||
|
- if (*up->ut_host)
|
||
|
- printf("\t(%.*s)", UT_HOSTSIZE, up->ut_host);
|
||
|
+ __uid = getuid();
|
||
|
+ if (__uid)
|
||
|
+ {
|
||
|
+ printf("\t<skulking about>");
|
||
|
+ }
|
||
|
+ else if (*up->ut_host)
|
||
|
+ {
|
||
|
+ printf("\t(%.*s)", UT_HOSTSIZE, up->ut_host);
|
||
|
+ }
|
||
|
(void)putchar('\n');
|
||
|
}
|
||
|
<-->
|
||
|
<++> TPE/Core/Patch/ld.so-diff
|
||
|
--- gnu/usr.bin/ld/rtld/rtld.c.old Thu Oct 22 20:44:52 1998
|
||
|
+++ gnu/usr.bin/ld/rtld/rtld.c Sat Oct 24 16:44:00 1998
|
||
|
@@ -39,6 +39,8 @@
|
||
|
#include <sys/resource.h>
|
||
|
#include <sys/errno.h>
|
||
|
#include <sys/mman.h>
|
||
|
+#include <sys/syscall.h>
|
||
|
+#include "/usr/src/sys/sys/kern_tpe.h"
|
||
|
#ifndef MAP_COPY
|
||
|
#define MAP_COPY MAP_PRIVATE
|
||
|
#endif
|
||
|
@@ -150,7 +152,9 @@
|
||
|
static uid_t uid, euid;
|
||
|
static gid_t gid, egid;
|
||
|
static int careful;
|
||
|
+static int tpe_ld_strip;
|
||
|
static int anon_fd = -1;
|
||
|
+static uid_t list[TPE_ACL_SIZE];
|
||
|
|
||
|
struct so_map *link_map_head, *main_map;
|
||
|
struct so_map **link_map_tail = &link_map_head;
|
||
|
@@ -271,7 +275,20 @@
|
||
|
|
||
|
careful = (uid != euid) || (gid != egid);
|
||
|
|
||
|
- if (careful) {
|
||
|
+ if (syscall(SYS_tpe_adm, TPE_LDCHECK_S, -1, list) == -1)
|
||
|
+ {
|
||
|
+ fprintf(stderr, "Unknown internal error\n"); /* should NOT fail */
|
||
|
+ exit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+ if (list[0] && uid)
|
||
|
+ {
|
||
|
+ if (getenv("LD_PRELOAD") || getenv("LD_LIBRARY_PATH"))
|
||
|
+ {
|
||
|
+ fprintf(stderr, "Your environment contains illegal variables which are being stripped out for the execution of this program.\n");
|
||
|
+ }
|
||
|
+ tpe_ld_strip = 1;
|
||
|
+ }
|
||
|
+ if (careful || tpe_ld_strip) {
|
||
|
unsetenv("LD_LIBRARY_PATH");
|
||
|
unsetenv("LD_PRELOAD");
|
||
|
}
|
||
|
<-->
|
||
|
----[ EOF
|