diff -urN linux/Documentation/Configure.help linux/Documentation/Configure.help --- linux/Documentation/Configure.help Fri Dec 21 12:41:53 2001 +++ linux/Documentation/Configure.help Sun Jan 20 12:01:27 2002 @@ -19794,6 +19794,682 @@ "Area6" will work for most boards. For ADX, select "Area5". +Grsecurity +CONFIG_GRKERNSEC + If you say Y here, you will be able to configure many features that + will enhance the security of your system. It is highly recommended + that you say Y here and read through the help for each option so + you fully understand what its doing and can evaluate its usefulness + for your machine. + +OpenWall Non-executable Stack +CONFIG_GRKERNSEC_STACK + If you say Y here, your system will not allow execution of + code on the stack, making buffer overflow exploitation more difficult. + The code for this protection is taken from the Openwall patch for + linux 2.2 by Solar Designer. You can view his projects at + http://www.openwall.com/linux. + Exploits against your machine with this protection will have to dabble + in more obscure methods of exploitation(bss,got,heap..) + +Gcc trampoline support +CONFIG_GRKERNSEC_STACK_GCC + If you say Y here, the system will support trampoline code along + with the stack protection. If you do not have any programs on + your system that require this (glibc 2.0 users must say YES to + this option) you may say no here. + +PaX protection +CONFIG_GRKERNSEC_PAX + By design the IA-32 architecture does not allow for protecting + memory pages against execution, i.e. if a page is readable (such + as the stack or heap) it is also executable. There is a well + known exploit technique that makes use of this fact and a common + programming mistake where an attacker can introduce executable + code of his choice somewhere in the attacked program's memory + (typically the stack or the heap) and then execute it. If the + attacked program was running with different (typically higher) + privileges than that of the attacker, then he can elevate his + own privilege level (e.g. get a root shell, write to files for + which he does not have write access to, etc). + + Since the implementation is software based, it comes with a + performance impact, you should evaluate your system carefully + before deciding to use this feature on production systems. + + Enabling this feature will enforce the non-executable flag on + memory pages thereby making it harder to execute 'foreign' code + in a program. This will also break programs that rely on the + old behaviour and expect that dynamically allocated memory via + the malloc() family of functions is executable (which it is not). + Notable examples are the XFree86 4.x server, the java runtime + and wine. + + NOTE: you can use the 'chpax' utility to enable/disable this + feature on a per file basis. chpax is available at + http://pageexec.virtualave.net + +Emulate trampolines +CONFIG_GRKERNSEC_PAX_EMUTRAMP + There are some programs and libraries that for one reason or + another attempt to execute special small code snippets from + non-executable memory pages. Most notable examples are the + signal handler return code generated by the kernel itself and + the GCC trampolines. + + If you enabled CONFIG_GRKERNSEC_PAX then such programs will no + longer work under your kernel. As a remedy you can say Y here + and use the 'chpax' utility to enable trampoline emulation for + the affected programs yet still have the protection provided by + CONFIG_GRKERNSEC_PAX. Alternatively you can say N here and use + the 'chpax' utility to disable CONFIG_GRKERNSEC_PAX for the + affected files. chpax is available at + http://pageexec.virtualave.net + + NOTE: enabling this feature *may* open up a loophole in the + protection provided by CONFIG_GRKERNSEC_PAX that an attacker + could abuse. Therefore the best solution is to not have any + files on your system that would require this option. This can + be achieved by not using libc5 (which relies on the kernel + signal handler return code) and not using or rewriting programs + that make use of the nested function implementation of GCC. + Skilled users can just fix GCC itself so that it implements + nested function calls in a way that does not interfere with PaX. + +Restrict mprotect() +CONFIG_GRKERNSEC_PAX_MPROTECT + Enabling this option will prevent programs from changing the + executable status of memory pages that were not originally + created as executable. The kernel will also prevent programs + from making read-only executable pages writable again. + + You should say Y here to complete the protection provided by + the enforcement of the PAGE_EXEC flag (CONFIG_GRKERNSEC_PAX). + + NOTE: you can use the 'chpax' utility to enable/disable this + feature on a per file basis. chpax is available at + http://pageexec.virtualave.net + +Randomize mmap() base +CONFIG_GRKERNSEC_PAX_RANDMMAP + By saying Y here the kernel will somewhat randomize the address + space layout of programs at each execution (the top of the stack, the + base address for mmap() requests that do not specify one themselves + and the base address of dynamic ELF executables). + + As a result all dynamically loaded libraries will appear at random + addresses and therefore be harder to exploit by a technique where + an attacker attempts to execute library code for his purposes + (e.g. spawn a shell from an exploited program that is running at + an elevated privilege level). + + Furthermore, if a program is relinked as a dynamic ELF file, its + base address layout will be randomized as well, completing the full + randomization of the address space. Attacking such programs becomes + a guess game. + + It is strongly recommended to say Y here even if CONFIG_GRKERNSEC_PAX + is not enabled as address space layout randomization has negligible + impact on performance yet it provides a very effective protection. + + NOTE: you can use the 'chpax' utility to enable/disable this + feature on a per file basis. chpax is available at + http://pageexec.virtualave.net + +Read-only kernel memory +CONFIG_GRKERNSEC_KMEM + If you say Y here, root will not be able to modify the contents of + kernel memory. If module support is removed in addition to enabling + this option, the ability of an attacker to insert foreign code into + a running kernel is removed. If the sysctl option is enabled, a + sysctl option with name "read_only_kmem" is created. + +Fixed mmap restrictions +CONFIG_GRKERNSEC_MMAPFIXED + If you say Y here, it will be impossible for an attacker to bypass the + PaX buffer overflow protection by mmaping an executable memory region + with a specific address set. If the sysctl option is enabled, a + sysctl option with name "mmap_fixed_restrict" is created. + +Proc Restrictions +CONFIG_GRKERNSEC_PROC + If you say Y here, the permissions of the /proc filesystem + will be altered to enhance system security and privacy. Depending + upon the options you choose, you can either restrict users to see + only the processes they themselves run, or choose a group that can + view all processes and files normally restricted to root if you choose + the "restrict to user only" option. NOTE: If you're running identd as + a non-root user, you will have to run it as the group you specify here. + +Restrict /proc to user only +CONFIG_GRKERNSEC_PROC_USER + If you say Y here, non-root users will only be able to view their own + processes, and restricts them from viewing network-related information, + running dmesg(8), and viewing kernel symbol and module information. + +Restrict /proc to user and group +CONFIG_GRKERNSEC_PROC_USERGROUP + If you say Y here, you will be able to select a group that will be + able to view all processes, network-related information, and + kernel and symbol information. This option is useful if you want + to run identd as a non-root user. + +Linking restrictions +CONFIG_GRKERNSEC_LINK + If you say Y here, /tmp race exploits will be prevented, since users + will no longer be able to follow symlinks owned by other users in + world-writeable +t directories (i.e. /tmp), unless the owner of the + symlink is the owner of the directory. users will also not be + able to hardlink to files they do not own. If the sysctl option is + enabled, a sysctl option with name "linking_restrictions" is created. + +FIFO restrictions +CONFIG_GRKERNSEC_FIFO + If you say Y here, users will not be able to write to FIFOs they don't + own in world-writeable +t directories (i.e. /tmp), unless the owner of + the FIFO is the same owner of the directory it's held in. If the sysctl + option is enabled, a sysctl option with name "fifo_restrictions" is + created. + +Secure file descriptors +CONFIG_GRKERNSEC_FD + If you say Y here, binaries will be protected from data spoofing + attacks (eg. making a program read /etc/shadow). The patches do this + by opening up /dev/null to any of the stdin, stdout, stderr file descriptors + for binaries that are open. If the sysctl option is enabled, a sysctl + option with name "secure_fds" is created. + +Exec process limiting +CONFIG_GRKERNSEC_EXECVE + If you say Y here, users with a resource limit on processes will + have the value checked during execve() calls. The current system + only checks the system limit during fork() calls. If the sysctl option + is enabled, a sysctl option with name "execve_limiting" is created. + +Fork-bombing protection +CONFIG_GRKERNSEC_FORKBOMB + If you say Y here, you will be able to configure a group to add to users + on your system that you want to be unable to fork-bomb the system. + You will be able to specify a maximum process limit for the user and + set a rate limit for all forks under their uid. (Fork-bombing is a + tactic used by attackers that can be enacted in two ways, (1) loading + up thousands of processes until the system can't take any more (this + method can be stopped outside of the kernel with PAM, however we place + protection for it in the kernel to be more complete and reduce overhead), + and (2), by forking processes at a rapid rate, and then killing them + off, which cannot be protected against in the same way at tactic 1) + The rate limit is specified in forks allowed per second. Set this + limit low enough to stop tactic 2, but high enough to allow for + normal operation. The protection will kill the offending process. + If the sysctl option is enabled, a sysctl option with name + "fork_bomb_prot" is created. + +Max processes for fork-bomb protection +CONFIG_GRKERNSEC_FORKBOMB_MAX + Here you can configure the maximum number of processes users in the + fork-bomb protected group can run. I would not recommend setting a + value lower than 8, since some programs like man(1) spawn up to 8 + processes to run. The default value should be fine for most purposes. + If the sysctl option is enabled, a sysctl option with name + "fork_bomb_max" is created. + +Forks allowed per second +CONFIG_GRKERNSEC_FORKBOMB_SEC + Here you can specify the maximum number of forks allowed per second. + You don't want to set this value too low, or else you'll hinder + normal operation of your system. The default value should be fine for + most users. If the sysctl option is enabled, a sysctl option with name + "fork_bomb_sec" is created. + +Group for fork-bomb protection +CONFIG_GRKERNSEC_FORKBOMB_GID + Here you can choose the GID to enable fork-bomb protection for. + Remember to add the users you want protection enabled for to the GID + specified here. If the sysctl option is enabled, whatever you choose + here won't matter. You'll have to specify the GID in your bootup + script by echoing the GID to the proper /proc entry. View the help + on the sysctl option for more information. If the sysctl option is + enabled, a sysctl option with name "fork_bomb_gid" is created. + +Single group for auditing +CONFIG_GRKERNSEC_AUDIT_GROUP + If you say Y here, the exec, chdir, (un)mount, and ipc logging features + will only operate on a group you specify. This option is recommended + if you only want to watch certain users instead of having a large + amount of logs from the entire system. If the sysctl option is enabled, + a sysctl option with name "audit_group" is created. + +GID for auditing +CONFIG_GRKERNSEC_AUDIT_GID + Here you can choose the GID that will be the target of kernel auditing. + Remember to add the users you want to log to the GID specified here. + If the sysctl option is enabled, whatever you choose here won't matter. + You'll have to specify the GID in your bootup script by echoing the GID + to the proper /proc entry. View the help on the sysctl option for more + information. If the sysctl option is enabled, a sysctl option with name + "audit_gid" is created. + +Chdir logging +CONFIG_GRKERNSEC_AUDIT_CHDIR + If you say Y here, all chdir() calls will be logged. If the sysctl + option is enabled, a sysctl option with name "audit_chdir" is created. + +(Un)Mount logging +CONFIG_GRKERNSEC_AUDIT_MOUNT + If you say Y here, all mounts and unmounts will be logged. If the + sysctl option is enabled, a sysctl option with name "audit_mount" is + created. + +IPC logging +CONFIG_GRKERNSEC_AUDIT_IPC + If you say Y here, creation and removal of message queues, semaphores, + and shared memory will be logged. If the sysctl option is enabled, a + sysctl option with name "audit_ipc" is created. + +Exec logging +CONFIG_GRKERNSEC_EXECLOG + If you say Y here, all execve() calls will be logged (since the + other exec*() calls are frontends to execve(), all execution + will be logged). Useful for shell-servers that like to keep track + of their users. If the sysctl option is enabled, a sysctl option with + name "exec_logging" is created. + WARNING: This option when enabled will produce a LOT of logs, especially + on an active system. + +Set*id logging +CONFIG_GRKERNSEC_SUID + If you say Y here, all set*id() calls will be logged. Such information + could be useful when detecting a possible intrusion attempt. This + option can produce a lot of logs on an active system. If the sysctl + option is enabled, a sysctl option with name "suid_logging" is created. + +Log set*ids to root +CONFIG_GRKERNSEC_SUID + If you say Y here, only set*id() calls where a user is changing to the + gid or uid of the root user will be logged. Such information + could be useful when detecting a possible intrusion attempt. This + option will produce less logs than logging all calls. If the sysctl + option is enabled, a sysctl option with name "suid_root_logging" is + created. + +Altered default IPC permissions +CONFIG_GRKERNSEC_IPC + If you say Y here, the default permissions for IPC objects will be + set based on the filesystem umask of the user creating the object. + By default linux sets the permissions to ugo+rwx, which can be + a security problem if the application doesn't explicitly set the + permissions of the IPC object. + +Signal logging +CONFIG_GRKERNSEC_SIGNAL + If you say Y here, certain important signals will be logged, such as + SIGSEGV, which will as a result inform you of when a error in a program + occurred, which in some cases could mean a possible exploit attempt. + If the sysctl option is enabled, a sysctl option with name + "signal_logging" is created. + +BSD-style coredumps +CONFIG_GRKERNSEC_COREDUMP + If you say Y here, linux will use a style similar to BSD for + coredumps, core.processname. Not a security feature, just + a useful one. If the sysctl option is enabled, a sysctl option with + name "coredump" is created. + +Fork failure logging +CONFIG_GRKERNSEC_FORKFAIL + If you say Y here, all failed fork() attempts will be logged. + This could suggest a fork bomb, or someone attempting to overstep + their process limit. If the sysctl option is enabled, a sysctl option + with name "forkfail_logging" is created. + +Time change logging +CONFIG_GRKERNSEC_TIME + If you say Y here, any changes of the system clock will be logged. + If the sysctl option is enabled, a sysctl option with name + "timechange_logging" is created. + +Secure keymap loading +CONFIG_GRKERNSEC_KBMAP + If you say Y here, KDSKBENT and KDSKBSENT ioctl calls being + called by unprivileged users will be denied. If you answer N, + everyone with access to the console will be able to modify keyboard + bindings. If the sysctl option is enabled, a sysctl option with name + "secure_kbmap" is created. + +Chroot jail restrictions +CONFIG_GRKERNSEC_CHROOT + If you say Y here, you will be able to choose several options that will + make breaking out of a chrooted jail much more difficult. If you + encounter no software incompatibilities with the following options, it + is recommended that you enable each one. + +Restricted signals in chroot +CONFIG_GRKERNSEC_CHROOT_SIG + If you say Y here, processes inside a chroot will not be able to send + signals outside of the chroot. The only signals allowed are null + signals which perform no action, and the parent process sending + a certain signal to its child. If the sysctl option is enabled, a + sysctl option with name "chroot_restrict_sigs" is created. + +Deny mounts in chroot +CONFIG_GRKERNSEC_CHROOT_MOUNT + If you say Y here, processes inside a chroot will not be able to + mount or remount filesystems. If the sysctl option is enabled, a + sysctl option with name "chroot_deny_mount" is created. + +Deny double-chroots +CONFIG_GRKERNSEC_CHROOT_DOUBLE + If you say Y here, processes inside a chroot will not be able to chroot + again. This is a widely used method of breaking out of a chroot jail + and should not be allowed. If the sysctl option is enabled, a sysctl + option with name "chroot_deny_chroot" is created. + +Enforce chdir("/") on all chroots +CONFIG_GRKERNSEC_CHROOT_CHDIR + If you say Y here, the current working directory of all newly-chrooted + applications will be set to the the root directory of the chroot. + The man page on chroot(2) states: + Note that this call does not change the current working + directory, so that `.' can be outside the tree rooted at + `/'. In particular, the super-user can escape from a + `chroot jail' by doing `mkdir foo; chroot foo; cd ..'. + + It is recommended that you say Y here, since it's not known to break + any software. If the sysctl option is enabled, a sysctl option with + name "chroot_enforce_chdir" is created. + +Deny (f)chmod +s in chroot +CONFIG_GRKERNSEC_CHROOT_CHMOD + If you say Y here, processes inside a chroot will not be able to chmod + or fchmod files to make them have suid or sgid bits. This protects + against another published method of breaking a chroot. If the sysctl + option is enabled, a sysctl option with name "chroot_deny_chmod" is + created. + +Deny mknod in chroot +CONFIG_GRKERNSEC_CHROOT_MKNOD + If you say Y here, processes inside a chroot will not be allowed to + mknod. The problem with using mknod inside a chroot is that it + would allow an attacker to create a device entry that is the same + as one on the physical root of your system, which could range from + anyhing from the console device to a device for your harddrive (which + they could then use to wipe the drive or steal data). It is recommended + that you say Y here, unless you run into software incompatibilities. + If the sysctl option is enabled, a sysctl option with name + "chroot_deny_mknod" is created. + +Deny ptraces in chroot +CONFIG_GRKERNSEC_CHROOT_PTRACE + If you say Y here, processes inside a chroot will not be able to ptrace + other processes. Ptracing a process allows one to attach and alter the + flow of execution for the process. It is strongly recommended that you + say Y here. If the sysctl option is enabled, a sysctl option with name + "chroot_deny_ptrace" is created. + +Restrict priority changes in chroot +CONFIG_GRKERNSEC_CHROOT_NICE + If you say Y here, processes inside a chroot will not be able to raise + the priority of processes in the chroot, or alter the priority of + processes outside the chroot. This provides more security than simply + removing CAP_SYS_NICE from the process' capability set. If the + sysctl option is enabled, a sysctl option with name "chroot_restrict_nice" + is created. + +Log all execs within chroot +CONFIG_GRKERNSEC_CHROOT_EXECLOG + If you say Y here, all executions inside a chroot jail will be logged + to syslog. If the sysctl option is enabled, a sysctl option with name + "chroot_execlog" is created. + +Chroot jail capability restrictions +CONFIG_GRKERNSEC_CHROOT_CAPS + If you say Y here, the capabilities on all root processes within a + chroot jail will be lowered to stop module insertion, raw i/o, + system and net admin tasks, transferring capabilities, and + tty configuration tasks. This is left an option because it breaks + some apps. Disable this if your chrooted apps are having + problems performing those kinds of tasks. If the sysctl option is + enabled, a sysctl option with name "chroot_caps" is created. + +Trusted path execution +CONFIG_GRKERNSEC_TPE + If you say Y here, you will be able to choose a gid to add to the + supplementary groups of users you want to mark as "untrusted." + These users will not be able to execute any files that are not in + root-owned directories writeable only by root. If the sysctl option + is enabled, a sysctl option with name "tpe" is created. + +Group for trusted path execution +CONFIG_GRKERNSEC_TPE_GID + Here you can choose the GID to enable trusted path protection for. + Remember to add the users you want protection enabled for to the GID + specified here. If the sysctl option is enabled, whatever you choose + here won't matter. You'll have to specify the GID in your bootup + script by echoing the GID to the proper /proc entry. View the help + on the sysctl option for more information. If the sysctl option is + enabled, a sysctl option with name "tpe_gid" is created. + +Partially restrict non-root users +CONFIG_GRKERNSEC_TPE_ALL + If you say Y here, All other non-root users will only be allowed to + execute files in directories they own that are not group or + world-writeable, or in directories owned by root and writeable only by + root. If the sysctl option is enabled, a sysctl option with name + "tpe_restrict_all" is created. + +Trusted path execution glibc protection +CONFIG_GRKERNSEC_TPE_GLIBC + If you say Y here, all non-root users will not be able to execute + any files while glibc specific environment variables such as + LD_PRELOAD are set, which could be used to evade the trusted path + execution protection. It also protects against evasion through + /lib/ld-2.* It is recommended you say Y here also. If the sysctl option + is enabled, a sysctl option with name "tpe_glibc" is created. + +Restricted ptrace +CONFIG_GRKERNSEC_PTRACE + If you say Y here, no one but root will be able to ptrace processes. + Tracing syscalls inside the kernel will also be disabled. All allowed + ptraces will be logged when this option is enabled. If the sysctl + option is enabled, a sysctl option with name "restrict_ptrace" is + created. + +Allow ptrace for group +CONFIG_GRKERNSEC_PTRACE_GROUP + If you say Y here, you will be able to choose a GID of whose users + will be able to ptrace. If the sysctl option is enabled, a sysctl + option with name "allow_ptrace_group" is created. + +GID for ptrace +CONFIG_GRKERNSEC_PTRACE_GID + Here you can choose the GID of whose users will be able to ptrace. + Remember to add the users you want ptrace enabled for to the GID + specified here. If the sysctl option is enabled, whatever you choose + here won't matter. You'll have to specify the GID in your bootup + script by echoing the GID to the proper /proc entry. View the help + on the sysctl option for more information. If the sysctl option is + enabled, a sysctl option with name "ptrace_gid" is created. + +Randomized PIDs +CONFIG_GRKERNSEC_RANDPID + If you say Y here, all PIDs created on the system will be + pseudo-randomly generated. This is extremely effective along + with the /proc restrictions to disallow an attacker from guessing + pids of daemons, etc. PIDs are also used in some cases as part + of a naming system for temporary files, so this option would keep + those filenames from being predicted as well. We also use code + to make sure that PID numbers aren't reused too soon. If the sysctl + option is enabled, a sysctl option with name "rand_pids" is created. + +Limit uid/gid changes to root +CONFIG_GRKERNSEC_TTYROOT + If you say Y here, you will be able choose from three option that + will allow you to restrict access to the root account by console + type. These options should only be enabled if you are sure of what + you're doing. Also note that they only apply to processes that have + ttys, which generally involves some kind of user-interaction. The + options are basically in place to keep users on a system who have a + (stolen) password for root from using it unless their console + credentials match. + +Deny physical consoles (tty) +CONFIG_GRKERNSEC_TTYROOT_PHYS + If you say Y here, access to root from physical consoles will be + denied. This is only recommended for rare cases where you will + never need to be physically at the machine. If the sysctl option + is enabled, a sysctl option with name "deny_phys_root" is created. + +Deny serial consoles (ttyS) +CONFIG_GRKERNSEC_TTYROOT_SERIAL + If you say Y here, access to root from serial consoles will be + denied. Most people can say Y here, since most don't use serial + devices for their console access. If you are unsure, say N. If + the sysctl option is enabled, a sysctl option with name + "deny_serial_root" is created. + +Deny pseudo consoles (pty) +CONFIG_GRKERNSEC_TTYROOT_PSEUDO + If you say Y here, access to root from pseudo consoles will be + denied. Pseudo consoles include consoles from telnet, ssh, or any other + kind of interactive shell initiated from the network. Pseudo consoles + also include any terminals you use in XFree86. If you will only be + accessing the machine for root access from the physical console, you + can say Y here. Only say Y here if you're sure of what you're doing. + If the sysctl option is enabled, a sysctl option with name + "deny_pseudo_root" is created. + +Randomized IP IDs +CONFIG_GRKERNSEC_RANDID + If you say Y here, all the id field on all outgoing packets + will be randomized. This hinders os fingerprinters and + keeps your machine from being used as a bounce for an untraceable + portscan. Ids are used for fragmented packets, fragments belonging + to the same packet have the same id. By default linux only + increments the id value on each packet sent to an individual host. + We use a port of the OpenBSD random ip id code to achieve the + randomness, while keeping the possibility of id duplicates to + near none. If the sysctl option is enabled, a sysctl option with name + "rand_ip_ids" is created. + +Randomized TCP source ports +CONFIG_GRKERNSEC_RANDSRC + If you say Y here, situations where a source port is generated on the + fly for the TCP protocol (ie. with connect() ) will be altered so that + the source port is generated at random, instead of a simple incrementing + algorithm. If the sysctl option is enabled, a sysctl option with name + "rand_tcp_src_ports" is created. + +Altered Ping IDs +CONFIG_GRKERNSEC_RANDPING + If you say Y here, the way Linux handles echo replies will be changed + so that the reply uses an ID equal to the ID of the echo request. + This will help in confusing OS detection. If the sysctl option is + enabled, a sysctl option with name "altered_pings" is created. + +Randomized TTL +CONFIG_GRKERNSEC_RANDTTL + If you say Y here, your TTL (time to live) for packets will be set at + random, with a base level you specify, to further confuse OS detection. + If the sysctl option is enabled, a sysctl option with name "rand_ttl" + is created. + +Randomized TTL threshold +CONFIG_GRKERNSEC_RANDTTL_THRESH + Here you can choose a base TTL for the randomization. The default value + for this setting is the Linux default TTL. Most users will want to + leave this setting as-is. The higher you set the base level (note that + you can't set it above 255) the more hops your packets will live. + If the sysctl option is enabled, whatever you choose here won't matter. + You'll have to specify the threshold in your bootup script by echoing + the threshold to the proper /proc entry. View the help on the sysctl + option for more information. If the sysctl option is enabled, a sysctl + option with name "rand_ttl_thresh" is created. + +Socket restrictions +CONFIG_GRKERNSEC_SOCKET + If you say Y here, you will be able to choose from several options. + If you assign a GID on your system and add it to the supplementary + groups of users you want to restrict socket access to, this patch + will perform up to three things, based on the option(s) you choose. + +Deny all socket access +CONFIG_GRKERNSEC_SOCKET_ALL + If you say Y here, you will be able to choose a GID of whose users will + be unable to connect to other hosts from your machine or run server + applications from your machine. If the sysctl option is enabled, a + sysctl option with name "socket_all" is created. + +Group for disabled socket access +CONFIG_GRKERNSEC_SOCKET_ALL_GID + Here you can choose the GID to disable socket access for. Remember to + add the users you want socket access disabled for to the GID + specified here. If the sysctl option is enabled, whatever you choose + here won't matter. You'll have to specify the GID in your bootup + script by echoing the GID to the proper /proc entry. View the help + on the sysctl option for more information. If the sysctl option is + enabled, a sysctl option with name "socket_all_gid" is created. + +Deny all client socket access +CONFIG_GRKERNSEC_SOCKET_CLIENT + If you say Y here, you will be able to choose a GID of whose users will + be unable to connect to other hosts from your machine, but will be + able to run servers. If this option is enabled, all users in the group + you specify will have to use passive mode when initiating ftp transfers + from the shell on your machine. If the sysctl option is enabled, a + sysctl option with name "socket_client" is created. + +Group for disabled client socket access +CONFIG_GRKERNSEC_SOCKET_CLIENT_GID + Here you can choose the GID to disable client socket access for. + Remember to add the users you want client socket access disabled for to + the GID specified here. If the sysctl option is enabled, whatever you + choose here won't matter. You'll have to specify the GID in your bootup + script by echoing the GID to the proper /proc entry. View the help + on the sysctl option for more information. If the sysctl option is + enabled, a sysctl option with name "socket_client_gid" is created. + +Deny all server socket access +CONFIG_GRKERNSEC_SOCKET_SERVER + If you say Y here, you will be able to choose a GID of whose users will + be unable to run server applications from your machine. If the sysctl + option is enabled, a sysctl option with name "socket_server" is created. + +Group for disabled server socket access +CONFIG_GRKERNSEC_SOCKET_SERVER_GID + Here you can choose the GID to disable server socket access for. + Remember to add the users you want server socket access disabled for to + the GID specified here. If the sysctl option is enabled, whatever you + choose here won't matter. You'll have to specify the GID in your bootup + script by echoing the GID to the proper /proc entry. View the help + on the sysctl option for more information. If the sysctl option is + enabled, a sysctl option with name "socket_server_gid" is created. + +Sysctl support +CONFIG_GRKERNSEC_SYSCTL + If you say Y here, you will be able to change the options that + grsecurity runs with at bootup, without having to recompile your + kernel. You can echo values to files in /proc/sys/kernel/grsecurity + to enable (1) or disable (0) various features. All the sysctl entries + are mutable until the "grsec_lock" entry is set to a non-zero value. + All features are disabled by default. Please note that this option could + reduce the effectiveness of the added security of this patch if an ACL + system is not put in place. Your init scripts should be read-only, and + root should not have access to adding modules or performing raw i/o + operations. All options should be set at startup, and the grsec_lock + entry should be set to a non-zero value after all the options are set. + *THIS IS EXTREMELY IMPORTANT* + +Oblivion ACL System +CONFIG_GRKERNSEC_ACL + If you say Y here, you enable the Access Control List system for + grsecurity called Oblivion. Oblivion is a very advanced ACL system + that is optimized for speed and correctness of ACLS. Unlike many + other popular ACL systems, it allows both process and file ACLs. + To use the ACL system, you must also download the userspace code + and documentation off the grsecurity website: http://grsecurity.net + You will then need to run obvadm setup to set your password and create + your config files. + # # m68k-specific kernel options # Documented by Chris Lawrence et al. diff -urN linux/Makefile linux/Makefile --- linux/Makefile Fri Dec 21 12:41:53 2001 +++ linux/Makefile Thu Jan 17 17:12:27 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 17 -EXTRAVERSION = +EXTRAVERSION = -grsec-1.9.3a KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux/arch/alpha/config.in linux/arch/alpha/config.in --- linux/arch/alpha/config.in Tue Nov 20 18:49:31 2001 +++ linux/arch/alpha/config.in Sun Jan 13 01:24:51 2002 @@ -393,3 +393,12 @@ fi endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/arm/config.in linux/arch/arm/config.in --- linux/arch/arm/config.in Fri Nov 9 16:58:02 2001 +++ linux/arch/arm/config.in Sun Jan 13 01:24:51 2002 @@ -606,3 +606,12 @@ dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE dep_bool ' kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/cris/config.in linux/arch/cris/config.in --- linux/arch/cris/config.in Mon Oct 15 16:42:14 2001 +++ linux/arch/cris/config.in Sun Jan 13 01:24:51 2002 @@ -251,3 +251,12 @@ int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/i386/config.in linux/arch/i386/config.in --- linux/arch/i386/config.in Fri Dec 21 12:41:53 2001 +++ linux/arch/i386/config.in Sun Jan 13 01:24:51 2002 @@ -416,3 +416,12 @@ fi endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- linux/arch/i386/kernel/entry.S Fri Nov 2 20:18:49 2001 +++ linux/arch/i386/kernel/entry.S Sun Jan 13 01:24:51 2002 @@ -45,6 +45,7 @@ #include #include #include +#include EBX = 0x00 ECX = 0x04 @@ -381,8 +382,52 @@ jmp error_code ENTRY(page_fault) +#ifdef CONFIG_GRKERNSEC_PAX + ALIGN + pushl $ SYMBOL_NAME(pax_do_page_fault) + pushl %ds + pushl %eax + xorl %eax,%eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + decl %eax # eax = -1 + pushl %ecx + pushl %ebx + cld + movl %es,%ecx + movl ORIG_EAX(%esp), %esi # get the error code + movl ES(%esp), %edi # get the function address + movl %eax, ORIG_EAX(%esp) + movl %ecx, ES(%esp) + movl %esp,%edx + pushl %esi # push the error code + pushl %edx # push the pt_regs pointer + movl $(__KERNEL_DS),%edx + movl %edx,%ds + movl %edx,%es + GET_CURRENT(%ebx) + call *%edi + addl $8,%esp + decl %eax + jnz ret_from_exception + + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + popl %eax + popl %ds + popl %es + addl $4,%esp + jmp system_call +#else pushl $ SYMBOL_NAME(do_page_fault) jmp error_code +#endif ENTRY(machine_check) pushl $0 diff -urN linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- linux/arch/i386/kernel/head.S Wed Jun 20 14:00:53 2001 +++ linux/arch/i386/kernel/head.S Sun Jan 13 01:24:51 2002 @@ -433,7 +433,11 @@ .quad 0x0000000000000000 /* not used */ .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ +#ifdef CONFIG_GRKERNSEC_STACK + .quad 0x00cbfa000000f7ff /* 0x23 user 3GB-8MB code at 0 */ +#else .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */ +#endif .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ .quad 0x0000000000000000 /* not used */ .quad 0x0000000000000000 /* not used */ diff -urN linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- linux/arch/i386/kernel/ptrace.c Wed Nov 21 13:42:41 2001 +++ linux/arch/i386/kernel/ptrace.c Sun Jan 13 01:24:51 2002 @@ -21,6 +21,9 @@ #include #include +#if defined(CONFIG_GRKERNSEC_CHROOT_PTRACE) || defined(CONFIG_GRKERNSEC_PTRACE) +#include +#endif /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. @@ -177,6 +180,32 @@ if (pid == 1) /* you may not mess with init */ goto out_tsk; +#ifdef CONFIG_GRKERNSEC_PTRACE + if(grsec_enable_ptrace && current->uid +#ifdef CONFIG_GRKERNSEC_PTRACE_GROUP + && ((grsec_enable_ptrace_group && !in_group_p(grsec_ptrace_gid)) + || !grsec_enable_ptrace_group) +#endif + ) { + security_alert("denied ptrace of (%.16s:%d) by " DEFAULTSECMSG, + "denied ptraces", child->comm, child->pid, DEFAULTSECARGS); + goto out_tsk; + } + security_alert("ptrace of (%.16s:%d) by " DEFAULTSECMSG, + "ptraces", child->comm, child->pid, DEFAULTSECARGS); +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_PTRACE + if(grsec_enable_chroot_ptrace && proc_is_chrooted(current) && + have_same_root(current,child)) { + security_alert("denied ptrace of process(%.16s:%d) within chroot jail " + "(%.32s:%lu) by " DEFAULTSECMSG, + "ptrace from chroot", + child->comm,child->pid,kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino, + DEFAULTSECARGS); + goto out_tsk; + } +#endif if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; @@ -439,11 +468,23 @@ return ret; } +#ifdef CONFIG_GRKERNSEC_PTRACE +asmlinkage void syscall_trace(int unused) +#else asmlinkage void syscall_trace(void) +#endif { +#ifdef CONFIG_GRKERNSEC_PTRACE + struct pt_regs *regs = (struct pt_regs *) &unused; +#endif + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != (PT_PTRACED|PT_TRACESYS)) return; +#ifdef CONFIG_GRKERNSEC_PTRACE + if(!user_mode(regs)) + return; +#endif /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) diff -urN linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- linux/arch/i386/kernel/signal.c Fri Sep 14 17:15:40 2001 +++ linux/arch/i386/kernel/signal.c Sun Jan 13 01:24:51 2002 @@ -7,6 +7,7 @@ * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes */ +#include #include #include #include @@ -421,11 +422,15 @@ if (ka->sa.sa_flags & SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { +#ifdef CONFIG_GRKERNSEC_STACK + err |= __put_user(MAGIC_SIGRETURN, &frame->pretcode); +#else err |= __put_user(frame->retcode, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ err |= __put_user(0xb858, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2)); err |= __put_user(0x80cd, (short *)(frame->retcode+6)); +#endif } if (err) @@ -496,11 +501,15 @@ if (ka->sa.sa_flags & SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { +#ifdef CONFIG_GRKERNSEC_STACK + err |= __put_user(MAGIC_RT_SIGRETURN, &frame->pretcode); +#else err |= __put_user(frame->retcode, &frame->pretcode); /* This is movl $,%eax ; int $0x80 */ err |= __put_user(0xb8, (char *)(frame->retcode+0)); err |= __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1)); err |= __put_user(0x80cd, (short *)(frame->retcode+5)); +#endif } if (err) @@ -557,6 +566,18 @@ regs->eip -= 2; } } + +#ifdef CONFIG_GRKERNSEC_PAX + /* PaX: clean up as our trace attempt became obsolete */ + if ((current->flags & PF_PAX_PAGEEXEC) && (current->ptrace & PT_PAX_TRACE)) { + if (!(current->ptrace & PT_PAX_OLDTF)) { + regs->eflags &= ~TF_MASK; + } + current->ptrace &= ~(PT_PAX_TRACE | PT_PAX_KEEPTF | PT_PAX_OLDTF); + current->thread.pax_faults.eip = 0; + current->thread.pax_faults.count = 0; + } +#endif /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) diff -urN linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- linux/arch/i386/kernel/traps.c Sun Sep 30 15:26:08 2001 +++ linux/arch/i386/kernel/traps.c Sun Jan 13 01:24:51 2002 @@ -49,6 +49,9 @@ #include #include +#ifdef CONFIG_GRKERNSEC_STACK +#include +#endif asmlinkage int system_call(void); asmlinkage void lcall7(void); @@ -348,14 +351,183 @@ DO_ERROR(12, SIGBUS, "stack segment", stack_segment) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) +#if defined(CONFIG_GRKERNSEC_STACK) && defined(CONFIG_GRKERNSEC_STACK_GCC) +static unsigned long *get_reg(struct pt_regs *regs, unsigned char regnum) +{ + switch (regnum) { + case 0: return ®s->eax; + case 1: return ®s->ecx; + case 2: return ®s->edx; + case 3: return ®s->ebx; + case 4: return ®s->esp; + case 5: return ®s->ebp; + case 6: return ®s->esi; + case 7: return ®s->edi; + } + return NULL; +} +static unsigned long get_modrm(struct pt_regs *regs, int *err) +{ + unsigned char modrm, sib; + signed char rel8; + unsigned long rel32; + int size, regnum, scale; + unsigned long index, base, addr, value; + + *err |= __get_user(modrm, (unsigned char *)(regs->eip + 1)); + size = 2; + regnum = modrm & 7; + addr = *get_reg(regs, regnum); + if (regnum == 4 && (modrm & 0xC0) != 0xC0) { + *err |= __get_user(sib, (unsigned char *)(regs->eip + 2)); + size = 3; + scale = sib >> 6; + index = *get_reg(regs, (sib >> 3) & 7); + base = *get_reg(regs, sib & 7); + addr = base + (index << scale); + } + + switch (modrm & 0xC0) { + case 0x00: + if (regnum == 5) { + *err |= __get_user(addr, + (unsigned long *)(regs->eip + 2)); + size = 6; + } + *err |= __get_user(value, (unsigned long *)addr); + break; + + case 0x40: + *err |= __get_user(rel8, (signed char *)(regs->eip + size)); + size++; + addr += rel8; + *err |= __get_user(value, (unsigned long *)addr); + break; + + case 0x80: + *err |= __get_user(rel32, (unsigned long *)(regs->eip + size)); + size += 4; + addr += rel32; + *err |= __get_user(value, (unsigned long *)addr); + break; + + case 0xC0: + default: + value = addr; + } + + if (*err) return 0; + regs->eip += size; + return value; +} +#endif asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { +#ifdef CONFIG_GRKERNSEC_STACK + unsigned long addr; +#ifdef CONFIG_GRKERNSEC_STACK_GCC + unsigned char insn; + int err, count; +#endif +#endif if (regs->eflags & VM_MASK) goto gp_in_vm86; if (!(regs->xcs & 3)) goto gp_in_kernel; +#ifdef CONFIG_GRKERNSEC_STACK +/* Check if it was return from a signal handler */ + if ((regs->xcs & 0xFFFF) == __USER_CS) + if (*(unsigned char *)regs->eip == 0xC3) + if (!__get_user(addr, (unsigned long *)regs->esp)) { + if ((addr & 0xFFFFFFFE) == MAGIC_SIGRETURN) { +/* Call sys_sigreturn() or sys_rt_sigreturn() to restore the context */ + regs->esp += 8; + __asm__("movl %3,%%esi\n\t" + "subl %1,%%esp\n\t" + "movl %2,%%ecx\n\t" + "movl %%esp,%%edi\n\t" + "rep; movsl\n\t" + "testl $1,%4\n\t" + "jnz 1f\n\t" + "call sys_sigreturn\n\t" + "leal %3,%%edi\n\t" + "jmp 2f\n\t" + "1:\n\t" + "call sys_rt_sigreturn\n\t" + "leal %3,%%edi\n\t" + "2:\n\t" + "addl %1,%%edi\n\t" + "movl %%esp,%%esi\n\t" + "movl %2,%%ecx\n\t" + "movl (%%edi),%%edi\n\t" + "rep; movsl\n\t" + "movl %%esi,%%esp" + : +/* %eax is returned separately */ + "=a" (regs->eax) + : + "i" (sizeof(*regs)), + "i" (sizeof(*regs) >> 2), + "m" (regs), + "r" (addr) + : + "cx", "dx", "si", "di", "cc", "memory"); + return; + } +/* + * * Check if we're returning to the stack area, which is only likely to happen + * * when attempting to exploit a buffer overflow. + * */ + if ((addr & 0xFF800000) == 0xBF800000 || + (addr >= PAGE_OFFSET - _STK_LIM && addr < PAGE_OFFSET)) + security_alert("return onto stack by " DEFAULTSECMSG, + "returns onto stack", DEFAULTSECARGS); + } + +#ifdef CONFIG_GRKERNSEC_STACK_GCC +/* Check if it could have been a trampoline call */ + if ((regs->xcs & 0xFFFF) == __USER_CS) + if (*(unsigned char *)regs->eip == 0xFF) + if (!__get_user(insn, (unsigned char *)(regs->eip + 1))) + if ((insn & 0x38) == 0x10 && insn != 0xD4) { /* call mod r/m */ +/* First, emulate the call */ + err = 0; + addr = get_modrm(regs, &err); + if (!err) { + regs->esp -= 4; + err = __put_user(regs->eip, (unsigned long *)regs->esp); + regs->eip = addr; + } +/* Then, start emulating the trampoline itself */ + count = 0; + while (!err && !__get_user(insn, (unsigned char *)regs->eip++)) + if ((insn & 0xF8) == 0xB8) { /* movl imm32,%reg */ +/* We only have 8 GP registers, no reason to initialize one twice */ + if (count++ >= 8) break; + err |= __get_user(addr, (unsigned long *)regs->eip); + regs->eip += 4; + *get_reg(regs, insn & 7) = addr; + } else + if (insn == 0xFF) { + err |= __get_user(insn, (unsigned char *)regs->eip); + if ((insn & 0xF8) == 0xE0) { /* jmp *%reg */ + regs->eip = *get_reg(regs, insn & 7); + if (err) break; else return; + } + break; + } else + if (insn == 0xE9) { /* jmp rel32 */ + err |= __get_user(addr, (unsigned long *)regs->eip); + if (err) break; + regs->eip += 4 + addr; + return; + } else + break; + } +#endif +#endif current->thread.error_code = error_code; current->thread.trap_no = 13; force_sig(SIGSEGV, current); @@ -452,6 +624,10 @@ inb(0x71); /* dummy */ } +#ifdef CONFIG_GRKERNSEC_PAX +void pax_handle_ptes(struct task_struct *tsk); +#endif + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -482,6 +658,22 @@ __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); +#ifdef CONFIG_GRKERNSEC_PAX + /* PaX: clean up */ + if ((tsk->flags & PF_PAX_PAGEEXEC) && (condition & DR_STEP) && (tsk->ptrace & PT_PAX_TRACE)) { + tsk->ptrace &= ~PT_PAX_TRACE; + pax_handle_ptes(tsk); + if (!(tsk->ptrace & PT_PAX_KEEPTF) && !(tsk->ptrace & PT_PAX_OLDTF)) + regs->eflags &= ~TF_MASK; + tsk->ptrace &= ~PT_PAX_KEEPTF; + if (!(tsk->ptrace & PT_PAX_OLDTF)) { + condition &= ~DR_STEP; + if (!(condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))) + return; + } + tsk->ptrace &= ~PT_PAX_OLDTF; + } +#endif /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) diff -urN linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- linux/arch/i386/mm/fault.c Tue Oct 9 18:13:03 2001 +++ linux/arch/i386/mm/fault.c Sun Jan 13 01:24:51 2002 @@ -4,6 +4,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include @@ -19,6 +20,9 @@ #include #include #include /* For unblank_screen() */ +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_RANDMMAP) +#include +#endif #include #include @@ -146,23 +150,31 @@ * bit 1 == 0 means read, 1 means write * bit 2 == 0 means kernel, 1 means user-mode */ +#ifdef CONFIG_GRKERNSEC_PAX +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address) +#else asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) +#endif { struct task_struct *tsk; struct mm_struct *mm; struct vm_area_struct * vma; +#ifndef CONFIG_GRKERNSEC_PAX unsigned long address; +#endif unsigned long page; unsigned long fixup; int write; siginfo_t info; +#ifndef CONFIG_GRKERNSEC_PAX /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); +#endif tsk = current; @@ -220,21 +232,37 @@ good_area: info.si_code = SEGV_ACCERR; write = 0; +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + switch (error_code & 7) { +#else switch (error_code & 3) { +#endif default: /* 3: write, present */ #ifdef TEST_VERIFY_AREA if (regs->cs == KERNEL_CS) printk("WP fault at %08lx\n", regs->eip); #endif /* fall through */ +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + case 7: /* PaX: write, present, some protection violation */ +#endif case 2: /* write, not present */ +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + case 6: +#endif if (!(vma->vm_flags & VM_WRITE)) goto bad_area; write++; break; case 1: /* read, present */ goto bad_area; +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + case 5: /* PaX: read, present, protection violation */ +#endif case 0: /* read, not present */ +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + case 4: +#endif if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } @@ -409,3 +437,441 @@ return; } } +#ifdef CONFIG_GRKERNSEC_PAX +/* PaX: called with the page_table_lock spinlock held */ +static inline pte_t * pax_get_pte(struct mm_struct *mm, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + + pgd = pgd_offset(mm, address); + if (!pgd || !pgd_present(*pgd)) + return 0; + pmd = pmd_offset(pgd, address); + if (!pmd || !pmd_present(*pmd)) + return 0; + return pte_offset(pmd, address); +} + +/* + * PaX: decide what to do with offenders + * + * returns 0 when access should be allowed + * 1 when task should be killed + * 2 when sigreturn trampoline was detected + * 3 when rt_sigreturn trampoline was detected + * 4 when gcc trampoline was detected + */ +static int pax_handle_read_fault(struct pt_regs *regs, unsigned long address) +{ + static unsigned char trans[8] = {6, 1, 2, 0, 13, 5, 3, 4}; + int err; + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + if (!(current->flags & PF_PAX_EMUTRAMP)) + return 1; + + { /* PaX: sigreturn emulation */ + unsigned char pop, mov; + unsigned short sys; + unsigned long nr; + + err = __get_user(pop, (unsigned char *)(regs->eip)); + err |= __get_user(mov, (unsigned char *)(regs->eip + 1)); + err |= __get_user(nr, (unsigned long *)(regs->eip + 2)); + err |= __get_user(sys, (unsigned short *)(regs->eip + 6)); + + if (!err) { + if (pop == 0x58 && + mov == 0xb8 && + nr == __NR_sigreturn && + sys == 0x80cd) + { + regs->esp += 4; + regs->eax = nr; + regs->eip += 8; + return 2; + } + } + } + + { /* PaX: rt_sigreturn emulation */ + unsigned char mov; + unsigned short sys; + unsigned long nr; + + err = __get_user(mov, (unsigned char *)(regs->eip)); + err |= __get_user(nr, (unsigned long *)(regs->eip + 1)); + err |= __get_user(sys, (unsigned short *)(regs->eip + 5)); + + if (!err) { + if (mov == 0xb8 && + nr == __NR_rt_sigreturn && + sys == 0x80cd) + { + regs->eax = nr; + regs->eip += 7; + return 3; + } + } + } + + { /* PaX: gcc trampoline emulation #1 */ + unsigned char mov1, mov2; + unsigned short jmp; + unsigned long addr1, addr2, ret; + + err = __get_user(mov1, (unsigned char *)(regs->eip)); + err |= __get_user(addr1, (unsigned long *)(regs->eip + 1)); + err |= __get_user(mov2, (unsigned char *)(regs->eip + 5)); + err |= __get_user(addr2, (unsigned long *)(regs->eip + 6)); + err |= __get_user(jmp, (unsigned short *)(regs->eip + 10)); + err |= __get_user(ret, (unsigned long *)(regs->esp)); + + if (!err) { + unsigned short call; + + err = __get_user(call, (unsigned short *)(ret-2)); + if (!err) { + if ((mov1 & 0xF8) == 0xB8 && + (mov2 & 0xF8) == 0xB8 && + (mov1 & 0x07) != (mov2 & 0x07) && + (jmp & 0xF8FF) == 0xE0FF && + (mov2 & 0x07) == ((jmp>>8) & 0x07) && + (call & 0xF8FF) == 0xD0FF && + (regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]])) + { + ((unsigned long *)regs)[trans[mov1 & 0x07]] = addr1; + ((unsigned long *)regs)[trans[mov2 & 0x07]] = addr2; + regs->eip = addr2; + return 4; + } + } + } + } + + { /* PaX: gcc trampoline emulation #2 */ + unsigned char mov, jmp; + unsigned long addr1, addr2, ret; + + err = __get_user(mov, (unsigned char *)(regs->eip)); + err |= __get_user(addr1, (unsigned long *)(regs->eip + 1)); + err |= __get_user(jmp, (unsigned char *)(regs->eip + 5)); + err |= __get_user(addr2, (unsigned long *)(regs->eip + 6)); + err |= __get_user(ret, (unsigned long *)(regs->esp)); + + if (!err) { + unsigned short call; + + err = __get_user(call, (unsigned short *)(ret-2)); + if (!err) { + if ((mov & 0xF8) == 0xB8 && + jmp == 0xE9 && + (call & 0xF8FF) == 0xD0FF && + (regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]])) + { + ((unsigned long *)regs)[trans[mov & 0x07]] = addr1; + regs->eip += addr2 + 10; + return 4; + } + } + } + } +#endif + + return 1; /* PaX in action */ +} + +static int pax_handle_opcode(struct task_struct *tsk, struct pt_regs *regs) +{ + unsigned long opsize = 1; + unsigned long opsize_override = 0; + unsigned long i; + + if (regs->eflags & TF_MASK) + tsk->ptrace |= PT_PAX_OLDTF; + else + tsk->ptrace &= ~PT_PAX_OLDTF; + tsk->ptrace &= ~PT_PAX_KEEPTF; + + for (i=0; i<15; i++) { + unsigned char opcode; + if (__get_user(opcode, (unsigned char*)(regs->eip+i))) + break; + switch (opcode) { + case 0x26: + case 0x2E: + case 0x36: + case 0x3E: + case 0x64: + case 0x65: + case 0x67: + case 0xF0: + case 0xF2: + case 0xF3: + break; + + case 0x66: + opsize_override = 1; + break; + + case 0x9C: /* PUSHF */ + if (opsize ^ opsize_override) { + __put_user(regs->eflags & 0x00FCFFFFul, (unsigned long*)(regs->esp-4)); + regs->esp -= 4; + } else { + __put_user(regs->eflags, (unsigned short*)(regs->esp-2)); + regs->esp -= 2; + } + regs->eip += i + 1; + return 1; + + case 0x9D: /* POPF */ + case 0xCF: /* IRET */ + tsk->ptrace |= PT_PAX_KEEPTF; + return 0; + + default: + return 0; + } + } + return 0; +} + +static inline void pax_handle_pte(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + pte = pax_get_pte(mm, address); + if (pte) { + set_pte(pte, pte_exprotect(*pte)); + __flush_tlb_one(address); + } +} + +#define PAX_SPIN_COUNT 256 + +void pax_handle_ptes(struct task_struct *tsk) +{ + struct mm_struct *mm; + + mm = tsk->mm; + spin_lock(&mm->page_table_lock); + switch (tsk->thread.pax_faults.count) { + default: + printk(KERN_ERR "PAX: wtf: %s:%d, %ld\n", tsk->comm, tsk->pid, tsk->thread.pax_faults.count); + break; + + case PAX_SPIN_COUNT+4: + pax_handle_pte(mm, tsk->thread.pax_faults.addresses[3]); + + case PAX_SPIN_COUNT+3: + pax_handle_pte(mm, tsk->thread.pax_faults.addresses[2]); + + case PAX_SPIN_COUNT+2: + pax_handle_pte(mm, tsk->thread.pax_faults.addresses[1]); + + case PAX_SPIN_COUNT+1: + pax_handle_pte(mm, tsk->thread.pax_faults.addresses[0]); + } + spin_unlock(&mm->page_table_lock); + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; +} + +/* + * PaX: handle the extra page faults or pass it down to the original handler + * + * returns 0 when nothing special was detected + * 1 when sigreturn trampoline (syscall) has to be emulated + */ +asmlinkage int pax_do_page_fault(struct pt_regs *regs, unsigned long error_code) +{ + struct task_struct *tsk = current; + struct mm_struct *mm = current->mm; + unsigned long address; + pte_t *pte; + unsigned char pte_mask = _PAGE_ACCESSED | _PAGE_USER; + int ret; + unsigned long i; + + __asm__("movl %%cr2,%0":"=r" (address)); + + /* It's safe to allow irq's after cr2 has been saved */ + if (regs->eflags & X86_EFLAGS_IF) + local_irq_enable(); + + if ((error_code & 5) != 5 || address >= TASK_SIZE || regs->xcs != __USER_CS || (VM_MASK & regs->eflags)) + goto chain; + + /* PaX: it's our fault, let's handle it if we can */ + + if (error_code == 7) { + pte_mask |= _PAGE_DIRTY; + /* PaX: take a look at read faults before acquiring any locks */ + } else if (regs->eip == address) { /* read/instruction fetch attempt from a protected page in user mode */ + ret = pax_handle_read_fault(regs, address); + switch (ret) { + case 4: + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + return 0; + + case 3: + case 2: + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + return 1; + + default: + case 1: { + char* buffer = (char*)__get_free_page(GFP_KERNEL); + char* path=NULL; + + if (buffer) { + struct vm_area_struct* vma; + + down_read(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { + break; + } + vma = vma->vm_next; + } + if (vma) + path = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt, buffer, PAGE_SIZE); + up_read(&mm->mmap_sem); + } + printk(KERN_ERR "PAX: terminating task: %s(%s):%d, uid/euid: %u/%u, EIP: %08lX, ESP: %08lX\n", path, tsk->comm, tsk->pid, tsk->uid, tsk->euid, regs->eip, regs->esp); + if (buffer) free_page((unsigned long)buffer); + printk(KERN_ERR "PAX: bytes at EIP: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (__get_user(c, (unsigned char*)(regs->eip+i))) { + printk("."); + break; + } + printk("%02x ", c); + } + printk("\n"); + + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + tsk->ptrace &= ~(PT_PAX_TRACE | PT_PAX_KEEPTF | PT_PAX_OLDTF); + regs->eflags &= ~TF_MASK; + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + force_sig(SIGKILL,tsk); + return 0; + } + + case 0: + } + } + + spin_lock(&mm->page_table_lock); + pte = pax_get_pte(mm, address); + if (!pte || !(pte_val(*pte) & _PAGE_PRESENT) || pte_exec(*pte)) { + spin_unlock(&mm->page_table_lock); + goto chain; + } + + if ((error_code == 7) && !pte_write(*pte)) { /* write attempt to a protected page in user mode */ + spin_unlock(&mm->page_table_lock); + goto chain; + } + + /* + * PaX: fill DTLB with user rights and retry + */ + if (regs->eip != tsk->thread.pax_faults.eip) { /* detect DTLB trashing */ + tsk->thread.pax_faults.eip = regs->eip; + tsk->thread.pax_faults.count = 0; + +pax_emu: + __asm__ __volatile__ ( + "orb %2,%1\n" + "invlpg %0\n" + "testb $0,%0\n" + "xorb %3,%1\n" + : + : "m" (*(char*)address), "m" (*(char*)pte) , "r" (pte_mask) , "i" (_PAGE_USER) + : "memory", "cc"); + spin_unlock(&mm->page_table_lock); + return 0; + } + + if (tsk->thread.pax_faults.count < PAX_SPIN_COUNT) { + ++tsk->thread.pax_faults.count; + goto pax_emu; + } + spin_unlock(&mm->page_table_lock); + + if (tsk->thread.pax_faults.count == PAX_SPIN_COUNT) { + if (pax_handle_opcode(tsk, regs)) { + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + tsk->ptrace &= ~(PT_PAX_TRACE | PT_PAX_KEEPTF | PT_PAX_OLDTF); + return 0; + } else { + ++tsk->thread.pax_faults.count; + } + } + + if (tsk->thread.pax_faults.count > PAX_SPIN_COUNT+1+3) { + printk(KERN_ERR "PAX: preventing DoS: %s:%d, EIP: %08lX, ESP: %08lX\n", tsk->comm, tsk->pid, regs->eip, regs->esp); + printk(KERN_ERR "PAX: bytes at EIP: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (__get_user(c, (unsigned char*)(regs->eip+i))) { + printk("."); + break; + } + printk("%02x ", c); + } + printk("\n"); + + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + tsk->ptrace &= ~(PT_PAX_TRACE | PT_PAX_KEEPTF | PT_PAX_OLDTF); + regs->eflags &= ~TF_MASK; + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + force_sig(SIGKILL,tsk); + return 0; + } + + spin_lock(&mm->page_table_lock); + pte = pax_get_pte(mm, address); + if (pte) { + set_pte(pte, pte_mkexec(*pte)); + __flush_tlb_one(address); + tsk->thread.pax_faults.addresses[tsk->thread.pax_faults.count-PAX_SPIN_COUNT-1] = address; + ++tsk->thread.pax_faults.count; + } + spin_unlock(&mm->page_table_lock); + tsk->ptrace |= PT_PAX_TRACE; + regs->eflags |= TF_MASK; + +#if 0 + if (tsk->thread.pax_faults.count > PAX_SPIN_COUNT+1+1) { + printk(KERN_ERR "PAX: DTLB trashing, level %ld: %s:%d," + "EIP: %08lX, ESP: %08lX, cr2: %08lX\n", + tsk->thread.pax_faults.count - (PAX_SPIN_COUNT+1), + tsk->comm, tsk->pid, regs->eip, regs->esp, address); + printk(KERN_ERR "PAX: DTLB trashing, %08lX, %08lX, %08lX\n", + tsk->thread.pax_faults.addresses[0], + tsk->thread.pax_faults.addresses[1], + tsk->thread.pax_faults.addresses[2]); + } +#endif + return 0; + +chain: + do_page_fault(regs, error_code, address); + return 0; +} +#endif + diff -urN linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- linux/arch/i386/mm/init.c Fri Dec 21 12:41:53 2001 +++ linux/arch/i386/mm/init.c Sun Jan 13 01:24:51 2002 @@ -400,7 +400,11 @@ pmd = pmd_offset(pgd, vaddr); pte = pte_offset(pmd, vaddr); old_pte = *pte; +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + *pte = mk_pte_phys(0, PAGE_READONLY_EXEC); +#else *pte = mk_pte_phys(0, PAGE_READONLY); +#endif local_flush_tlb(); boot_cpu_data.wp_works_ok = do_test_wp_bit(vaddr); diff -urN linux/arch/ia64/config.in linux/arch/ia64/config.in --- linux/arch/ia64/config.in Fri Nov 9 17:26:17 2001 +++ linux/arch/ia64/config.in Sun Jan 13 01:24:51 2002 @@ -276,3 +276,12 @@ fi endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/m68k/config.in linux/arch/m68k/config.in --- linux/arch/m68k/config.in Mon Jun 11 22:15:27 2001 +++ linux/arch/m68k/config.in Sun Jan 13 01:24:51 2002 @@ -546,3 +546,12 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/mips/config.in linux/arch/mips/config.in --- linux/arch/mips/config.in Mon Oct 15 16:41:34 2001 +++ linux/arch/mips/config.in Sun Jan 13 01:24:51 2002 @@ -520,3 +520,12 @@ bool 'Run uncached' CONFIG_MIPS_UNCACHED fi endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/mips64/config.in linux/arch/mips64/config.in --- linux/arch/mips64/config.in Sun Sep 9 13:43:02 2001 +++ linux/arch/mips64/config.in Sun Jan 13 01:24:51 2002 @@ -276,3 +276,12 @@ bool 'Run uncached' CONFIG_MIPS_UNCACHED fi endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/parisc/config.in linux/arch/parisc/config.in --- linux/arch/parisc/config.in Tue Apr 17 20:19:25 2001 +++ linux/arch/parisc/config.in Sun Jan 13 01:24:51 2002 @@ -208,3 +208,11 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/ppc/config.in linux/arch/ppc/config.in --- linux/arch/ppc/config.in Fri Nov 16 13:10:08 2001 +++ linux/arch/ppc/config.in Sun Jan 13 01:24:51 2002 @@ -393,3 +393,12 @@ bool 'Include kgdb kernel debugger' CONFIG_KGDB bool 'Include xmon kernel debugger' CONFIG_XMON endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/s390/config.in linux/arch/s390/config.in --- linux/arch/s390/config.in Fri Nov 9 16:58:02 2001 +++ linux/arch/s390/config.in Sun Jan 13 01:24:51 2002 @@ -73,3 +73,11 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/s390x/config.in linux/arch/s390x/config.in --- linux/arch/s390x/config.in Thu Oct 11 12:04:57 2001 +++ linux/arch/s390x/config.in Sun Jan 13 01:24:51 2002 @@ -77,3 +77,11 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/sh/config.in linux/arch/sh/config.in --- linux/arch/sh/config.in Mon Oct 15 16:36:48 2001 +++ linux/arch/sh/config.in Sun Jan 13 01:24:51 2002 @@ -386,3 +386,12 @@ bool 'Early printk support' CONFIG_SH_EARLY_PRINTK fi endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/sparc/config.in linux/arch/sparc/config.in --- linux/arch/sparc/config.in Mon Jun 11 22:15:27 2001 +++ linux/arch/sparc/config.in Sun Jan 13 01:24:51 2002 @@ -266,3 +266,12 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- linux/arch/sparc64/config.in Fri Dec 21 12:41:53 2001 +++ linux/arch/sparc64/config.in Sun Jan 13 01:24:51 2002 @@ -306,3 +306,12 @@ fi endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -urN linux/drivers/char/mem.c linux/drivers/char/mem.c --- linux/drivers/char/mem.c Fri Dec 21 12:41:54 2001 +++ linux/drivers/char/mem.c Fri Jan 18 16:40:05 2002 @@ -25,6 +25,9 @@ #include #include #include +#ifdef CONFIG_GRKERNSEC_KMEM +#include +#endif #ifdef CONFIG_I2C extern int i2c_init_all(void); @@ -46,6 +49,14 @@ const char * buf, size_t count, loff_t *ppos) { ssize_t written; +#ifdef CONFIG_GRKERNSEC_KMEM + if(grsec_enable_kmem) { + security_alert("attempted write to read-only kernel memory by " + DEFAULTSECMSG, "attempted kernel writes", + DEFAULTSECARGS); + return -EPERM; + } +#endif written = 0; #if defined(__sparc__) || defined(__mc68000__) @@ -200,9 +211,21 @@ /* * Don't dump addresses that are not real memory to a core file. */ +#ifdef CONFIG_GRKERNSEC_PAX + if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) { +#else if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) +#endif vma->vm_flags |= VM_IO; +#ifdef CONFIG_GRKERNSEC_PAX + /* it turned out to be device memory (eg. video RAM), don't apply PaX */ + if ((current->flags & PF_PAX_PAGEEXEC) &&!(vma->vm_flags & VM_EXEC)) { + vma->vm_flags |= VM_EXEC | VM_MAYEXEC; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f]; + } + } +#endif if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start, vma->vm_page_prot)) return -EAGAIN; @@ -291,7 +314,9 @@ wrote = (unsigned long) high_memory - p; wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos); - +#ifdef CONFIG_GRKERNSEC_KMEM + if(grsec_enable_kmem && (wrote == -EPERM)) return -EPERM; +#endif p += wrote; buf += wrote; count -= wrote; @@ -401,8 +426,12 @@ count = size; zap_page_range(mm, addr, count); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + zeromap_page_range(addr, count, vma->vm_page_prot); +#else zeromap_page_range(addr, count, PAGE_COPY); +#endif size -= count; buf += count; addr += count; diff -urN linux/drivers/char/random.c linux/drivers/char/random.c --- linux/drivers/char/random.c Fri Nov 9 17:01:21 2001 +++ linux/drivers/char/random.c Sun Jan 13 01:24:51 2002 @@ -260,6 +260,12 @@ /* * Configuration information */ +#ifdef CONFIG_GRKERNSEC_RANDNET +#include +#define DEFAULT_POOL_SIZE_RANDNET 4096 +#define SECONDARY_POOL_SIZE_RANDNET 1024 +#define BATCH_ENTROPY_SIZE_RANDNET 2048 +#endif #define DEFAULT_POOL_SIZE 512 #define SECONDARY_POOL_SIZE 128 #define BATCH_ENTROPY_SIZE 256 @@ -387,8 +393,13 @@ /* * Static global variables */ +#ifdef CONFIG_GRKERNSEC_RANDPID +struct entropy_store *random_state; /* The default global store */ +struct entropy_store *sec_random_state; /* secondary store */ +#else static struct entropy_store *random_state; /* The default global store */ static struct entropy_store *sec_random_state; /* secondary store */ +#endif static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); @@ -1433,11 +1444,23 @@ { int i; - if (create_entropy_store(DEFAULT_POOL_SIZE, &random_state)) + if (create_entropy_store( +#ifdef CONFIG_GRKERNSEC_RANDNET + grsec_enable_randnet?DEFAULT_POOL_SIZE_RANDNET: +#endif + DEFAULT_POOL_SIZE, &random_state)) return; /* Error, return */ - if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state)) + if (batch_entropy_init( +#ifdef CONFIG_GRKERNSEC_RANDNET + grsec_enable_randnet?BATCH_ENTROPY_SIZE_RANDNET: +#endif + BATCH_ENTROPY_SIZE, random_state)) return; /* Error, return */ - if (create_entropy_store(SECONDARY_POOL_SIZE, &sec_random_state)) + if (create_entropy_store( +#ifdef CONFIG_GRKERNSEC_RANDNET + grsec_enable_randnet?SECONDARY_POOL_SIZE_RANDNET: +#endif + SECONDARY_POOL_SIZE, &sec_random_state)) return; /* Error, return */ clear_entropy_store(random_state); clear_entropy_store(sec_random_state); diff -urN linux/drivers/char/vt.c linux/drivers/char/vt.c --- linux/drivers/char/vt.c Fri Nov 16 13:08:28 2001 +++ linux/drivers/char/vt.c Sun Jan 13 01:24:51 2002 @@ -37,6 +37,10 @@ #include #endif /* CONFIG_FB_COMPAT_XPMAC */ +#ifdef CONFIG_GRKERNSEC_KBMAP +#include +#endif + char vt_dont_switch; extern struct tty_driver console_driver; @@ -177,7 +181,11 @@ val = (i ? K_HOLE : K_NOSUCHMAP); return put_user(val, &user_kbe->kb_value); case KDSKBENT: +#ifdef CONFIG_GRKERNSEC_KBMAP + if (!perm || (grsec_enable_kbmap && !suser())) +#else if (!perm) +#endif return -EPERM; if (!i && v == K_NOSUCHMAP) { /* disallocate map */ @@ -298,7 +306,11 @@ return -EFAULT; return ((p && *p) ? -EOVERFLOW : 0); case KDSKBSENT: +#ifdef CONFIG_GRKERNSEC_KBMAP + if (!perm || (grsec_enable_kbmap && !suser())) +#else if (!perm) +#endif return -EPERM; q = func_table[i]; diff -urN linux/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c --- linux/drivers/ieee1394/video1394.c Fri Dec 21 12:41:54 2001 +++ linux/drivers/ieee1394/video1394.c Sun Jan 13 01:24:51 2002 @@ -843,7 +843,11 @@ pos=(unsigned long) d->buf; while (size > 0) { page = kvirt_to_pa(pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start+=PAGE_SIZE; pos+=PAGE_SIZE; diff -urN linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c --- linux/drivers/media/video/bttv-driver.c Fri Dec 21 12:41:54 2001 +++ linux/drivers/media/video/bttv-driver.c Sun Jan 13 01:24:51 2002 @@ -2052,7 +2052,11 @@ pos=(unsigned long) btv->fbuffer; while (size > 0) { page = kvirt_to_pa(pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start+=PAGE_SIZE; pos+=PAGE_SIZE; diff -urN linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c --- linux/drivers/media/video/cpia.c Thu Oct 25 16:53:47 2001 +++ linux/drivers/media/video/cpia.c Sun Jan 13 01:24:51 2002 @@ -3005,7 +3005,11 @@ pos = (unsigned long)(cam->frame_buf); while (size > 0) { page = kvirt_to_pa(pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) { +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { +#endif up(&cam->busy_lock); return -EAGAIN; } diff -urN linux/drivers/media/video/meye.c linux/drivers/media/video/meye.c --- linux/drivers/media/video/meye.c Fri Dec 21 12:41:54 2001 +++ linux/drivers/media/video/meye.c Sun Jan 13 01:24:51 2002 @@ -1263,7 +1263,11 @@ while (size > 0) { page = kvirt_to_pa(pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) { +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { +#endif up(&meye.lock); return -EAGAIN; } diff -urN linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c --- linux/drivers/media/video/planb.c Thu Oct 25 16:53:47 2001 +++ linux/drivers/media/video/planb.c Sun Jan 13 01:24:51 2002 @@ -2009,7 +2009,11 @@ } for (i = 0; i < pb->rawbuf_size; i++) { if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]), +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + PAGE_SIZE, PAGE_SHARED_EXEC)) +#else PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; if (size <= PAGE_SIZE) diff -urN linux/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c --- linux/drivers/media/video/zr36067.c Fri Nov 9 17:01:22 2001 +++ linux/drivers/media/video/zr36067.c Sun Jan 13 01:24:51 2002 @@ -4322,7 +4322,11 @@ frag_tab[2 * j]; page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ if (remap_page_range +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + (start, page, todo, PAGE_SHARED_EXEC)) { +#else (start, page, todo, PAGE_SHARED)) { +#endif printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); @@ -4363,7 +4367,11 @@ ("V4L remap page range %d 0x%lx %ld to 0x%lx\n", i, page, todo, start)); if (remap_page_range +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + (start, page, todo, PAGE_SHARED_EXEC)) { +#else (start, page, todo, PAGE_SHARED)) { +#endif printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); diff -urN linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c --- linux/drivers/media/video/zr36120.c Fri Nov 9 17:01:22 2001 +++ linux/drivers/media/video/zr36120.c Sun Jan 13 01:24:51 2002 @@ -1484,7 +1484,11 @@ pos = (unsigned long)ztv->fbuffer; while (size>0) { unsigned long page = virt_to_phys((void*)pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; diff -urN linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- linux/drivers/usb/ov511.c Fri Sep 14 17:04:07 2001 +++ linux/drivers/usb/ov511.c Sun Jan 13 01:24:51 2002 @@ -2769,7 +2769,11 @@ pos = (unsigned long)ov511->fbuf; while (size > 0) { page = kvirt_to_pa(pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; diff -urN linux/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c --- linux/drivers/usb/pwc-if.c Fri Dec 21 12:41:55 2001 +++ linux/drivers/usb/pwc-if.c Sun Jan 13 01:24:51 2002 @@ -1581,7 +1581,11 @@ pos = (unsigned long)pdev->image_data; while (size > 0) { page = kvirt_to_pa(pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; diff -urN linux/drivers/usb/se401.c linux/drivers/usb/se401.c --- linux/drivers/usb/se401.c Fri Sep 14 17:27:10 2001 +++ linux/drivers/usb/se401.c Sun Jan 13 01:24:51 2002 @@ -1374,7 +1374,11 @@ pos = (unsigned long)se401->fbuf; while (size > 0) { page = kvirt_to_pa(pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) { +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { +#endif up(&se401->lock); return -EAGAIN; } diff -urN linux/drivers/usb/usbvideo.c linux/drivers/usb/usbvideo.c --- linux/drivers/usb/usbvideo.c Thu Oct 11 02:42:46 2001 +++ linux/drivers/usb/usbvideo.c Sun Jan 13 01:24:51 2002 @@ -1199,7 +1199,11 @@ pos = (unsigned long) uvd->fbuf; while (size > 0) { page = usbvideo_kvirt_to_pa(pos); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; diff -urN linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- linux/fs/binfmt_aout.c Fri Nov 2 20:39:20 2001 +++ linux/fs/binfmt_aout.c Sun Jan 13 01:24:51 2002 @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -307,6 +308,25 @@ current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; +#ifdef CONFIG_GRKERNSEC_STACK + if (N_FLAGS(ex) & F_STACKEXEC) current->flags |= PF_STACKEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX + if (!(N_FLAGS(ex) & F_PAX_PAGEEXEC)) + current->flags |= PF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + if (N_FLAGS(ex) & F_PAX_EMUTRAMP) + current->flags |= PF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_MPROTECT + if (!(N_FLAGS(ex) & F_PAX_MPROTECT)) + current->flags |= PF_PAX_MPROTECT; +#endif + #ifdef __sparc__ if (N_MAGIC(ex) == NMAGIC) { loff_t pos = fd_offset; @@ -393,7 +413,11 @@ down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + PROT_READ | PROT_WRITE, +#else PROT_READ | PROT_WRITE | PROT_EXEC, +#endif MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); up_write(¤t->mm->mmap_sem); diff -urN linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- linux/fs/binfmt_elf.c Fri Dec 21 12:41:55 2001 +++ linux/fs/binfmt_elf.c Sun Jan 13 01:24:51 2002 @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -33,6 +34,9 @@ #include #include #include +#if defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) || defined(CONFIG_GRKERNSEC_PAX) +#include +#endif #include #include @@ -73,7 +77,10 @@ #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) -static struct linux_binfmt elf_format = { +#ifndef CONFIG_GRKERNSEC_STACK +static +#endif +struct linux_binfmt elf_format = { NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE }; @@ -138,6 +145,11 @@ } else u_platform = p; +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if (current->flags & PF_PAX_RANDMMAP) + u_platform -= (current->mm->delta_stack & ~PAGE_MASK); +#endif + /* * Force 16 byte _final_ alignment here for generality. */ @@ -599,7 +611,49 @@ current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + current->mm->delta_mmap = 0; + current->mm->delta_exec = 0; + current->mm->delta_stack = 0; +#endif current->flags &= ~PF_FORKNOEXEC; + +#ifdef CONFIG_GRKERNSEC_STACK + if (elf_ex.e_flags & EF_STACKEXEC) + current->flags |= PF_STACKEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX + if (!(elf_ex.e_flags & EF_PAX_PAGEEXEC)) + current->flags |= PF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + if (elf_ex.e_flags & EF_PAX_EMUTRAMP) + current->flags |= PF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_MPROTECT + if (!(elf_ex.e_flags & EF_PAX_MPROTECT)) + current->flags |= PF_PAX_MPROTECT; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if (!(elf_ex.e_flags & EF_PAX_RANDMMAP)) { + unsigned short delta; + current->flags |= PF_PAX_RANDMMAP; + + get_random_bytes(&delta, sizeof(delta)); + current->mm->delta_mmap = (unsigned long)delta << PAGE_SHIFT; + + get_random_bytes(&delta, sizeof(delta)); + current->mm->delta_exec = (unsigned long)delta << PAGE_SHIFT; + + get_random_bytes(&delta, sizeof(delta)); + current->mm->delta_stack = (unsigned long)delta << 4; + } +#endif + elf_entry = (unsigned long) elf_ex.e_entry; /* Do this immediately, since STACK_TOP as used in setup_arg_pages @@ -654,6 +708,13 @@ base, as well as whatever program they might try to exec. This is because the brk will follow the loader, and is not movable. */ load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + /* PaX: randomize base address at the default exe base if requested */ + if (current->flags | PF_PAX_RANDMMAP) { + load_bias = ELF_PAGESTART(0x08048000 - vaddr + current->mm->delta_exec); + } +#endif + } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); diff -urN linux/fs/devices.c linux/fs/devices.c --- linux/fs/devices.c Sat Sep 22 23:35:43 2001 +++ linux/fs/devices.c Sun Jan 13 01:24:51 2002 @@ -162,7 +162,11 @@ * is contain the open that then fills in the correct operations * depending on the special file... */ -static struct file_operations def_chr_fops = { + +#ifndef CONFIG_GRKERNSEC_FD +static +#endif +struct file_operations def_chr_fops = { open: chrdev_open, }; diff -urN linux/fs/exec.c linux/fs/exec.c --- linux/fs/exec.c Fri Dec 21 12:41:55 2001 +++ linux/fs/exec.c Thu Jan 17 17:00:54 2002 @@ -48,6 +48,19 @@ int core_uses_pid; +#if defined(CONFIG_GRKERNSEC_FD) || defined(CONFIG_GRKERNSEC_EXECVE) ||\ + defined(CONFIG_GRKERNSEC_COREDUMP)||defined(CONFIG_GRKERNSEC_TPE) ||\ + defined(CONFIG_GRKERNSEC_CHROOT_EXECLOG) || \ + defined(CONFIG_GRKERNSEC_EXECLOG) ||\ + defined(CONFIG_GRKERNSEC_PTRACE) || defined(CONFIG_GRKERNSEC_ACL) +#include +#endif + +#ifdef CONFIG_GRKERNSEC_FD +#include +extern struct file_operations def_chr_fops; +#endif + static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; @@ -278,7 +291,12 @@ lru_cache_add(page); flush_dcache_page(page); flush_page_to_ram(page); +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, + (tsk->flags & PF_PAX_PAGEEXEC)?PAGE_COPY_NOEXEC:PAGE_COPY_EXEC)))); +#else set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY)))); +#endif tsk->mm->rss++; spin_unlock(&tsk->mm->page_table_lock); @@ -299,6 +317,12 @@ stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if (current->flags & PF_PAX_RANDMMAP) + stack_base = PAGE_MASK & (stack_base - current->mm->delta_stack); + +#endif + bprm->p += stack_base; if (bprm->loader) bprm->loader += stack_base; @@ -312,9 +336,15 @@ { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; +#if defined(CONFIG_GRKERNSEC_PAX) || defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) + mpnt->vm_end = stack_base + MAX_ARG_PAGES*PAGE_SIZE; + mpnt->vm_page_prot = (current->flags & PF_PAX_PAGEEXEC)?PAGE_COPY_NOEXEC:PAGE_COPY_EXEC; + mpnt->vm_flags = (current->flags & PF_PAX_PAGEEXEC)?VM_STACK_FLAGS:(VM_STACK_FLAGS|VM_EXEC|VM_MAYEXEC); +#else mpnt->vm_end = STACK_TOP; mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; +#endif mpnt->vm_ops = NULL; mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; @@ -473,6 +503,69 @@ if (atomic_dec_and_test(&oldsig->count)) kmem_cache_free(sigact_cachep, oldsig); } +#ifdef CONFIG_GRKERNSEC_FD +static inline int tweak_fd_open_null(struct linux_binprm *bprm) +{ + struct inode *i; + struct dentry *d; + struct file *f; + + if(!(i = get_empty_inode())) + return -ENOMEM; + if(!(d = dget(d_alloc_root(i)))) { + iput(i); + return -ENOMEM; + } + if(!(f = get_empty_filp())) { + dput(d); + iput(i); + return -ENFILE; + } + i->i_mode = S_IFCHR | S_IRUGO | S_IWUGO; + i->i_uid = current->fsuid; + i->i_gid = current->fsgid; + i->i_rdev = MKDEV(MEM_MAJOR,3); + i->i_blksize = PAGE_SIZE; + i->i_blocks = 0; + i->i_atime = i->i_mtime = i->i_ctime = CURRENT_TIME; + i->i_fop = &def_chr_fops; + i->i_state = I_DIRTY; + + f->f_flags = O_RDWR; + f->f_mode = FMODE_READ | FMODE_WRITE; + f->f_dentry = d; + f->f_op = i->i_fop; + f->f_pos = 0; + f->f_reada = 0; + f->f_op->open(i,f); + + bprm->tweak_fd_null = f; + + return 0; +} + +static int tweak_fd_0_1_2(struct linux_binprm *bprm) +{ + int fd,new,retval; + + for(fd=0;fd<=2;fd++) { + if(current->files->fd[fd]) continue; + if((new = get_unused_fd()) != fd) { + if(new >= 0) put_unused_fd(new); + return -EMFILE; + } + if(bprm->tweak_fd_null) + atomic_inc(&bprm->tweak_fd_null->f_count); + else + if((retval = tweak_fd_open_null(bprm))) + return retval; + + fd_install(fd,bprm->tweak_fd_null); + bprm->tweak_fd_mask |= 1 << fd; + } + return 0; +} +#endif /* * These functions flushes out all traces of the currently running executable @@ -563,6 +656,25 @@ current->comm[i++] = ch; } current->comm[i] = '\0'; +#ifdef CONFIG_GRKERNSEC_STACK + current->flags &= ~PF_STACKEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX + current->flags &= ~PF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + current->flags &= ~PF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_MPROTECT + current->flags &= ~PF_PAX_MPROTECT; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + current->flags &= ~PF_PAX_RANDMMAP; +#endif flush_thread(); @@ -580,6 +692,10 @@ flush_signal_handlers(current); flush_old_files(current->files); +#ifdef CONFIG_GRKERNSEC_FD + if(grsec_enable_fd) + return tweak_fd_0_1_2(bprm); +#endif return 0; mmap_failed: @@ -626,8 +742,8 @@ if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) { /* Set-uid? */ - if (mode & S_ISUID) - bprm->e_uid = inode->i_uid; + if (mode & S_ISUID) + bprm->e_uid = inode->i_uid; /* Set-gid? */ /* @@ -635,9 +751,9 @@ * is a candidate for mandatory locking, not a setgid * executable. */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) - bprm->e_gid = inode->i_gid; - } + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) + bprm->e_gid = inode->i_gid; +} /* We don't have VFS support for capabilities yet */ cap_clear(bprm->cap_inheritable); @@ -660,7 +776,26 @@ if (bprm->e_uid == 0) cap_set_full(bprm->cap_effective); } - +#ifdef CONFIG_GRKERNSEC_PTRACE + if (current->ptrace & PT_PTRACED){ + if(current->uid && grsec_enable_ptrace +#ifdef CONFIG_GRKERNSEC_PTRACE_GROUP + && ((grsec_enable_ptrace_group && !in_group_p(grsec_ptrace_gid)) + || !grsec_enable_ptrace_group) +#endif + ) { + security_alert("denied ptrace of [%.32s:%lu] (%s) by " DEFAULTSECMSG, + "denied ptraces", kdevname(bprm->file->f_dentry->d_inode->i_dev), + bprm->file->f_dentry->d_inode->i_ino, bprm->filename, + DEFAULTSECARGS); + return -EPERM; + } + security_alert("ptrace of [%.32s:%lu] (%s) by " DEFAULTSECMSG, + "ptraces", kdevname(bprm->file->f_dentry->d_inode->i_dev), + bprm->file->f_dentry->d_inode->i_ino, bprm->filename, + DEFAULTSECARGS); + } +#endif memset(bprm->buf,0,BINPRM_BUF_SIZE); return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); } @@ -708,6 +843,9 @@ current->cap_permitted); } } +#ifdef CONFIG_GRKERNSEC_FD + if (grsec_enable_fd) tweak_fd_0_1_2(bprm); +#endif do_unlock = 1; } @@ -859,6 +997,20 @@ struct file *file; int retval; int i; +#if defined(CONFIG_GRKERNSEC_EXECLOG) || defined(CONFIG_GRKERNSEC_EXECLOG_GROUP) + int x; + char *grargs; + char grarg[68]; +#endif + +#ifdef CONFIG_GRKERNSEC_EXECVE + if(grsec_enable_execve && current->user) + if(atomic_read(¤t->user->processes) > current->rlim[RLIMIT_NPROC].rlim_cur) { + security_alert("Attempt to overstep process limit by " DEFAULTSECMSG, + "proc limit overstep", DEFAULTSECARGS); + return -EAGAIN; + } +#endif file = open_exec(filename); @@ -866,6 +1018,16 @@ if (IS_ERR(file)) return retval; +#ifdef CONFIG_GRKERNSEC_ACL +if( ( (gr_search(file->f_dentry,GR_EXEC,file->f_vfsmnt)) == GR_DENY) ) { + security_alert("denying execution of %.1024s by " DEFAULTSECMSG, + "file exec attempts", filename, DEFAULTSECARGS); + allow_write_access(file); + fput(file); + return -EPERM; +} +#endif + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); @@ -886,10 +1048,111 @@ return bprm.envc; } +#ifdef CONFIG_GRKERNSEC_FD + if (grsec_enable_fd) { + bprm.tweak_fd_mask = 0; + bprm.tweak_fd_null = NULL; + } +#endif retval = prepare_binprm(&bprm); if (retval < 0) goto out; + +#ifdef CONFIG_GRKERNSEC_TPE +if (grsec_enable_tpe) { +#ifdef CONFIG_GRKERNSEC_TPE_GLIBC +if (grsec_enable_tpe_glibc) { +#ifdef CONFIG_GRKERNSEC_TPE_ALL +if(grsec_enable_tpe_all?current->uid:in_group_p(grsec_tpe_gid)){ +#else +if(in_group_p(grsec_tpe_gid)){ +#endif + char **envpp=envp,*envpt; + while(*envpp){ + envpt=*envpp; + if((*envpt == 'L') && (*(envpt + 1) == 'D') && + (*(envpt + 2) == '_') && strchr(envpt,'=')){ + security_alert("denied exec of %.32s by " DEFAULTSECMSG + "reason: malicious environment","denied execs", + filename, DEFAULTSECARGS); + dput(file->f_dentry); + return -EACCES; + } + *envpp=*++envpp; + } + if(!strncmp(file->f_dentry->d_name.name,"ld-2.",5) && + !strncmp(file->f_dentry->d_parent->d_name.name,"lib",3)){ + security_alert("denied exec of %.32s by " DEFAULTSECMSG + "reason: tried to bypass via ld","denied execs", + filename, DEFAULTSECARGS); + dput(file->f_dentry); + return -EACCES; + } +} +} +#endif +if((current->uid) && + ((file->f_dentry->d_parent->d_inode->i_uid) || + (!(file->f_dentry->d_parent->d_inode->i_uid) && + ((file->f_dentry->d_parent->d_inode->i_mode & S_IWGRP) || + (file->f_dentry->d_parent->d_inode->i_mode & S_IWOTH)))) && + (in_group_p(grsec_tpe_gid))){ + security_alert("denied exec of %.32s by " DEFAULTSECMSG + "reason: untrusted","denied execs", + filename, DEFAULTSECARGS); + dput(file->f_dentry); + return -EACCES; +} +#ifdef CONFIG_GRKERNSEC_TPE_ALL +else if(grsec_enable_tpe_all && + (current->uid) && !(((!(file->f_dentry->d_parent->d_inode->i_uid) && + !(file->f_dentry->d_parent->d_inode->i_mode & S_IWGRP) && + !(file->f_dentry->d_parent->d_inode->i_mode & S_IWOTH)) || + ((file->f_dentry->d_parent->d_inode->i_uid == current->uid) && + !(file->f_dentry->d_parent->d_inode->i_mode & S_IWGRP) && + !(file->f_dentry->d_parent->d_inode->i_mode & S_IWOTH))))){ + security_alert("denied exec of %.32s by " DEFAULTSECMSG + "reason: untrusted","denied execs", + filename, DEFAULTSECARGS); + dput(file->f_dentry); + return -EACCES; +} +#endif +} +#endif + +#ifdef CONFIG_GRKERNSEC_CHROOT_EXECLOG + if(grsec_enable_chroot_execlog && proc_is_chrooted(current)) { + printk(KERN_INFO "grsec: exec of %.64s within chroot " + "jail (%.32s:%lu) by process " DEFAULTSECMSG "\n", + filename,kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino, + DEFAULTSECARGS); + } +#endif + +#if defined(CONFIG_GRKERNSEC_EXECLOG) || defined(CONFIG_GRKERNSEC_EXECLOG_GROUP) +#ifdef CONFIG_GRKERNSEC_AUDIT_GROUP + if (in_group_p(grsec_audit_gid) && grsec_enable_group) { +#else + if (grsec_enable_execlog) { +#endif + for(x=0;xf_dentry->d_inode->i_dev), + file->f_dentry->d_inode->i_ino, grarg, DEFAULTSECARGS); + } +#endif + retval = copy_strings_kernel(1, &bprm.filename, &bprm); if (retval < 0) goto out; @@ -904,9 +1167,20 @@ goto out; retval = search_binary_handler(&bprm,regs); - if (retval >= 0) + if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC_ACL + if(gr_set_proc_acl(file->f_dentry,current,filename,file->f_vfsmnt)) { + security_alert("could not set acl for %ld %d", + "acl set failures", + file->f_dentry->d_inode->i_ino, + file->f_dentry->d_inode->i_dev); + goto out; + } +#endif + /* execve success */ return retval; + } out: /* Something went wrong, return the inode and free the argument pages*/ @@ -920,6 +1194,13 @@ __free_page(page); } +#ifdef CONFIG_GRKERNSEC_FD + if(grsec_enable_fd && bprm.tweak_fd_mask) { + for(i=0;i<=2;i++) + if(bprm.tweak_fd_mask & (1 << i)) + (void)sys_close(i); + } +#endif return retval; } @@ -952,7 +1233,14 @@ goto fail; memcpy(corename,"core.", 5); +#ifdef CONFIG_GRKERNSEC_COREDUMP + if(grsec_enable_coredump) + memcpy(corename+5,current->comm,sizeof(current->comm)); + else + corename[4] = '\0'; +#else corename[4] = '\0'; +#endif if (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1) sprintf(&corename[4], ".%d", current->pid); file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600); @@ -970,7 +1258,11 @@ goto close_fail; if (!file->f_op->write) goto close_fail; +#ifdef CONFIG_GRKERNSEC_ACL + if (do_truncate(file->f_dentry, 0, file->f_vfsmnt) != 0) +#else if (do_truncate(file->f_dentry, 0) != 0) +#endif goto close_fail; retval = binfmt->core_dump(signr, regs, file); diff -urN linux/fs/namei.c linux/fs/namei.c --- linux/fs/namei.c Wed Oct 17 17:46:29 2001 +++ linux/fs/namei.c Sat Jan 19 02:50:42 2002 @@ -26,6 +26,11 @@ #include #include +#if defined(CONFIG_GRKERNSEC_LINK) || defined(CONFIG_GRKERNSEC_FIFO) ||\ + defined(CONFIG_GRKERNSEC_CHROOT_MKNOD) || defined(CONFIG_GRKERNSEC_ACL) +#include +#endif + #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) /* [Feb-1997 T. Schoebel-Theuer] @@ -342,6 +347,27 @@ current->state = TASK_RUNNING; schedule(); } + +#ifdef CONFIG_GRKERNSEC_LINK + if(grsec_enable_link && S_ISLNK(dentry->d_inode->i_mode) && + (dentry->d_parent->d_inode->i_mode & S_ISVTX) && + dentry->d_parent->d_inode->i_uid != dentry->d_inode->i_uid && + (dentry->d_parent->d_inode->i_mode & S_IWOTH) && + current->fsuid != dentry->d_inode->i_uid) { + security_alert("not following symlink (%.30s/%.30s) of [%.32s]:%lu owned by %d.%d " + "by " DEFAULTSECMSG,"symlinks not followed", + dentry->d_parent->d_name.name, + dentry->d_name.name, + kdevname(dentry->d_inode->i_dev), + dentry->d_inode->i_ino, + dentry->d_inode->i_uid, + dentry->d_inode->i_gid, + DEFAULTSECARGS); + path_release(nd); + return -EACCES; + } +#endif + current->link_count++; current->total_link_count++; UPDATE_ATIME(dentry->d_inode); @@ -625,6 +651,22 @@ else if (this.len == 2 && this.name[1] == '.') nd->last_type = LAST_DOTDOT; return_base: +#ifdef CONFIG_GRKERNSEC_ACL + if(nd->dentry && !(IS_ERR(nd->dentry))) + if( ( (gr_check_hidden(nd->dentry,nd->mnt)) == GR_DENY) ) { + security_alert("attempt to access hidden file " + "with inode %ld dev %d by " + DEFAULTSECMSG, + "hidden file access attempts", + nd->dentry->d_inode->i_ino, + nd->dentry->d_inode->i_dev, DEFAULTSECARGS); + err = -ENOENT; /*Fake that its not there*/ + dput(dentry); + path_release(nd); + goto return_err; + } +#endif + return 0; out_dput: dput(dentry); @@ -976,6 +1018,52 @@ struct dentry *dentry; struct dentry *dir; int count = 0; +#ifdef CONFIG_GRKERNSEC_ACL + int tmp; + if(flag & GR_NONEXISTANT) { + flag &= ~GR_NONEXISTANT; + if(path_init(pathname,lookup_flags(flag)|LOOKUP_PARENT,nd)) + error = path_walk(pathname,nd); + if(error) return error; + } else { + if(path_init(pathname,lookup_flags(flag),nd)) + error = path_walk(pathname,nd); + if(error) return error; + } + if( (tmp = (flag&O_ACCMODE)) > 0) { + if(tmp & FMODE_READ ) { + if( (gr_search(nd->dentry,GR_READ,nd->mnt)) == GR_DENY) { + security_alert("attempt to open %.1024s read-only " + "by " DEFAULTSECMSG, + "file open attempts", pathname, DEFAULTSECARGS); + error = -EPERM; + goto exit; + } + } + else if(flag & O_APPEND) { + if( (gr_search(nd->dentry,GR_APPEND,nd->mnt)) == GR_DENY) { + security_alert("attempt to open %.1024s " + "append-only by " DEFAULTSECMSG , + "file open attempts", + pathname, DEFAULTSECARGS); + error = -EPERM; + goto exit; + } + } + if(tmp & FMODE_WRITE && (!(flag & O_APPEND))) { /* its write*/ + if( ( (gr_search(nd->dentry,GR_WRITE,nd->mnt)) == GR_DENY) ) { + security_alert("attempt to open %.1024s " + "for writing by " DEFAULTSECMSG, + "file open attempts", + pathname, DEFAULTSECARGS); + error = -EPERM; + goto exit; + } + } + } + path_release(nd); +#endif + acc_mode = ACC_MODE(flag); @@ -1083,6 +1171,22 @@ * actually live on the filesystem itself, and as such you * can write to them even if the filesystem is read-only. */ +#ifdef CONFIG_GRKERNSEC_FIFO + if (grsec_enable_fifo && + S_ISFIFO(inode->i_mode) && !(flag & O_EXCL) && + (dentry->d_parent->d_inode->i_mode & S_ISVTX) && + inode->i_uid != dentry->d_parent->d_inode->i_uid && + current->fsuid != inode->i_uid) { + if (!permission(inode, acc_mode)) + security_alert("denied writing FIFO (%.32s/%.32s) of %d.%d " + "by " DEFAULTSECMSG, + "writes into a FIFO denied",dentry->d_parent->d_name.name,dentry->d_name.name, + inode->i_uid, inode->i_gid, + DEFAULTSECARGS); + error = -EACCES; + goto exit_dput; + } +#endif if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { flag &= ~O_TRUNC; } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { @@ -1126,7 +1230,11 @@ if (!error) { DQUOT_INIT(inode); +#ifdef CONFIG_GRKERNSEC_ACL + error = do_truncate(dentry,0,nd->mnt); +#else error = do_truncate(dentry, 0); +#endif } put_write_access(inode); if (error) @@ -1157,6 +1265,24 @@ * stored in nd->last.name and we will have to putname() it when we * are done. Procfs-like symlinks just set LAST_BIND. */ +#ifdef CONFIG_GRKERNSEC_LINK + if(grsec_enable_link && S_ISLNK(dentry->d_inode->i_mode) && + (dentry->d_parent->d_inode->i_mode & S_ISVTX) && + dentry->d_parent->d_inode->i_uid != dentry->d_inode->i_uid && + (dentry->d_parent->d_inode->i_mode & S_IWOTH) && + current->fsuid != dentry->d_inode->i_uid) { + security_alert("not following symlink (%.30s/%.30s) [%.32s]:%lu of %d.%d " + "by " DEFAULTSECMSG,"symlinks not followed", + dentry->d_parent->d_name.name, dentry->d_name.name, + kdevname(dentry->d_inode->i_dev), + dentry->d_inode->i_ino, dentry->d_inode->i_uid, + dentry->d_inode->i_gid, + DEFAULTSECARGS); + error = -EACCES; + goto exit_dput; + } +#endif + UPDATE_ATIME(dentry->d_inode); error = dentry->d_inode->i_op->follow_link(dentry, nd); dput(dentry); @@ -1241,6 +1367,9 @@ struct dentry * dentry; struct nameidata nd; +#ifdef CONFIG_GRKERNSEC_CHROOT_MKNOD + char grdevmode; +#endif if (S_ISDIR(mode)) return -EPERM; tmp = getname(filename); @@ -1256,6 +1385,37 @@ mode &= ~current->fs->umask; if (!IS_ERR(dentry)) { +#ifdef CONFIG_GRKERNSEC_CHROOT_MKNOD + if (grsec_enable_chroot_mknod && !S_ISFIFO(mode) && proc_is_chrooted(current)) { + switch (mode & S_IFMT) { + case S_IFREG: grdevmode = 'r'; break; + case S_IFCHR: grdevmode = 'c'; break; + case S_IFBLK: grdevmode = 'b'; break; + case S_IFSOCK: grdevmode = 's'; break; + default: grdevmode = 'u'; + } + security_alert("refused attempt to mknod(%c:%.32s) (%.30s) from chroot() jail (%s:%lu) " + "owned by %d %d by " DEFAULTSECMSG, + "mknods in chroot denied",grdevmode,kdevname(dev),tmp, + kdevname(current->fs->root->d_inode->i_dev),current->fs->root->d_inode->i_ino, + current->fs->root->d_inode->i_uid,current->fs->root->d_inode->i_gid, + DEFAULTSECARGS); + error = -EPERM; + dput(dentry); + goto out_dput; + } +#endif +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(nd.dentry,GR_WRITE,nd.mnt)) == GR_DENY) ) { + security_alert("attempt to mknod %.1024s (dev %d) by " + DEFAULTSECMSG, "mknod attempts", filename, dev, + DEFAULTSECARGS); + error = -EPERM; + dput(dentry); + goto out_dput; + } +#endif + switch (mode & S_IFMT) { case 0: case S_IFREG: error = vfs_create(nd.dentry->d_inode,dentry,mode); @@ -1271,6 +1431,7 @@ } dput(dentry); } +out_dput: up(&nd.dentry->d_inode->i_sem); path_release(&nd); out: @@ -1323,6 +1484,18 @@ dentry = lookup_create(&nd, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { +#ifdef CONFIG_GRKERNSEC_ACL + error = 0; + if( ( ((gr_search(nd.dentry,GR_WRITE,nd.mnt)) == GR_DENY))){ + security_alert("attempt to mkdir %.1024s by " + DEFAULTSECMSG, "mkdir attempts", + pathname, + DEFAULTSECARGS); + error = -EPERM; + } + if(!error) +#endif + error = vfs_mkdir(nd.dentry->d_inode, dentry, mode & ~current->fs->umask); dput(dentry); @@ -1431,7 +1604,18 @@ dentry = lookup_hash(&nd.last, nd.dentry); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_rmdir(nd.dentry->d_inode, dentry); +#ifdef CONFIG_GRKERNSEC_ACL + error = 0; + if( ( (gr_search(nd.dentry,GR_WRITE,nd.mnt)) == GR_DENY)) { + security_alert("attempt to rmdir %.1024s by " + DEFAULTSECMSG, "rmdir attempts", + pathname, + DEFAULTSECARGS); + error = -EPERM; + } + if(!error) +#endif + error = vfs_rmdir(nd.dentry->d_inode, dentry); dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1494,7 +1678,18 @@ /* Why not before? Because we want correct error value */ if (nd.last.name[nd.last.len]) goto slashes; - error = vfs_unlink(nd.dentry->d_inode, dentry); +#ifdef CONFIG_GRKERNSEC_ACL + error = 0; + if( ( (gr_search(dentry,GR_WRITE, nd.mnt)) == GR_DENY)) { + security_alert("attempt to unlink %.1024s by " DEFAULTSECMSG, + "unlink attempts", + name, DEFAULTSECARGS); + error = -EPERM; + } + if(!error) +#endif + + error = vfs_unlink(nd.dentry->d_inode, dentry); exit2: dput(dentry); } @@ -1559,7 +1754,20 @@ dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_symlink(nd.dentry->d_inode, dentry, from); +#ifdef CONFIG_GRKERNSEC_ACL + error = 0; + if( gr_search(nd.dentry,GR_WRITE,nd.mnt) == GR_DENY) + { + security_alert("attempt to symlink %.1024s" + "to %.1024s by " DEFAULTSECMSG, + "symlink attempts", + from, to, DEFAULTSECARGS); + error = -EPERM; + } + + if(!error) +#endif + error = vfs_symlink(nd.dentry->d_inode, dentry, from); dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1650,6 +1858,36 @@ new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { +#if defined(CONFIG_GRKERNSEC_LINK) || defined(CONFIG_GRKERNSEC_ACL) + error = 0; +#ifdef CONFIG_GRKERNSEC_LINK + if(grsec_enable_link) { + if(current->fsuid != old_nd.dentry->d_inode->i_uid && + (!S_ISREG(old_nd.dentry->d_inode->i_mode) || + (old_nd.dentry->d_inode->i_mode & S_ISUID) || + ((old_nd.dentry->d_inode->i_mode & (S_ISGID | S_IXGRP)) == + (S_ISGID | S_IXGRP)) || (error = permission(old_nd.dentry->d_inode, + MAY_READ | MAY_WRITE))) && !capable(CAP_FOWNER) + && current->uid) { + security_alert("denied hardlink of %.30s (owned by %d.%d) to %.30s for " + DEFAULTSECMSG, "denied hardlinks",oldname,old_nd.dentry->d_inode->i_uid, + old_nd.dentry->d_inode->i_gid,newname,DEFAULTSECARGS); + error = -EPERM; + } + } + if(!error) +#endif +#ifdef CONFIG_GRKERNSEC_ACL + if( gr_search(old_nd.dentry,GR_WRITE,old_nd.mnt) == GR_DENY || gr_search(nd.dentry,GR_WRITE,nd.mnt) == GR_DENY) { + security_alert("attempt to link %.1024s to %.1024s by " + DEFAULTSECMSG, "attempted links", oldname, newname, + DEFAULTSECARGS); + error = -EPERM; + } + if(!error) +#endif +#endif + error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); dput(new_dentry); } @@ -1887,11 +2125,26 @@ error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) goto exit4; +#ifdef CONFIG_GRKERNSEC_ACL + error = 0; + if( gr_search(old_dir,GR_WRITE,oldnd.mnt) == GR_DENY || gr_search(new_dir,GR_WRITE,newnd.mnt) == GR_DENY) { + security_alert("attempt to rename %.1024s to %.1024s by " + DEFAULTSECMSG, "rename attempts", + oldname, newname, + DEFAULTSECARGS); + error = -EPERM; + } + if(!error) { +#endif + lock_kernel(); error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); unlock_kernel(); +#ifdef CONFIG_GRKERNSEC_ACL + } +#endif dput(new_dentry); exit4: diff -urN linux/fs/namespace.c linux/fs/namespace.c --- linux/fs/namespace.c Fri Dec 21 12:41:55 2001 +++ linux/fs/namespace.c Sun Jan 20 12:04:44 2002 @@ -16,6 +16,10 @@ #include #include #include +#if defined(CONFIG_GRKERNSEC_CHROOT_MOUNT) || defined(CONFIG_GRKERNSEC_AUDIT_MOUNT) +#include +#include +#endif #include @@ -353,6 +357,14 @@ } spin_unlock(&dcache_lock); up(&mount_sem); +#ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT + if( +#ifdef CONFIG_GRKERNSEC_AUDIT_GROUP + grsec_enable_group && in_group_p(grsec_audit_gid) && +#endif + grsec_enable_mount) + printk(KERN_INFO "grsec: unmount of %.30s by " DEFAULTSECMSG "\n",mnt->mnt_devname, DEFAULTSECARGS); +#endif return retval; } @@ -673,6 +685,23 @@ retval = path_walk(dir_name, &nd); if (retval) return retval; + +#ifdef CONFIG_GRKERNSEC_CHROOT_MOUNT + if (grsec_enable_chroot_mount && proc_is_chrooted(current)) { + security_alert("denied attempt to mount (%.30s) as %.64s from chroot jail (%.32s:%lu) " + "of %d.%d by " DEFAULTSECMSG, "denied mounts in chroot", + dev_name,dir_name, kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino,current->fs->root->d_inode->i_uid, + current->fs->root->d_inode->i_gid, DEFAULTSECARGS); + retval = -EPERM; + path_release(&nd); + return retval; + } +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT + if(grsec_enable_mount) + printk(KERN_INFO "grsec: mount %.30s to %.64s by " DEFAULTSECMSG "\n",dev_name,dir_name, DEFAULTSECARGS); +#endif if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, diff -urN linux/fs/open.c linux/fs/open.c --- linux/fs/open.c Fri Oct 12 16:48:42 2001 +++ linux/fs/open.c Sun Jan 20 12:04:15 2002 @@ -18,8 +18,32 @@ #include +#if defined(CONFIG_GRKERNSEC_CHROOT_DOUBLE)||\ + defined(CONFIG_GRKERNSEC_CHROOT_CAPS) ||\ + defined(CONFIG_GRKERNSEC_CHROOT_CHMOD) ||\ + defined(CONFIG_GRKERNSEC_CHROOT_CHDIR) ||\ + defined(CONFIG_GRKERNSEC_AUDIT_CHDIR) ||\ + defined(CONFIG_GRKERNSEC_ACL) +#include +#endif + + #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) +#ifdef CONFIG_GRKERNSEC_ACL +static int conv_flags(int p) { + int retval = LOOKUP_FOLLOW; + if(p & O_NOFOLLOW) + retval &= ~LOOKUP_FOLLOW; + if( (p & (O_CREAT|O_EXCL)) == (O_CREAT | O_EXCL)) + retval &= ~LOOKUP_FOLLOW; + if(p & O_DIRECTORY) + retval |= LOOKUP_DIRECTORY; + return retval; +} +#endif + + int vfs_statfs(struct super_block *sb, struct statfs *buf) { int retval = -ENODEV; @@ -71,7 +95,11 @@ return error; } +#ifdef CONFIG_GRKERNSEC_ACL +int do_truncate(struct dentry *dentry, loff_t length, struct vfsmount *mnt) +#else int do_truncate(struct dentry *dentry, loff_t length) +#endif { struct inode *inode = dentry->d_inode; int error; @@ -81,6 +109,17 @@ if (length < 0) return -EINVAL; +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(dentry,GR_WRITE,mnt)) == GR_DENY)) { + security_alert("attempted to truncate file with inode %ld dev " + "%d by " DEFAULTSECMSG, "file truncate attempts", + dentry->d_inode->i_ino, + dentry->d_inode->i_dev, DEFAULTSECARGS); + return -EPERM; + } +#endif + + down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; @@ -139,7 +178,11 @@ error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); +#ifdef CONFIG_GRKERNSEC_ACL + error = do_truncate(nd.dentry, length, nd.mnt); +#else error = do_truncate(nd.dentry, length); +#endif } put_write_access(inode); @@ -191,7 +234,11 @@ error = locks_verify_truncate(inode, file, length); if (!error) +#ifdef CONFIG_GRKERNSEC_ACL + error = do_truncate(dentry, length, file->f_vfsmnt); +#else error = do_truncate(dentry, length); +#endif out_putf: fput(file); out: @@ -245,6 +292,19 @@ if (IS_RDONLY(inode)) goto dput_and_out; +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(nd.dentry,GR_WRITE,nd.mnt)) == GR_DENY)) { + security_alert("attempted to change access time for file" + "with inode %ld dev %d by " DEFAULTSECMSG, + "file access time change attempts", + nd.dentry->d_inode->i_ino, + nd.dentry->d_inode->i_dev, DEFAULTSECARGS); + error = -EPERM; + goto dput_and_out; + } +#endif + + /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { @@ -290,6 +350,19 @@ if (IS_RDONLY(inode)) goto dput_and_out; +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(nd.dentry,GR_WRITE,nd.mnt)) == GR_DENY)) { + security_alert("attempted to change access time for file with" + "inode %ld dev %d by " DEFAULTSECMSG, + "file access time change attempts", + nd.dentry->d_inode->i_ino, + nd.dentry->d_inode->i_dev, DEFAULTSECARGS); + error = -EPERM; + goto dput_and_out; + } +#endif + + /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (utimes) { @@ -341,6 +414,17 @@ res = user_path_walk(filename, &nd); if (!res) { +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(nd.dentry,GR_WRITE,nd.mnt)) == GR_DENY)) { + security_alert("attempted to access file with inode %ld dev " + "%d by " DEFAULTSECMSG, "file access attempts", + nd.dentry->d_inode->i_ino, + nd.dentry->d_inode->i_dev, DEFAULTSECARGS); + path_release(&nd); + return -EPERM; + } +#endif + res = permission(nd.dentry->d_inode, mode); /* SuS v2 requires we report a read only fs too */ if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) @@ -378,6 +462,25 @@ if (error) goto dput_and_out; +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(nd.dentry,GR_READ,nd.mnt)) == GR_DENY)) { + security_alert("Attempted to chdir to directory with inode %ld dev " + "%d by " DEFAULTSECMSG, "chdir attempts", + nd.dentry->d_inode->i_ino, + nd.dentry->d_inode->i_dev, DEFAULTSECARGS); + error = -EPERM; + goto dput_and_out; + } +#endif + +#ifdef CONFIG_GRKERNSEC_AUDIT_CHDIR + if( +#ifdef CONFIG_GRKERNSEC_AUDIT_GROUP + grsec_enable_group && in_group_p(grsec_audit_gid) && +#endif + grsec_enable_chdir) + printk(KERN_INFO "grsec: chdir(\"%.64s\") by " DEFAULTSECMSG "\n", filename, DEFAULTSECARGS); +#endif set_fs_pwd(current->fs, nd.mnt, nd.dentry); dput_and_out: @@ -408,6 +511,17 @@ goto out_putf; error = permission(inode, MAY_EXEC); + +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(file->f_dentry,GR_WRITE,file->f_vfsmnt)) == GR_DENY)) { + security_alert("attempted to truncate file with inode %ld dev " + "%d by " DEFAULTSECMSG, "file truncate attempts", + file->f_dentry->d_inode->i_ino, + file->f_dentry->d_inode->i_dev, DEFAULTSECARGS); + error = -EPERM; + } +#endif + if (!error) set_fs_pwd(current->fs, mnt, dentry); out_putf: @@ -441,9 +555,39 @@ error = -EPERM; if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; +#ifdef CONFIG_GRKERNSEC_CHROOT_DOUBLE + if(grsec_enable_chroot_double && proc_is_chrooted(current)) { + security_alert("denied attempt to chroot() from (%.32s:%lu) to (%.30s)" + ", process " DEFAULTSECMSG, + "double chroot() denied", + kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino,name, + DEFAULTSECARGS); + goto dput_and_out; + } +#endif set_fs_root(current->fs, nd.mnt, nd.dentry); set_fs_altroot(); +#ifdef CONFIG_GRKERNSEC_CHROOT_CAPS + if(grsec_enable_chroot_caps && current->pid && current->pid > 1) { + cap_lower(current->cap_permitted,CAP_FOWNER & CAP_SETPCAP & CAP_LINUX_IMMUTABLE & + CAP_NET_ADMIN & CAP_SYS_MODULE & CAP_SYS_RAWIO & CAP_SYS_PACCT & + CAP_SYS_ADMIN & CAP_SYS_BOOT & CAP_SYS_RESOURCE & CAP_SYS_TIME & + CAP_SYS_TTY_CONFIG); + cap_lower(current->cap_inheritable,CAP_FOWNER & CAP_SETPCAP & CAP_LINUX_IMMUTABLE & + CAP_NET_ADMIN & CAP_SYS_MODULE & CAP_SYS_RAWIO & CAP_SYS_PACCT & + CAP_SYS_ADMIN & CAP_SYS_BOOT & CAP_SYS_RESOURCE & CAP_SYS_TIME & + CAP_SYS_TTY_CONFIG); + cap_lower(current->cap_effective,CAP_FOWNER & CAP_SETPCAP & CAP_LINUX_IMMUTABLE & + CAP_NET_ADMIN & CAP_SYS_MODULE & CAP_SYS_RAWIO & CAP_SYS_PACCT & + CAP_SYS_ADMIN & CAP_SYS_BOOT & CAP_SYS_RESOURCE & CAP_SYS_TIME & + CAP_SYS_TTY_CONFIG); + } +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_CHDIR + if (grsec_enable_chroot_chdir) set_fs_pwd(current->fs, nd.mnt, nd.dentry); +#endif error = 0; dput_and_out: path_release(&nd); @@ -472,8 +616,36 @@ err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out_putf; + +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(dentry,GR_WRITE,file->f_vfsmnt)) == GR_DENY)) { + security_alert("Attempt to fchmod program with inode %ld dev %d " + "by " DEFAULTSECMSG, "fchmod attempts", + dentry->d_inode->i_ino, + dentry->d_inode->i_dev, DEFAULTSECARGS); + + err = -EPERM; + goto out_putf; + } +#endif + if (mode == (mode_t) -1) mode = inode->i_mode; +#ifdef CONFIG_GRKERNSEC_CHROOT_CHMOD + if(grsec_enable_chroot_chmod && ((mode & S_ISUID) || (mode & S_ISGID)) + && proc_is_chrooted(current)) { + security_alert("denied attempt to fchmod +s (%.32s:%lu) owned by %d.%d to mode 0%07o " + "from chroot jail (%.32s:%lu) of %d.%d by " + DEFAULTSECMSG, + "denied fchmod +s in chroot", + kdevname(inode->i_dev),inode->i_ino,inode->i_uid,inode->i_gid,mode, + kdevname(current->fs->root->d_inode->i_dev),current->fs->root->d_inode->i_ino, + current->fs->root->d_inode->i_uid,current->fs->root->d_inode->i_gid, + DEFAULTSECARGS); + err = -EPERM; + goto out_putf; + } +#endif newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); @@ -504,8 +676,34 @@ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(nd.dentry,GR_WRITE,nd.mnt)) == GR_DENY)) { + security_alert("Attempt to chmod file %1024s by " + DEFAULTSECMSG, "chmod attempts", + filename, DEFAULTSECARGS); + error = -EPERM; + goto dput_and_out; + } +#endif + + if (mode == (mode_t) -1) mode = inode->i_mode; +#ifdef CONFIG_GRKERNSEC_CHROOT_CHMOD + if (grsec_enable_chroot_chmod && ((mode & S_ISUID) || (mode & S_ISGID)) + && proc_is_chrooted(current)) { + security_alert("denied attempt to chmod +s (%.32s:%lu) (%.30s) owned by %d.%d to mode 0%07o " + "from chroot jail (%.32s:%lu) of %d.%d by " + DEFAULTSECMSG,"denied chmod +s in chroot", + kdevname(inode->i_dev),inode->i_ino,filename,inode->i_uid,inode->i_gid, + mode,kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino,current->fs->root->d_inode->i_uid, + current->fs->root->d_inode->i_gid, + DEFAULTSECARGS); + error = -EPERM; + goto dput_and_out; + } +#endif newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(nd.dentry, &newattrs); @@ -516,7 +714,11 @@ return error; } +#ifdef CONFIG_GRKERNSEC_ACL +static int chown_common(struct dentry * dentry, uid_t user, gid_t group, struct vfsmount *mnt) +#else static int chown_common(struct dentry * dentry, uid_t user, gid_t group) +#endif { struct inode * inode; int error; @@ -533,6 +735,17 @@ error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; +#ifdef CONFIG_GRKERNSEC_ACL + if( ( (gr_search(dentry,GR_WRITE,mnt)) == GR_DENY)) { + security_alert("Attempt to chown file with inode %ld dev %d " + "to %d.%d by " DEFAULTSECMSG, "chown attempts", + dentry->d_inode->i_ino,dentry->d_inode->i_dev, + user, group, DEFAULTSECARGS); + error = -EPERM; + goto out; + } +#endif + if (user == (uid_t) -1) user = inode->i_uid; if (group == (gid_t) -1) @@ -583,7 +796,11 @@ error = user_path_walk(filename, &nd); if (!error) { +#ifdef CONFIG_GRKERNSEC_ACL + error = chown_common(nd.dentry, user, group, nd.mnt); +#else error = chown_common(nd.dentry, user, group); +#endif path_release(&nd); } return error; @@ -596,7 +813,11 @@ error = user_path_walk_link(filename, &nd); if (!error) { +#ifdef CONFIG_GRKERNSEC_ACL + error = chown_common(nd.dentry, user, group, nd.mnt); +#else error = chown_common(nd.dentry, user, group); +#endif path_release(&nd); } return error; @@ -610,7 +831,11 @@ file = fget(fd); if (file) { +#ifdef CONFIG_GRKERNSEC_ACL + error = chown_common(file->f_dentry, user, group, file->f_vfsmnt); +#else error = chown_common(file->f_dentry, user, group); +#endif fput(file); } return error; @@ -634,12 +859,41 @@ { int namei_flags, error; struct nameidata nd; +#ifdef CONFIG_GRKERNSEC_ACL + struct nameidata obv; +#endif namei_flags = flags; if ((namei_flags+1) & O_ACCMODE) namei_flags++; if (namei_flags & O_TRUNC) namei_flags |= 2; + +#ifdef CONFIG_GRKERNSEC_ACL + error = 0; + if(path_init(filename,conv_flags(namei_flags),&obv)) + error = path_walk(filename,&obv); + if(error) goto out; + if(!obv.dentry->d_inode) + flags |= GR_NONEXISTANT; + else + if(S_ISBLK(obv.dentry->d_inode->i_mode) && !capable(CAP_SYS_RAWIO)) { + security_alert("Attempt to block device %ld %d with " + "insuffificent capabilities by process " + DEFAULTSECMSG, + "attempt to access block devices", + obv.dentry->d_inode->i_ino, + obv.dentry->d_inode->i_dev, DEFAULTSECARGS); + path_release(&obv); + error = -EPERM; + return ERR_PTR(error); + } + + path_release(&obv); +out: + +#endif + error = open_namei(filename, namei_flags, mode, &nd); if (!error) diff -urN linux/fs/proc/base.c linux/fs/proc/base.c --- linux/fs/proc/base.c Thu Oct 11 02:42:47 2001 +++ linux/fs/proc/base.c Sun Jan 13 01:24:51 2002 @@ -24,6 +24,10 @@ #include #include +#ifdef CONFIG_GRKERNSEC_ACL +#include +#endif + /* * For hysterical raisins we keep the same inumbers as in the old procfs. * Feel free to change the macro below - just keep the range distinct from @@ -663,7 +667,11 @@ inode->i_gid = 0; if (ino == PROC_PID_INO || task_dumpable(task)) { inode->i_uid = task->euid; +#ifndef CONFIG_GRKERNSEC_PROC_USERGROUP inode->i_gid = task->egid; +#else + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#endif } out: @@ -966,13 +974,27 @@ if (!task) goto out; +#ifdef CONFIG_GRKERNSEC_ACL + if(gr_check_hidden_proc(task->acl)) { + free_task_struct(task); + goto out; + } +#endif + + inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO); free_task_struct(task); if (!inode) goto out; +#ifdef CONFIG_GRKERNSEC_PROC_USER + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR; +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP; +#else inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; +#endif inode->i_op = &proc_base_inode_operations; inode->i_fop = &proc_base_operations; inode->i_nlink = 3; @@ -1012,8 +1034,13 @@ int pid = p->pid; if (!pid) continue; +#ifdef CONFIG_GRKERNSEC_ACL + if(gr_check_hidden_proc(p->acl)) + continue; +#endif if (--index >= 0) continue; + pids[nr_pids] = pid; nr_pids++; if (nr_pids >= PROC_MAXPIDS) diff -urN linux/fs/proc/generic.c linux/fs/proc/generic.c --- linux/fs/proc/generic.c Fri Sep 7 13:53:59 2001 +++ linux/fs/proc/generic.c Sun Jan 13 01:24:51 2002 @@ -491,6 +491,22 @@ return ent; } +#ifdef CONFIG_GRKERNSEC_PROC +struct proc_dir_entry *proc_priv_mkdir(const char *name, mode_t mode, struct proc_dir_entry *parent) +{ + struct proc_dir_entry *ent; + + ent = proc_create(&parent, name, mode, 2); + if (ent) { + ent->proc_fops = &proc_dir_operations; + ent->proc_iops = &proc_dir_inode_operations; + + proc_register(parent, ent); + } + return ent; +} +#endif + struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) { diff -urN linux/fs/proc/inode.c linux/fs/proc/inode.c --- linux/fs/proc/inode.c Sat Nov 17 14:24:32 2001 +++ linux/fs/proc/inode.c Sun Jan 13 01:24:51 2002 @@ -152,7 +152,11 @@ if (de->mode) { inode->i_mode = de->mode; inode->i_uid = de->uid; +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#else inode->i_gid = de->gid; +#endif } if (de->size) inode->i_size = de->size; diff -urN linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c --- linux/fs/proc/proc_misc.c Wed Nov 21 00:29:09 2001 +++ linux/fs/proc/proc_misc.c Sun Jan 13 01:24:51 2002 @@ -507,8 +507,10 @@ {"meminfo", meminfo_read_proc}, {"version", version_read_proc}, #ifdef CONFIG_MODULES +#ifndef CONFIG_GRKERNSEC_PROC {"modules", modules_read_proc}, #endif +#endif {"stat", kstat_read_proc}, {"devices", devices_read_proc}, {"partitions", partitions_read_proc}, @@ -531,6 +533,13 @@ for (p = simple_ones; p->name; p++) create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL); +#if defined(CONFIG_GRKERNSEC_PROC) && defined(CONFIG_MODULES) +#ifdef CONFIG_GRKERNSEC_PROC_USER + create_proc_read_entry("modules", S_IRUSR, NULL, &modules_read_proc, NULL); +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + create_proc_read_entry("modules", S_IRUSR | S_IRGRP, NULL, &modules_read_proc, NULL); +#endif +#endif /* And now for trickier ones */ entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); if (entry) @@ -538,7 +547,13 @@ create_seq_entry("mounts", 0, &proc_mounts_operations); create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); #ifdef CONFIG_MODULES +#ifdef CONFIG_GRKERNSEC_PROC_USER + create_seq_entry("ksyms", S_IRUSR, &proc_ksyms_operations); +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + create_seq_entry("ksyms", S_IRUSR | S_IRGRP, &proc_ksyms_operations); +#else create_seq_entry("ksyms",