home *** CD-ROM | disk | FTP | other *** search
Text File | 2003-06-11 | 41.2 KB | 1,124 lines |
- ---[ Phrack Magazine Volume 8, Issue 52 January 26, 1998, article 06 of 20
-
-
- -------------------------[ Hardening the Linux Kernel (series 2.0.x)
-
-
- --------[ route|daemon9 <route@infonexus.com>
-
-
-
-
- ----[ Introduction and Impetus
-
-
- Linux. The cutest Unix-like O/S alive today. Everyone knows at least
- *one* person who has at least *one* Linux machine. Linux, whatever your
- opinion of it, is out there, and is being used by more and more people. Many
- of the people using Linux are using it in multi-user environments. All of a
- sudden they find security to be a big issue. This article is for those people.
-
- This article covers a few areas of potential insecurity in the Linux O/S
- and attempts to improve upon them. It contains several security related
- kernel patches for the 2.0.x kernels (each has been tested successfully on the
- 2.0.3x kernels and most should work on older 2.0.x kernels; see each
- subsection for more info).
-
- These are kernel patches. They do nothing for user-land security. If you
- can not set permissions and configure services correctly, you should not be
- running a Unix machine.
-
- These patches are not bugfixes. They are preventative security fixes.
- They are intended to prevent possible problems and breaches of security from
- occurring. In some cases they can remove (or at least severely complicate) the
- threat of many of today's most popular methods of attack.
-
- These patches are not really useful on a single-user machine. They are
- really intended for a multi-user box.
-
- This article is for those of you who want better security out of your Linux
- O/S. If you want to go a bit further, look into the POSIX.1e (POSIX 6) stuff.
- POSIX.1e is a security model that basically separates identity and privilege.
- Effectively, it splits superuser privileges into different `capabilities`.
- Additionally, the Linux POSIX.1e (linux-privs) implementation offers a bitmapped
- securelevel, kernel-based auditing (userland audit hooks are being developed),
- and ACLs. See: http://parc.power.net/morgan/Orange-Linux/linux-privs/index.html
-
- To sum it up, in this article, we explore a few ways to make the multi-user
- Linux machine a bit more secure and resilient to attack.
-
-
- ----[ The Patches
-
-
- procfs patch
- ------------
- Tested on: 2.0.0 +
- Author: route
-
- Why should we allow anyone to be able to view info on any process?
-
- Normally, /bin/ps can show process listing for every process in the
- kernel's process table, regardless of ownership. A non-privileged user can
- see all the running processes on a system. This can include information that
- could be used in some forms of known / guessed PID-based attacks, not to
- mention the obvious lack of privacy. /bin/ps gets this process information by
- reading the /proc filesystem.
-
- The /proc filesystem is a virtual filesystem interface into the O/S which
- provides all kinds of good information including the status of various
- portions of the running kernel and a list of currently running processes. It
- has a filesystem interface, which means it has file-system-like access
- controls. As such, we can change the default access permissions on the inode
- from 555 to 500.
-
- And that's the patch. We just change the permissions on the inode from
- S_IFDIR | S_IRUGO | S_IXUGO to S_IFDIR | S_IRUSR | S_IXUSR.
-
-
- trusted path execution patch
- ----------------------------
- Tested on: 2.0.0 +
- Author: route (2.0.x version, original 1.x patch by merc)
-
- Why should we allow arbitrary programs execution rights?
-
- Consider this scenario: You are the administrator of a multi-user Linux
- machine. All of a sudden there is a new bug in the Pentium(tm) processor!
- As it happens, this bug causes the CPU to lock up entirely, requiring a cold
- reboot. This bug is also exploitable by any user regardless of privilege. All
- it necessitates is for the malevolent user to 1) get the source, 2) compile the
- exploit, and 3) execute the program.
-
- Whelp... 1) has happened. You cannot prevent anyone from getting it. It's
- out there. You could remove permissions from the compiler on your machine or
- remove the binary entirely, but this does not stop the user from compiling
- the exploit elsewhere, and getting the binary on your machine somehow. You
- cannot prevent 2) either. However, if you only allow binaries to be executed
- from a trusted path, you can prevent 3) from happening. A trusted path is
- one that is inside is a root owned directory that is not group or world
- writable. /bin, /usr/bin, /usr/local/bin, are (under normal circumstances)
- considered trusted. Any non-root users home directory is not trusted, nor is
- /tmp. Be warned: This patch is a major annoyance to users who like to execute
- code and scripts from their home directories! It will make you extremely
- un-popular as far as these people are concerned. It will also let you sleep
- easier at night knowing that no unscrupulous persons will be executing
- malicious bits of code on your machine.
-
- Before any call to exec is allowed to run, we open the inode of the
- directory that the executable lives in and check ownership and permissions.
- If the directory is not owned by root, or is writable to group or other, we
- consider that untrusted.
-
-
- securelevel patch
- -----------------
- Tested on: 2.0.26 +
- Author: route
-
- Damnit, if I set the immutable and append only bits, I did it for a reason.
-
- This patch isn't really much of a patch. It simply bumps the securelevel
- up, to 1 from 0. This freezes the immutable and append-only bits on files,
- keeping anyone from changing them (from the normal chattr interface). Before
- turning this on, you should of course make certain key files immutable, and
- logfiles append-only. It is still possible to open the raw disk device,
- however. Your average cut and paste hacker will probably not know how to do
- this.
-
-
- stack execution disabling patch and symlink patch
- -------------------------------
- Tested on: 2.0.30 +
- Author: solar designer
-
- From the documentation accompanying SD's patch:
-
- This patch is intended to add protection against two classes of security
- holes: buffer overflows and symlinks in /tmp.
-
- Most buffer overflow exploits are based on overwriting a function's return
- address on the stack to point to some arbitrary code, which is also put
- onto the stack. If the stack area is non-executable, buffer overflow
- vulnerabilities become harder to exploit.
-
- Another way to exploit a buffer overflow is to point the return address to
- a function in libc, usually system(). This patch also changes the default
- address that shared libraries are mmap()ed at to make it always contain a
- zero byte. This makes it impossible to specify any more data (parameters
- to the function, or more copies of the return address when filling with a
- pattern) in an exploit that has to do with ASCIIZ strings (this is the
- case for most overflow vulnerabilities).
-
- However, note that this patch is by no means a complete solution, it just
- adds an extra layer of security. Some buffer overflow vulnerabilities will
- still remain exploitable a more complicated way. The reason for using such
- a patch is to protect against some of the buffer overflow vulnerabilities
- that are yet unknown.
-
- In this version of my patch I also added a symlink security fix, originally
- by Andrew Tridgell. I changed it to prevent from using hard links too, by
- simply not allowing non-root users to create hard links to files they don't
- own, in +t directories. This seems to be the desired behavior anyway, since
- otherwise users couldn't remove such links they just created. I also added
- exploit attempt logging, this code is shared with the non-executable stack
- stuff, and was the reason to make it a single patch instead of two separate
- ones. You can enable them separately anyway.
-
-
- GID split privilege patch
- -------------------------------
- Tested on: 2.0.30 +
- Author: Original version DaveG, updated for 2.0.33 by route
-
- From the documentation accompanying Dave's original patch:
- This is a simple kernel patch that allows you to perform certain
- privileged operations with out requiring root access. With this patch
- three groups become privileged groups allowed to do different operations
- within the kernel.
-
- GID 16 : a program running with group 16 privileges can bind to a
- < 1024. This allows programs like: rlogin, rcp, rsh, and ssh
- to run setgid 16 instead of setuid 0(root). This also allows
- servers that need to run as root to bind to a privileged port
- like named, to also run setgid 16.
-
- GID 17 : any program running under GID 17 privileges will be able to
- create a raw socket. Programs like ping and traceroute can now
- be made to run setgid 17 instead of setuid 0(root).
-
- GID 18 : This group is for SOCK_PACKET. This isn't useful for most people,
- so if you don't know what it is, don't worry about it.
-
- Limitations
- -----------
- Since this is a simple patch, it is VERY limited. First of all, there
- is no support for supplementary groups. This means that you can't stack
- these privileges. If you need GID 16 and 17, there isn't much you can do
- about it.
-
-
-
- ----[ Installation
-
-
- This patchfile has been tested and verified to work against the latest
- stable release of the linux kernel (as of this writing, 2.0.33). It should
- work against other 2.0.x releases as well with little or no modification. THIS
- IS NOT A GUARANTEE! Please do not send me your failed patch logs from older
- kernels. Take this as a perfect opportunity to upgrade your kernel to the
- latest release. Note that several of these patches are for X86-Linux only.
- Sorry.
-
- 1. Create the symlink:
-
- `cd /usr/src`
- `ln -s linux-KERNEL_VERSION linux-stock`
-
- 2. Apply the kernel patch:
-
- `patch < slinux.patch >& patch.err`
-
- 2a. Examine the error file for any failed hunks. Figure where you went wrong
- in life:
-
- `grep fail patch.err`
-
- 3. Configure your kernel:
-
- `make config` OR `make menu-config` OR `make xconfig`
-
- 4. You will need to enable prompting for experimental code in your kernel and
- turn on the patches individually.
-
- 5. To configure the split GID privilege patch, add the follow to your
- /etc/group file:
-
- `cat >> /etc/group`
- priv_port::16:user1, user2, user3
- raw_sock::17:user1, user2
- sock_pak::18:user2, user3
- ^D
-
- Where `userx` are the usernames of the users you wish to give these
- permissions to. Next, fix the corresponding group and permissions on the
- binaries you wish to strip root privileges from:
-
- `chgrp raw_sock /bin/ping`
- `chmod 2755 /bin/ping`
-
-
-
- ----[ The patchfile
-
-
- This patchfile should be extracted with the Phrack Magazine Extraction
- Utility included in this (and every) issue.
-
- <++> slinux.patch
- diff -ru linux-stock/Documentation/Configure.help linux-patched/Documentation/Configure.help
- --- linux-stock/Documentation/Configure.help Fri Sep 5 20:43:58 1997
- +++ linux-patched/Documentation/Configure.help Mon Nov 10 22:02:36 1997
- @@ -720,6 +720,77 @@
- later load the module when you install the JDK or find an interesting
- Java program that you can't live without.
-
- +Non-executable user stack area (EXPERIMENTAL)
- +CONFIG_STACKEXEC
- + Most buffer overflow exploits are based on overwriting a function's
- + return address on the stack to point to some arbitrary code, which is
- + also put onto the stack. If the stack area is non-executable, buffer
- + overflow vulnerabilities become harder to exploit. However, a few
- + programs depend on the stack being executable, and might stop working
- + unless you also enable GCC trampolines autodetection below, or enable
- + the stack area execution permission for every such program separately
- + using chstk.c. If you don't know what all this is about, or don't care
- + about security that much, say N.
- +
- +Autodetect GCC trampolines
- +CONFIG_STACKEXEC_AUTOENABLE
- + GCC generates trampolines on the stack to correctly pass control to
- + nested functions when calling from outside. This requires the stack
- + being executable. When this option is enabled, programs containing
- + trampolines will automatically get their stack area executable when
- + a trampoline is found. However, in some cases this autodetection can
- + be fooled in a buffer overflow exploit, so it is more secure to
- + disable this option and use chstk.c to enable the stack area execution
- + permission for every such program separately. If you're too lazy,
- + answer Y.
- +
- +Log buffer overflow exploit attempts
- +CONFIG_STACKEXEC_LOG
- + This option enables logging of buffer overflow exploit attempts. No
- + more than one attempt per minute is logged, so this is safe. Say Y.
- +
- +Process table viewing restriction (EXPERIMENTAL)
- +CONFIG_PROC_RESTRICT
- + This option enables process table viewing restriction. Users will only
- + be able to get status of processes they own, with the exception the
- + root user, who can get an entire process table listing. This patch
- + should not cause any problems with other programs but it is not fully
- + tested under every possible contingency. You must enable the /proc
- + filesystem for this option to be of any use. If you run a multi-user
- + system and are reasonably concerned with privacy and/or security, say Y.
- +
- +Trusted path execution (EXPERIMENTAL)
- +CONFIG_TPE
- + This option enables trusted path execution. Binaries are considered
- + `trusted` if they live in a root owned directory that is not group or
- + world writable. If an attempt is made to execute a program from a non
- + trusted directory, it will simply not be allowed to run. This is
- + quite useful on a multi-user system where security is an issue. Users
- + will not be able to compile and execute arbitrary programs (read: evil)
- + from their home directories, as these directories are not trusted.
- + This option is useless on a single user machine.
- +
- +Trusted path execution (EXPERIMENTAL)
- +CONFIG_TPE_LOG
- + This option enables logging of execution attempts from non-trusted
- + paths.
- +
- +Secure mode (EXPERIMENTAL)
- +CONFIG_SECURE_ON
- + This bumps up the securelevel from 0 to 1. When the securelevel is `on`,
- + immutable and append-only bits cannot be set or cleared. If you are not
- + concerned with security, you can say `N`.
- +
- +Split Network Groups (EXPERIMENTAL)
- +CONFIG_SPLIT_GID
- + This is a simple kernel patch that allows you to perform certain
- + privileged operations with out requiring root access. With this patch
- + three groups become privileged groups allowed to do different operations
- + within the kernel.
- + GID 16 allows programs to bind to privledged ports.
- + GID 17 allows programs to open raw sockets.
- + GID 18 allows programs to open sock packets.
- +
- Processor type
- CONFIG_M386
- This is the processor type of your CPU. It is used for optimizing
- @@ -2951,6 +3020,27 @@
- netatalk, new mars-nwe and other file servers. At the time of
- writing none of these are available. So it's safest to say N here
- unless you really know that you need this feature.
- +
- +Symlink security fix (EXPERIMENTAL)
- +CONFIG_SYMLINK_FIX
- + A very common class of security hole on UNIX-like systems involves
- + a malicious user creating a symbolic link in /tmp pointing at
- + another user's file. When the victim then writes to that file they
- + inadvertently write to the wrong file. Enabling this option fixes
- + this class of hole by preventing a process from following a link
- + which is in a +t directory unless they own the link. However, this
- + fix does not affect links owned by root, since these could only be
- + created by someone having root access already. To prevent someone
- + from using a hard link instead, this fix does not allow non-root
- + users to create hard links in a +t directory to files they don't
- + own. Note that this fix might break things. Only say Y if security
- + is more important.
- +
- +Log symlink exploit attempts
- +CONFIG_SYMLINK_LOG
- + This option enables logging of symlink (and hard link) exploit
- + attempts. No more than one attempt per minute is logged, so this is
- + safe. Say Y.
-
- Minix fs support
- CONFIG_MINIX_FS
- diff -ru linux-stock/arch/i386/config.in linux-patched/arch/i386/config.in
- --- linux-stock/arch/i386/config.in Sun May 12 21:17:23 1996
- +++ linux-patched/arch/i386/config.in Sun Nov 9 12:38:27 1997
- @@ -35,6 +35,15 @@
- tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
- + bool 'Non-executable user stack area (EXPERIMENTAL)' CONFIG_STACKEXEC
- + if [ "$CONFIG_STACKEXEC" = "y" ]; then
- + bool ' Autodetect GCC trampolines' CONFIG_STACKEXEC_AUTOENABLE
- + bool ' Log buffer overflow exploit attempts' CONFIG_STACKEXEC_LOG
- + fi
- + bool ' Restrict process table viewing (EXPERIMENTAL)' CONFIG_PROC_RESTRICT
- + bool ' Trusted path execution (EXPERIMENTAL)' CONFIG_TPE
- + bool ' Log untrusted path execution attempts (EXPERIMENTAL)' CONFIG_TPE_LOG
- + bool ' Split Network GIDs (EXPERIMENTAL)' CONFIG_SPLIT_GID
- fi
- bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
-
- diff -ru linux-stock/arch/i386/defconfig linux-patched/arch/i386/defconfig
- --- linux-stock/arch/i386/defconfig Mon Sep 22 13:44:01 1997
- +++ linux-patched/arch/i386/defconfig Sun Nov 9 12:38:23 1997
- @@ -24,6 +24,10 @@
- CONFIG_SYSVIPC=y
- CONFIG_BINFMT_AOUT=y
- CONFIG_BINFMT_ELF=y
- +# CONFIG_STACKEXEC is not set
- +CONFIG_STACKEXEC_AUTOENABLE=y
- +CONFIG_STACKEXEC_LOG=y
- +CONFIG_SPLIT_GID=y
- CONFIG_KERNEL_ELF=y
- # CONFIG_M386 is not set
- # CONFIG_M486 is not set
- @@ -134,6 +138,8 @@
- # Filesystems
- #
- # CONFIG_QUOTA is not set
- +# CONFIG_SYMLINK_FIX is not set
- +CONFIG_SYMLINK_LOG=y
- CONFIG_MINIX_FS=y
- # CONFIG_EXT_FS is not set
- CONFIG_EXT2_FS=y
- @@ -143,6 +149,9 @@
- # CONFIG_VFAT_FS is not set
- # CONFIG_UMSDOS_FS is not set
- CONFIG_PROC_FS=y
- +CONFIG_PROC_RESTRICT=y
- +CONFIG_TPE=y
- +CONFIG_TPE_LOG=y
- CONFIG_NFS_FS=y
- # CONFIG_ROOT_NFS is not set
- # CONFIG_SMB_FS is not set
- diff -ru linux-stock/arch/i386/kernel/head.S linux-patched/arch/i386/kernel/head.S
- --- linux-stock/arch/i386/kernel/head.S Tue Aug 5 09:19:53 1997
- +++ linux-patched/arch/i386/kernel/head.S Sun Nov 9 00:55:50 1997
- @@ -400,10 +400,17 @@
- .quad 0x0000000000000000 /* not used */
- .quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */
- .quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */
- +#ifdef CONFIG_STACKEXEC
- + .quad 0x00cafa000000ffff /* 0x23 user 2.75GB code at 0 */
- + .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0 */
- + .quad 0x00cbda000000ffff /* 0x32 user 3GB code at 0, DPL=2 */
- + .quad 0x00cbd2000000ffff /* 0x3a user 3GB stack at 0, DPL=2 */
- +#else
- .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */
- .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */
- .quad 0x0000000000000000 /* not used */
- .quad 0x0000000000000000 /* not used */
- +#endif
- .fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */
- #ifdef CONFIG_APM
- .quad 0x00c09a0000000000 /* APM CS code */
- diff -ru linux-stock/arch/i386/kernel/ptrace.c linux-patched/arch/i386/kernel/ptrace.c
- --- linux-stock/arch/i386/kernel/ptrace.c Mon Aug 4 12:12:22 1997
- +++ linux-patched/arch/i386/kernel/ptrace.c Sun Nov 9 00:55:50 1997
- @@ -413,7 +413,7 @@
- addr == FS || addr == GS ||
- addr == CS || addr == SS) {
- data &= 0xffff;
- - if (data && (data & 3) != 3)
- + if (data && (data & 3) < 2)
- return -EIO;
- }
- if (addr == EFL) { /* flags. */
- @@ -423,6 +423,10 @@
- /* Do not allow the user to set the debug register for kernel
- address space */
- if(addr < 17){
- + if (addr == EIP && (data & 0xF0000000) == 0xB0000000)
- + if (put_stack_long(child, CS*sizeof(long)-MAGICNUMBER, USER_HUGE_CS) ||
- + put_stack_long(child, SS*sizeof(long)-MAGICNUMBER, USER_HUGE_SS))
- + return -EIO;
- if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
- return -EIO;
- return 0;
- diff -ru linux-stock/arch/i386/kernel/signal.c linux-patched/arch/i386/kernel/signal.c
- --- linux-stock/arch/i386/kernel/signal.c Mon Aug 4 12:12:51 1997
- +++ linux-patched/arch/i386/kernel/signal.c Sun Nov 9 00:55:50 1997
- @@ -83,10 +83,10 @@
- #define COPY_SEG(x) \
- if ( (context.x & 0xfffc) /* not a NULL selectors */ \
- && (context.x & 0x4) != 0x4 /* not a LDT selector */ \
- - && (context.x & 3) != 3 /* not a RPL3 GDT selector */ \
- + && (context.x & 3) < 2 /* not a RPL3 or RPL2 GDT selector */ \
- ) goto badframe; COPY(x);
- #define COPY_SEG_STRICT(x) \
- -if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
- +if (!(context.x & 0xfffc) || (context.x & 3) < 2) goto badframe; COPY(x);
- struct sigcontext_struct context;
- struct pt_regs * regs;
-
- @@ -167,16 +167,20 @@
- unsigned long * frame;
-
- frame = (unsigned long *) regs->esp;
- - if (regs->ss != USER_DS && sa->sa_restorer)
- + if (regs->ss != USER_DS && regs->ss != USER_HUGE_SS && sa->sa_restorer)
- frame = (unsigned long *) sa->sa_restorer;
- frame -= 64;
- if (verify_area(VERIFY_WRITE,frame,64*4))
- do_exit(SIGSEGV);
-
- /* set up the "normal" stack seen by the signal handler (iBCS2) */
- +#ifdef CONFIG_STACKEXEC
- + put_user((unsigned long)MAGIC_SIGRETURN, frame);
- +#else
- #define __CODE ((unsigned long)(frame+24))
- #define CODE(x) ((unsigned long *) ((x)+__CODE))
- put_user(__CODE,frame);
- +#endif
- if (current->exec_domain && current->exec_domain->signal_invmap)
- put_user(current->exec_domain->signal_invmap[signr], frame+1);
- else
- @@ -204,19 +208,17 @@
- /* non-iBCS2 extensions.. */
- put_user(oldmask, frame+22);
- put_user(current->tss.cr2, frame+23);
- +#ifndef CONFIG_STACKEXEC
- /* set up the return code... */
- put_user(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */
- put_user(0x80cd0000, CODE(4)); /* int $0x80 */
- put_user(__NR_sigreturn, CODE(2));
- #undef __CODE
- #undef CODE
- +#endif
-
- /* Set up registers for signal handler */
- - regs->esp = (unsigned long) frame;
- - regs->eip = (unsigned long) sa->sa_handler;
- - regs->cs = USER_CS; regs->ss = USER_DS;
- - regs->ds = USER_DS; regs->es = USER_DS;
- - regs->gs = USER_DS; regs->fs = USER_DS;
- + start_thread(regs, (unsigned long)sa->sa_handler, (unsigned long)frame);
- regs->eflags &= ~TF_MASK;
- }
-
- diff -ru linux-stock/arch/i386/kernel/traps.c linux-patched/arch/i386/kernel/traps.c
- --- linux-stock/arch/i386/kernel/traps.c Mon Aug 11 13:37:24 1997
- +++ linux-patched/arch/i386/kernel/traps.c Sun Nov 9 00:55:50 1997
- @@ -117,7 +117,7 @@
-
- esp = (unsigned long) ®s->esp;
- ss = KERNEL_DS;
- - if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3)
- + if ((regs->eflags & VM_MASK) || (3 & regs->cs) >= 2)
- return;
- if (regs->cs & 3) {
- esp = regs->esp;
- @@ -193,11 +193,82 @@
-
- asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
- {
- +#ifdef CONFIG_STACKEXEC
- + unsigned long retaddr;
- +#endif
- +
- if (regs->eflags & VM_MASK) {
- handle_vm86_fault((struct vm86_regs *) regs, error_code);
- return;
- }
- +
- +#ifdef CONFIG_STACKEXEC
- +/* Check if it was return from a signal handler */
- + if (regs->cs == USER_CS || regs->cs == USER_HUGE_CS)
- + if (get_seg_byte(USER_DS, (char *)regs->eip) == 0xC3)
- + if (!verify_area(VERIFY_READ, (void *)regs->esp, 4))
- + if ((retaddr = get_seg_long(USER_DS, (char *)regs->esp)) ==
- + MAGIC_SIGRETURN) {
- +/*
- + * Call sys_sigreturn() to restore the context. It would definitely be better
- + * to convert sys_sigreturn() into an inline function accepting a pointer to
- + * pt_regs, making this faster...
- + */
- + regs->esp += 8;
- + __asm__("movl %3,%%esi;"
- + "subl %1,%%esp;"
- + "movl %2,%%ecx;"
- + "movl %%esp,%%edi;"
- + "cld; rep; movsl;"
- + "call sys_sigreturn;"
- + "leal %3,%%edi;"
- + "addl %1,%%edi;"
- + "movl %%esp,%%esi;"
- + "movl (%%edi),%%edi;"
- + "movl %2,%%ecx;"
- + "cld; rep; movsl;"
- + "movl %%esi,%%esp"
- + :
- +/* %eax is returned separately */
- + "=a" (regs->eax)
- + :
- + "i" (sizeof(*regs)),
- + "i" (sizeof(*regs) >> 2),
- + "m" (regs)
- + :
- + "cx", "dx", "si", "di", "cc", "memory");
- + return;
- + }
- +
- +#ifdef CONFIG_STACKEXEC_LOG
- +/*
- + * Check if we're returning to the stack area, which is only likely to happen
- + * when attempting to exploit a buffer overflow.
- + */
- + else if (regs->cs == USER_CS &&
- + (retaddr & 0xF0000000) == 0xB0000000)
- + security_alert("buffer overflow");
- +#endif
- +#endif
- +
- die_if_kernel("general protection",regs,error_code);
- +
- +#if defined(CONFIG_STACKEXEC) && defined(CONFIG_STACKEXEC_AUTOENABLE)
- +/*
- + * Switch to the original huge code segment (and allow code execution on the
- + * stack for this entire process), if the faulty instruction is a call %reg,
- + * except for call %esp.
- + */
- + if (regs->cs == USER_CS)
- + if (get_seg_byte(USER_DS, (char *)regs->eip) == 0xFF &&
- + (get_seg_byte(USER_DS, (char *)(regs->eip + 1)) & 0xD8) == 0xD0 &&
- + get_seg_byte(USER_DS, (char *)(regs->eip + 1)) != 0xD4) {
- + current->flags |= PF_STACKEXEC;
- + regs->cs = USER_HUGE_CS; regs->ss = USER_HUGE_SS;
- + return;
- + }
- +#endif
- +
- current->tss.error_code = error_code;
- current->tss.trap_no = 13;
- force_sig(SIGSEGV, current);
- diff -ru linux-stock/arch/i386/mm/fault.c linux-patched/arch/i386/mm/fault.c
- --- linux-stock/arch/i386/mm/fault.c Sat Aug 16 22:21:20 1997
- +++ linux-patched/arch/i386/mm/fault.c Sun Nov 9 00:55:50 1997
- @@ -44,6 +44,7 @@
- unsigned long page;
- int write;
-
- + if ((regs->cs & 3) >= 2) error_code |= 4;
- /* get the address */
- __asm__("movl %%cr2,%0":"=r" (address));
- down(&mm->mmap_sem);
- diff -ru linux-stock/fs/binfmt_aout.c linux-patched/fs/binfmt_aout.c
- --- linux-stock/fs/binfmt_aout.c Wed Oct 15 14:56:43 1997
- +++ linux-patched/fs/binfmt_aout.c Tue Nov 11 00:38:48 1997
- @@ -315,6 +315,7 @@
- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
- current->flags &= ~PF_FORKNOEXEC;
- + if (N_FLAGS(ex) & F_STACKEXEC) current->flags |= PF_STACKEXEC;
- if (N_MAGIC(ex) == OMAGIC) {
- #ifdef __alpha__
- do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
- diff -ru linux-stock/fs/binfmt_elf.c linux-patched/fs/binfmt_elf.c
- --- linux-stock/fs/binfmt_elf.c Wed Oct 15 14:56:43 1997
- +++ linux-patched/fs/binfmt_elf.c Tue Nov 11 01:02:05 1997
- @@ -55,7 +55,10 @@
- #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
- #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
-
- -static struct linux_binfmt elf_format = {
- +#ifndef CONFIG_STACKEXEC
- +static
- +#endif
- +struct linux_binfmt elf_format = {
- #ifndef MODULE
- NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
- #else
- @@ -662,6 +665,7 @@
- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
- current->flags &= ~PF_FORKNOEXEC;
- + if (elf_ex.e_flags & EF_STACKEXEC) current->flags |= PF_STACKEXEC;
- bprm->p = (unsigned long)
- create_elf_tables((char *)bprm->p,
- bprm->argc,
- diff -ru linux-stock/fs/exec.c linux-patched/fs/exec.c
- --- linux-stock/fs/exec.c Wed Oct 15 14:56:43 1997
- +++ linux-patched/fs/exec.c Tue Nov 11 12:59:51 1997
- @@ -475,6 +475,8 @@
- }
- current->comm[i] = '\0';
-
- + current->flags &= ~PF_STACKEXEC;
- +
- /* Release all of the old mmap stuff. */
- if (exec_mmap())
- return -ENOMEM;
- @@ -650,12 +652,30 @@
- int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
- {
- struct linux_binprm bprm;
- + struct inode *dir;
- + const char *basename;
- + int namelen;
- int retval;
- int i;
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- bprm.page[i] = 0;
- +
- +#ifdef CONFIG_TPE
- + /* Check to make sure the path is trusted. If the directory is root
- + * owned and not group/world writable, it's trusted. Otherwise,
- + * return -EACCES and optionally log it
- + */
- + dir_namei(filename, &namelen, &basename, NULL, &dir);
- + if (dir->i_mode & (S_IWGRP | S_IWOTH) || dir->i_uid)
- + {
- +#ifdef CONFIG_TPE_LOG
- + security_alert("Trusted path execution violation");
- +#endif /* CONFIG_TPE_LOG */
- + return -EACCES;
- + }
- +#endif /* CONFIG_TPE */
- retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
- if (retval)
- return retval;
- diff -ru linux-stock/fs/namei.c linux-patched/fs/namei.c
- --- linux-stock/fs/namei.c Sat Aug 16 16:23:19 1997
- +++ linux-patched/fs/namei.c Tue Nov 11 00:44:51 1997
- @@ -19,6 +19,7 @@
- #include <linux/fcntl.h>
- #include <linux/stat.h>
- #include <linux/mm.h>
- +#include <linux/config.h>
-
- #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
-
- @@ -207,6 +208,23 @@
- *res_inode = inode;
- return 0;
- }
- +#ifdef CONFIG_SYMLINK_FIX
- +/*
- + * Don't follow links that we don't own in +t directories, unless the link
- + * is owned by root.
- + */
- + if (S_ISLNK(inode->i_mode) && (dir->i_mode & S_ISVTX) &&
- + inode->i_uid &&
- + current->fsuid != inode->i_uid) {
- +#ifdef CONFIG_SYMLINK_LOG
- + security_alert("symlink");
- +#endif
- + iput(dir);
- + iput(inode);
- + *res_inode = NULL;
- + return -EPERM;
- + }
- +#endif
- return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
- }
-
- @@ -216,8 +234,13 @@
- * dir_namei() returns the inode of the directory of the
- * specified name, and the name within that directory.
- */
- +#ifdef CONFIG_TPE
- +int dir_namei(const char *pathname, int *namelen, const char **name,
- + struct inode * base, struct inode **res_inode)
- +#else
- static int dir_namei(const char *pathname, int *namelen, const char **name,
- struct inode * base, struct inode **res_inode)
- +#endif /* CONFIG_TPE */
- {
- char c;
- const char * thisname;
- @@ -787,6 +810,22 @@
- iput(dir);
- return -EPERM;
- }
- +#ifdef CONFIG_SYMLINK_FIX
- +/*
- + * Don't allow non-root users to create hard links to files they don't own
- + * in a +t directory.
- + */
- + if ((dir->i_mode & S_ISVTX) &&
- + current->fsuid != oldinode->i_uid &&
- + !fsuser()) {
- +#ifdef CONFIG_SYMLINK_LOG
- + security_alert("hard link");
- +#endif
- + iput(oldinode);
- + iput(dir);
- + return -EPERM;
- + }
- +#endif
- if (IS_RDONLY(dir)) {
- iput(oldinode);
- iput(dir);
- diff -ru linux-stock/fs/proc/base.c linux-patched/fs/proc/base.c
- --- linux-stock/fs/proc/base.c Wed Feb 21 01:26:09 1996
- +++ linux-patched/fs/proc/base.c Sun Nov 9 10:53:19 1997
- @@ -74,7 +74,11 @@
- */
- struct proc_dir_entry proc_pid = {
- PROC_PID_INO, 5, "<pid>",
- - S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- +#ifdef CONFIG_PROC_RESTRICT
- + S_IFDIR | S_IRUSR | S_IXUSR, 2, 0, 0,
- +#else
- + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- +#endif /* CONFIG_PROC_RESTRICT */
- 0, &proc_base_inode_operations,
- NULL, proc_pid_fill_inode,
- NULL, &proc_root, NULL
- diff -ru linux-stock/fs/proc/inode.c linux-patched/fs/proc/inode.c
- --- linux-stock/fs/proc/inode.c Sat Nov 30 02:21:21 1996
- +++ linux-patched/fs/proc/inode.c Sun Nov 9 10:58:06 1997
- @@ -153,7 +153,11 @@
- if (!p || i >= NR_TASKS)
- return;
- if (ino == PROC_ROOT_INO) {
- - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
- +#ifdef CONFIG_PROC_RESTRICT
- + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
- +#else
- + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
- +#endif /* CONFIG_PROC_RESTRICT */
- inode->i_nlink = 2;
- for (i = 1 ; i < NR_TASKS ; i++)
- if (task[i])
- @@ -171,7 +175,11 @@
- inode->i_nlink = 2;
- break;
- case PROC_SCSI:
- +#ifdef CONFIG_PROC_RESTRICT
- + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
- +#else
- inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
- +#endif /* CONFIG_PROC_RESTRICT */
- inode->i_nlink = 2;
- inode->i_op = &proc_scsi_inode_operations;
- break;
- @@ -181,7 +189,11 @@
- inode->i_size = (MAP_NR(high_memory) << PAGE_SHIFT) + PAGE_SIZE;
- break;
- case PROC_PROFILE:
- - inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
- +#ifdef CONFIG_PROC_RESTRICT
- + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
- +#else
- + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
- +#endif /* CONFIG_PROC_RESTRICT */
- inode->i_op = &proc_profile_inode_operations;
- inode->i_size = (1+prof_len) * sizeof(unsigned long);
- break;
- @@ -203,7 +215,11 @@
- return;
- case PROC_PID_MEM:
- inode->i_op = &proc_mem_inode_operations;
- - inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
- +#ifdef CONFIG_PROC_RESTRICT
- + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
- +#else
- + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
- +#endif /* CONFIG_PROC_RESTRICT */
- return;
- case PROC_PID_CWD:
- case PROC_PID_ROOT:
- diff -ru linux-stock/include/asm-i386/processor.h linux-patched/include/asm-i386/processor.h
- --- linux-stock/include/asm-i386/processor.h Tue Mar 11 13:52:29 1997
- +++ linux-patched/include/asm-i386/processor.h Tue Nov 11 00:47:04 1997
- @@ -9,6 +9,8 @@
-
- #include <asm/vm86.h>
- #include <asm/math_emu.h>
- +#include <linux/binfmts.h>
- +#include <linux/config.h>
-
- /*
- * System setup and hardware bug flags..
- @@ -41,6 +43,15 @@
- */
- #define TASK_SIZE (0xC0000000UL)
-
- +#if defined(CONFIG_STACKEXEC) && defined(CONFIG_BINFMT_ELF)
- +extern struct linux_binfmt elf_format;
- +#define MMAP_ADDR ( \
- + current->binfmt == &elf_format && \
- + !(current->flags & PF_STACKEXEC) \
- + ? 0x00110000UL \
- + : TASK_SIZE / 3 )
- +#endif
- +
- /*
- * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
- */
- @@ -134,14 +145,6 @@
- #define alloc_kernel_stack() __get_free_page(GFP_KERNEL)
- #define free_kernel_stack(page) free_page((page))
-
- -static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
- -{
- - regs->cs = USER_CS;
- - regs->ds = regs->es = regs->ss = regs->fs = regs->gs = USER_DS;
- - regs->eip = eip;
- - regs->esp = esp;
- -}
- -
- /*
- * Return saved PC of a blocked thread.
- */
- @@ -151,3 +154,25 @@
- }
-
- #endif /* __ASM_I386_PROCESSOR_H */
- +
- +#if defined(current) && !defined(__START_THREAD)
- +#define __START_THREAD
- +
- +static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
- +{
- +#ifdef CONFIG_STACKEXEC
- + if (current->flags & PF_STACKEXEC) {
- + regs->cs = USER_HUGE_CS; regs->ss = USER_HUGE_SS;
- + } else {
- + regs->cs = USER_CS; regs->ss = USER_DS;
- + }
- + regs->ds = regs->es = regs->fs = regs->gs = USER_DS;
- +#else
- + regs->cs = USER_CS;
- + regs->ds = regs->es = regs->fs = regs->gs = regs->ss = USER_DS;
- +#endif
- + regs->eip = eip;
- + regs->esp = esp;
- +}
- +
- +#endif /* __START_THREAD */
- diff -ru linux-stock/include/asm-i386/segment.h linux-patched/include/asm-i386/segment.h
- --- linux-stock/include/asm-i386/segment.h Tue Apr 9 00:35:29 1996
- +++ linux-patched/include/asm-i386/segment.h Tue Nov 11 00:47:13 1997
- @@ -1,11 +1,27 @@
- #ifndef _ASM_SEGMENT_H
- #define _ASM_SEGMENT_H
-
- +#include <linux/config.h>
- +
- #define KERNEL_CS 0x10
- #define KERNEL_DS 0x18
-
- #define USER_CS 0x23
- #define USER_DS 0x2B
- +
- +#ifdef CONFIG_STACKEXEC
- +#define USER_HUGE_CS 0x32
- +#define USER_HUGE_SS 0x3A
- +#else
- +#define USER_HUGE_CS 0x23
- +#define USER_HUGE_SS 0x2B
- +#endif
- +
- +/*
- + * Magic address to return to the kernel from signal handlers, any address
- + * beyond user code segment limit will do.
- + */
- +#define MAGIC_SIGRETURN 0xC1428571
-
- #ifndef __ASSEMBLY__
-
- diff -ru linux-stock/include/linux/a.out.h linux-patched/include/linux/a.out.h
- --- linux-stock/include/linux/a.out.h Sat Aug 17 11:19:28 1996
- +++ linux-patched/include/linux/a.out.h Tue Nov 11 00:47:21 1997
- @@ -37,6 +37,9 @@
- M_MIPS2 = 152, /* MIPS R6000/R4000 binary */
- };
-
- +/* Constants for the N_FLAGS field */
- +#define F_STACKEXEC 1 /* Executable stack area forced */
- +
- #if !defined (N_MAGIC)
- #define N_MAGIC(exec) ((exec).a_info & 0xffff)
- #endif
- diff -ru linux-stock/include/linux/elf.h linux-patched/include/linux/elf.h
- --- linux-stock/include/linux/elf.h Sat Aug 10 00:03:15 1996
- +++ linux-patched/include/linux/elf.h Tue Nov 11 00:47:39 1997
- @@ -57,6 +57,9 @@
- */
- #define EM_ALPHA 0x9026
-
- +/* Constants for the e_flags field */
- +#define EF_STACKEXEC 1 /* Executable stack area forced */
- +
-
- /* This is the info that is needed to parse the dynamic section of the file */
- #define DT_NULL 0
- diff -ru linux-stock/include/linux/kernel.h linux-patched/include/linux/kernel.h
- --- linux-stock/include/linux/kernel.h Thu Aug 14 10:05:47 1997
- +++ linux-patched/include/linux/kernel.h Tue Nov 11 00:47:44 1997
- @@ -78,6 +78,27 @@
- (((addr) >> 16) & 0xff), \
- (((addr) >> 24) & 0xff)
-
- +#define security_alert(msg) { \
- + static unsigned long warning_time = 0, no_flood_yet = 0; \
- +\
- +/* Make sure at least one minute passed since the last warning logged */ \
- + if (!warning_time || jiffies - warning_time > 60 * HZ) { \
- + warning_time = jiffies; no_flood_yet = 1; \
- + printk( \
- + KERN_ALERT \
- + "Possible " msg " exploit attempt:\n" \
- + KERN_ALERT \
- + "Process %s (pid %d, uid %d, euid %d).\n", \
- + current->comm, current->pid, \
- + current->uid, current->euid); \
- + } else if (no_flood_yet) { \
- + warning_time = jiffies; no_flood_yet = 0; \
- + printk( \
- + KERN_ALERT \
- + "More possible " msg " exploit attempts follow.\n"); \
- + } \
- +}
- +
- #endif /* __KERNEL__ */
-
- #define SI_LOAD_SHIFT 16
- diff -ru linux-stock/include/linux/sched.h linux-patched/include/linux/sched.h
- --- linux-stock/include/linux/sched.h Wed Oct 15 15:22:05 1997
- +++ linux-patched/include/linux/sched.h Tue Nov 11 00:47:48 1997
- @@ -269,6 +269,8 @@
- #define PF_USEDFPU 0x00100000 /* Process used the FPU this quantum (SMP only) */
- #define PF_DTRACE 0x00200000 /* delayed trace (used on m68k) */
-
- +#define PF_STACKEXEC 0x01000000 /* Executable stack area forced */
- +
- /*
- * Limit the stack by to some sane default: root can always
- * increase this limit if needed.. 8MB seems reasonable.
- @@ -490,6 +492,9 @@
-
- #define for_each_task(p) \
- for (p = &init_task ; (p = p->next_task) != &init_task ; )
- +
- +/* x86 start_thread() */
- +#include <asm/processor.h>
-
- #endif /* __KERNEL__ */
-
- diff -ru linux-stock/kernel/sched.c linux-patched/kernel/sched.c
- --- linux-stock/kernel/sched.c Fri Oct 17 13:17:43 1997
- +++ linux-patched/kernel/sched.c Sun Nov 9 01:11:01 1997
- @@ -44,7 +44,11 @@
- * kernel variables
- */
-
- +#ifdef CONFIG_SECURE_ON
- +int securelevel = 1; /* system security level */
- +#else
- int securelevel = 0; /* system security level */
- +#endif
-
- long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */
- volatile struct timeval xtime; /* The current time */
- diff -ru linux-stock/mm/mmap.c linux-patched/mm/mmap.c
- --- linux-stock/mm/mmap.c Fri Nov 22 06:25:17 1996
- +++ linux-patched/mm/mmap.c Tue Nov 11 00:48:26 1997
- @@ -308,7 +308,11 @@
- if (len > TASK_SIZE)
- return 0;
- if (!addr)
- +#ifdef MMAP_ADDR
- + addr = MMAP_ADDR;
- +#else
- addr = TASK_SIZE / 3;
- +#endif
- addr = PAGE_ALIGN(addr);
-
- for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
-
-
- diff -ru linux-stock/net/ipv4/af_inet.c linux-patched/net/ipv4/af_inet.c
- --- linux/net/ipv4/af_inet.c Fri Aug 15 12:23:23 1997
- +++ linux-stock/net/ipv4/af_inet.c Mon Dec 29 18:05:29 1997
- @@ -111,6 +111,15 @@
-
- #define min(a,b) ((a)<(b)?(a):(b))
-
- +#ifdef CONFIG_SPLIT_GID
- +/*
- + * Priveleged group ids
- + */
- +#define PROT_SOCK_GID 16
- +#define RAW_SOCK_GID 17
- +#define PACKET_SOCK_GID 18
- +#endif /* CONFIG_SPLIT_GID */
- +
- extern struct proto packet_prot;
- extern int raw_get_info(char *, char **, off_t, int, int);
- extern int snmp_get_info(char *, char **, off_t, int, int);
- @@ -435,8 +444,26 @@
- sk->no_check = UDP_NO_CHECK;
- prot=&udp_prot;
- } else if(sock->type == SOCK_RAW || sock->type == SOCK_PACKET) {
- +#ifdef CONFIG_SPLIT_GID
- + /*
- + * If we are not the super user, check to see if we have the
- + * corresponding special group priviledge.
- + */
- + if (!suser())
- + {
- + if (sock->type == SOCK_RAW && current->egid != RAW_SOCK_GID)
- + {
- + goto free_and_badperm;
- + }
- + else if (sock->type == SOCK_PACKET && current->egid != PACKET_SOCK_GID)
- + {
- + goto free_and_badperm;
- + }
- + }
- +#else
- if (!suser())
- goto free_and_badperm;
- +#endif /* CONFIG_SPLIT_GID */
- if (!protocol)
- goto free_and_noproto;
- prot = &raw_prot;
- @@ -621,7 +648,11 @@
- if (snum == 0)
- snum = sk->prot->good_socknum();
- if (snum < PROT_SOCK) {
- +#ifdef CONFIG_SPLIT_GID
- + if (!suser() && current->egid != PROT_SOCK_GID)
- +#else
- if (!suser())
- +#endif /* CONFIG_SPLIT_GID */
- return(-EACCES);
- if (snum == 0)
- return(-EAGAIN);
- <-->
-
-
- ----[ EOF
-
-