diff -ruN linux-2.4.29/Documentation/Configure.help linux-2.4.29-BF6-C7_III-grsec/Documentation/Configure.help --- linux-2.4.29/Documentation/Configure.help 2005-01-19 07:09:22.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/Documentation/Configure.help 2005-03-21 17:27:01.023285672 -0700 @@ -2899,6 +2899,20 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +stealth networking support +CONFIG_IP_NF_MATCH_STEALTH + Enabling this option will drop all syn packets coming to unserved tcp + ports as well as all packets coming to unserved udp ports. If you + are using your system to route any type of packets (ie. via NAT) + you should put this module at the end of your ruleset, since it will + drop packets that aren't going to ports that are listening on your + machine itself, it doesn't take into account that the packet might be + destined for someone on your internal network if you're using NAT for + instance. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + MAC address match support CONFIG_IP_NF_MATCH_MAC MAC matching allows you to match packets based on the source @@ -23427,6 +23441,930 @@ "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 the features and can evaluate their usefulness + for your machine. + +Additional security levels +CONFIG_GRKERNSEC_LOW + + Low additional security + ----------------------------------------------------------------------- + If you choose this option, several of the grsecurity options will + be enabled that will give you greater protection against a number + of attacks, while assuring that none of your software will have any + conflicts with the additional security measures. If you run a lot of + unusual software, or you are having problems with the higher security + levels, you should say Y here. With this option, the following features + are enabled: + + linking restrictions + fifo restrictions + random pids + enforcing nproc on execve() + restricted dmesg + enforced chdir("/") on chroot + + Medium additional security + ----------------------------------------------------------------------- + If you say Y here, several features in addition to those included in the + low additional security level will be enabled. These features provide + even more security to your system, though in rare cases they may + be incompatible with very old or poorly written software. If you + enable this option, make sure that your auth service (identd) is + running as gid 10 (usually group wheel). With this option the following + features (in addition to those provided in the low additional security + level) will be enabled: + + random tcp source ports + failed fork logging + time change logging + signal logging + deny mounts in chroot + deny double chrooting + deny sysctl writes in chroot + deny mknod in chroot + deny access to abstract AF_UNIX sockets out of chroot + deny pivot_root in chroot + denied writes of /dev/kmem, /dev/mem, and /dev/port + /proc restrictions with special gid set to 10 (usually wheel) + address space layout randomization + removal of addresses from /proc//[maps|stat] + + High additional security + ---------------------------------------------------------------------- + If you say Y here, many of the features of grsecurity will be enabled, + that will protect you against many kinds of attacks against + your system. The heightened security comes at a cost of an + increased chance of incompatibilities with rare software on your + machine. Since this security level enables PaX, you should view + and read about the PaX project. While + you are there, download chpax and run it on binaries that cause + problems with PaX. Also remember that since the /proc restrictions are + enabled, you must run your identd as group wheel (gid 10). + This security level enables the following features in addition to those + listed in the low and medium security levels: + + additional /proc restrictions + chmod restrictions in chroot + no signals, ptrace, or viewing processes outside of chroot + capability restrictions in chroot + deny fchdir out of chroot + priority restrictions in chroot + segmentation-based implementation of PaX + mprotect restrictions + kernel stack randomization + mount/unmount/remount logging + kernel symbol hiding + destroy unused shared memory + +Customized additional security +CONFIG_GRKERNSEC_CUSTOM + If you say Y here, you will be able to configure every grsecurity + option, which allows you to enable many more features that aren't + covered in the basic security levels. These additional features include + TPE, socket restrictions, and the sysctl system for grsecurity. It is + advised that you read through the help for each option to determine its + usefulness in your situation. + +Support soft mode +CONFIG_GRKERNSEC_PAX_SOFTMODE + Enabling this option will allow you to run PaX in soft mode, that + is, PaX features will not be enforced by default, only on executables + marked explicitly. You must also enable PT_PAX_FLAGS support as it + is the only way to mark executables for soft mode use. + + Soft mode can be activated by using the "pax_softmode=1" kernel command + line option on boot. Furthermore you can control various PaX features + at runtime via the entries in /proc/sys/kernel/pax. + +Use legacy ELF header marking +CONFIG_GRKERNSEC_PAX_EI_PAX + Enabling this option will allow you to control PaX features on + a per executable basis via the 'chpax' utility available at + http://pax.grsecurity.net/. The control flags will be read from + an otherwise reserved part of the ELF header. This marking has + numerous drawbacks (no support for soft-mode, toolchain does not + know about the non-standard use of the ELF header) therefore it + has been deprecated in favour of PT_PAX_FLAGS support. + + If you have applications not marked by the PT_PAX_FLAGS ELF + program header then you MUST enable this option otherwise they + will not get any protection. + + Note that if you enable PT_PAX_FLAGS marking support as well, + the PT_PAX_FLAG marks will override the legacy EI_PAX marks. + +Use ELF program header marking +CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS + Enabling this option will allow you to control PaX features on + a per executable basis via the 'paxctl' utility available at + http://pax.grsecurity.net/. The control flags will be read from + a PaX specific ELF program header (PT_PAX_FLAGS). This marking + has the benefits of supporting both soft mode and being fully + integrated into the toolchain (the binutils patch is available + from http://pax.grsecurity.net). + + If you have applications not marked by the PT_PAX_FLAGS ELF + program header then you MUST enable the EI_PAX marking support + otherwise they will not get any protection. + + Note that if you enable the legacy EI_PAX marking support as well, + the EI_PAX marks will be overridden by the PT_PAX_FLAGS marks. + +MAC system integration +CONFIG_GRKERNSEC_PAX_NO_ACL_FLAGS + Mandatory Access Control systems have the option of controlling + PaX flags on a per executable basis, choose the method supported + by your particular system. + + - "none": if your MAC system does not interact with PaX, + - "direct": if your MAC system defines pax_set_flags() itself, + - "hook": if your MAC system uses the pax_set_flags_func callback. + + NOTE: this option is for developers/integrators only. + +Enforce non-executable pages +CONFIG_GRKERNSEC_PAX_NOEXEC + By design some architectures do not allow for protecting memory + pages against execution or even if they do, Linux does not make + use of this feature. In practice this means that 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 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). + + Enabling this option will let you choose from various features + that prevent the injection and execution of '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. + +Paging based non-executable pages +CONFIG_GRKERNSEC_PAX_PAGEEXEC + This implementation is based on the paging feature of the CPU. + On i386 it has a variable performance impact on applications + depending on their memory usage pattern. You should carefully + test your applications before using this feature in production. + On alpha, parisc, sparc and sparc64 there is no performance + impact. On ppc there is a slight performance impact. + +Segmentation based non-executable pages +CONFIG_GRKERNSEC_PAX_SEGMEXEC + This implementation is based on the segmentation feature of the + CPU and has little performance impact, however applications will + be limited to a 1.5 GB address space instead of the normal 3 GB. + +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_PAGEEXEC or + CONFIG_GRKERNSEC_PAX_SEGMEXEC then such programs will no longer + work under your kernel. + + As a remedy you can say Y here and use the 'chpax' or 'paxctl' + utilities to enable trampoline emulation for the affected programs + yet still have the protection provided by the non-executable pages. + + On parisc and ppc you MUST enable this option and EMUSIGRT as + well, otherwise your system will not even boot. + + Alternatively you can say N here and use the 'chpax' or 'paxctl' + utilities to disable CONFIG_GRKERNSEC_PAX_PAGEEXEC and + CONFIG_GRKERNSEC_PAX_SEGMEXEC for the affected files. + + NOTE: enabling this feature *may* open up a loophole in the + protection provided by non-executable pages 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. + +Automatically emulate sigreturn trampolines +CONFIG_GRKERNSEC_PAX_EMUSIGRT + Enabling this option will have the kernel automatically detect + and emulate signal return trampolines executing on the stack + that would otherwise lead to task termination. + + This solution is intended as a temporary one for users with + legacy versions of libc (libc5, glibc 2.0, uClibc before 0.9.17, + Modula-3 runtime, etc) or executables linked to such, basically + everything that does not specify its own SA_RESTORER function in + normal executable memory like glibc 2.1+ does. + + On parisc and ppc you MUST enable this option, otherwise your + system will not even boot. + + NOTE: this feature cannot be disabled on a per executable basis + and since it *does* open up a loophole in the protection provided + by non-executable pages, the best solution is to not have any + files on your system that would require this option. + +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, + - making read-only executable pages writable again, + - creating executable pages from anonymous memory. + + You should say Y here to complete the protection provided by + the enforcement of non-executable pages. + + NOTE: you can use the 'chpax' utility to control this + feature on a per file basis. chpax is available at + + +Disallow ELF text relocations +CONFIG_GRKERNSEC_PAX_NOELFRELOCS + Non-executable pages and mprotect() restrictions are effective + in preventing the introduction of new executable code into an + attacked task's address space. There remain only two venues + for this kind of attack: if the attacker can execute already + existing code in the attacked task then he can either have it + create and mmap() a file containing his code or have it mmap() + an already existing ELF library that does not have position + independent code in it and use mprotect() on it to make it + writable and copy his code there. While protecting against + the former approach is beyond PaX, the latter can be prevented + by having only PIC ELF libraries on one's system (which do not + need to relocate their code). If you are sure this is your case, + then enable this option otherwise be careful as you may not even + be able to boot or log on your system (for example, some PAM + modules are erroneously compiled as non-PIC by default). + + NOTE: if you are using dynamic ELF executables (as suggested + when using ASLR) then you must have made sure that you linked + your files using the PIC version of crt1 (the et_dyn.zip package + referenced there has already been updated to support this). + +Enforce non-executable kernel pages +CONFIG_GRKERNSEC_PAX_KERNEXEC + This is the kernel land equivalent of PAGEEXEC and MPROTECT, + that is, enabling this option will make it harder to inject + and execute 'foreign' code in kernel memory itself. + +Address Space Layout Randomization +CONFIG_GRKERNSEC_PAX_ASLR + Many if not most exploit techniques rely on the knowledge of + certain addresses in the attacked program. The following options + will allow the kernel to apply a certain amount of randomization + to specific parts of the program thereby forcing an attacker to + guess them in most cases. Any failed guess will most likely crash + the attacked program which allows the kernel to detect such attempts + and react on them. PaX itself provides no reaction mechanisms, + instead it is strongly encouraged that you make use of grsecurity's + built-in crash detection features or develop one yourself. + + By saying Y here you can choose to randomize the following areas: + - top of the task's kernel stack + - top of the task's userland stack + - base address for mmap() requests that do not specify one + (this includes all libraries) + - base address of the main executable + + It is strongly recommended to say Y here as address space layout + randomization has negligible impact on performance yet it provides + a very effective protection. + + NOTE: you can use the 'chpax' or 'paxctl' utilities to control most + of these features on a per file basis. + +Randomize kernel stack base +CONFIG_GRKERNSEC_PAX_RANDKSTACK + By saying Y here the kernel will randomize every task's kernel + stack on every system call. This will not only force an attacker + to guess it but also prevent him from making use of possible + leaked information about it. + + Since the kernel stack is a rather scarce resource, randomization + may cause unexpected stack overflows, therefore you should very + carefully test your system. Note that once enabled in the kernel + configuration, this feature cannot be disabled on a per file basis. + +Randomize user stack base +CONFIG_GRKERNSEC_PAX_RANDUSTACK + By saying Y here the kernel will randomize every task's userland + stack. The randomization is done in two steps where the second + one may apply a big amount of shift to the top of the stack and + cause problems for programs that want to use lots of memory (more + than 2.5 GB if SEGMEXEC is not active, or 1.25 GB when it is). + For this reason the second step can be controlled by 'chpax' or + 'paxctl' on a per file basis. + +Randomize ET_EXEC base +CONFIG_GRKERNSEC_PAX_RANDEXEC + By saying Y here the kernel will randomize the base address of normal + ET_EXEC ELF executables as well. This is accomplished by mapping the + executable in memory in a special way which also allows for detecting + attackers who attempt to execute its code for their purposes. Since + this special mapping causes performance degradation and the attack + detection may create false alarms as well, you should carefully test + your executables when this feature is enabled. + + This solution is intended only as a temporary one until you relink + your programs as a dynamic ELF file. + + NOTE: you can use the 'chpax' or 'paxctl' utilities to control + this feature on a per file basis. + +Allow ELF ET_EXEC text relocations +CONFIG_GRKERNSEC_PAX_ETEXECRELOCS + On some architectures like the alpha there are incorrectly + created applications that require text relocations and would + not work without enabling this option. If you are an alpha + user, you should enable this option and disable it once you + have made sure that none of your applications need it. + +Automatically emulate ELF PLT +CONFIG_GRKERNSEC_PAX_EMUPLT + Enabling this option will have the kernel automatically detect + and emulate the Procedure Linkage Table entries in ELF files. + On some architectures such entries are in writable memory, and + become non-executable leading to task termination. Therefore + it is mandatory that you enable this option on alpha, parisc, ppc, + sparc and sparc64, otherwise your system would not even boot. + + NOTE: this feature *does* open up a loophole in the protection + provided by the non-executable pages, therefore the proper + solution is to modify the toolchain to produce a PLT that does + not need to be writable. + +Randomize mmap() base +CONFIG_GRKERNSEC_PAX_RANDMMAP + By saying Y here the kernel will use a randomized base address for + mmap() requests that do not specify one themselves. 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 will be randomized as well, completing the full + randomization of the address space layout. Attacking such programs + becomes a guess game. You can find an example of doing this at + and practical samples at + . + + NOTE: you can use the 'chpax' or 'paxctl' utilities to control this + feature on a per file basis. + +Deny writing to /dev/kmem, /dev/mem, and /dev/port +CONFIG_GRKERNSEC_KMEM + If you say Y here, /dev/kmem and /dev/mem won't be allowed to + be written to via mmap or otherwise to modify the running kernel. + /dev/port will also not be allowed to be opened. If you have module + support disabled, enabling this will close up four ways that are + currently used to insert malicious code into the running kernel. + Even with all these features enabled, we still highly recommend that + you use the RBAC system, as it is still possible for an attacker to + modify the running kernel through privileged I/O granted by ioperm/iopl. + If you are not using XFree86, you may be able to stop this additional + case by enabling the 'Disable privileged I/O' option. Though nothing + legitimately writes to /dev/kmem, XFree86 does need to write to /dev/mem, + but only to video memory, which is the only writing we allow in this + case. If /dev/kmem or /dev/mem are mmaped without PROT_WRITE, they will + not be allowed to mprotect it with PROT_WRITE later. + It is highly recommended that you say Y here if you meet all the + conditions above. + +Disable privileged I/O +CONFIG_GRKERNSEC_IO + If you say Y here, all ioperm and iopl calls will return an error. + Ioperm and iopl can be used to modify the running kernel. + Unfortunately, some programs need this access to operate properly, + the most notable of which are XFree86 and hwclock. hwclock can be + remedied by having RTC support in the kernel, so CONFIG_RTC is + enabled if this option is enabled, to ensure that hwclock operates + correctly. XFree86 still will not operate correctly with this option + enabled, so DO NOT CHOOSE Y IF YOU USE XFree86. If you use XFree86 + and you still want to protect your kernel against modification, + use the RBAC system. + +Hide kernel symbols +CONFIG_GRKERNSEC_HIDESYM + If you say Y here, getting information on loaded modules, and + displaying all kernel symbols through a syscall will be restricted + to users with CAP_SYS_MODULE. This option is only effective + provided the following conditions are met: + 1) The kernel using grsecurity is not precompiled by some distribution + 2) You are using the RBAC system and hiding other files such as your + kernel image and System.map + 3) You have the additional /proc restrictions enabled, which removes + /proc/kcore + If the above conditions are met, this option will aid to provide a + useful protection against local and remote kernel exploitation of + overflows and arbitrary read/write vulnerabilities. + +Deter exploit bruteforcing +CONFIG_GRKERNSEC_BRUTE + If you say Y here, attempts to bruteforce exploits against forking + daemons such as apache or sshd will be deterred. When a child of a + forking daemon is killed by PaX or crashes due to an illegal + instruction, the parent process will be delayed 30 seconds upon every + subsequent fork until the administrator is able to assess the + situation and restart the daemon. It is recommended that you also + enable signal logging in the auditing section so that logs are + generated when a process performs an illegal instruction. + +/proc//ipaddr support +CONFIG_GRKERNSEC_PROC_IPADDR + If you say Y here, a new entry will be added to each /proc/ + directory that contains the IP address of the person using the task. + The IP is carried across local TCP and AF_UNIX stream sockets. + This information can be useful for IDS/IPSes to perform remote response + to a local attack. The entry is readable by only the owner of the + process (and root if he has CAP_DAC_OVERRIDE, which can be removed via + the RBAC system), and thus does not create privacy concerns. + +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. You MUST + choose either a user only restriction or a user and group restriction. + Depending upon the option 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, + 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. + +Remove addresses from /proc/pid/[maps|stat] +CONFIG_GRKERNSEC_PROC_MEMMAP + If you say Y here, the /proc//maps and /proc//stat files will + give no information about the addresses of its mappings if + PaX features that rely on random addresses are enabled on the task. + If you use PaX it is greatly recommended that you say Y here as it + closes up a hole that makes the full ASLR useless for suid + binaries. + +Additional proc restrictions +CONFIG_GRKERNSEC_PROC_ADD + If you say Y here, additional restrictions will be placed on + /proc that keep normal users from viewing device information and + slabinfo information that could be useful for exploits. + +Dmesg(8) Restriction +CONFIG_GRKERNSEC_DMESG + If you say Y here, non-root users will not be able to use dmesg(8) + to view up to the last 4kb of messages in the kernel's log buffer. + If the sysctl option is enabled, a sysctl option with name "dmesg" is + created. + +Destroy unused shared memory +CONFIG_GRKERNSEC_SHM + If you say Y here, shared memory will be destroyed when no one is + attached to it. Otherwise, resources involved with the shared + memory can be used up and not be associated with any process (as the + shared memory still exists, and the creating process has exited). If + the sysctl option is enabled, a sysctl option with name + "destroy_unused_shm" is created. + +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-writable +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-writable +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. + +Enforce RLIMIT_NPROC on execs +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. + +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. + +Resource logging +CONFIG_GRKERNSEC_RESLOG + If you say Y here, all attempts to overstep resource limits will + be logged with the resource name, the requested size, and the current + limit. It is highly recommended that you say Y here. + +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. + +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. + +ELF text relocations logging +CONFIG_GRKERNSEC_AUDIT_TEXTREL + If you say Y here, text relocations will be logged with the filename + of the offending library or binary. The purpose of the feature is + to help Linux distribution developers get rid of libraries and + binaries that need text relocations which hinder the future progress + of PaX. Only Linux distribution developers should say Y here, and + never on a production machine, as this option creates an information + leak that could aid an attacker in defeating the randomization of + a single memory region. If the sysctl option is enabled, a sysctl + option with name "audit_textrel" 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. + +Deny access to abstract AF_UNIX sockets out of chroot +CONFIG_GRKERNSEC_CHROOT_UNIX + If you say Y here, processes inside a chroot will not be able to + connect to abstract (meaning not belonging to a filesystem) Unix + domain sockets that were bound outside of a chroot. It is recommended + that you say Y here. If the sysctl option is enabled, a sysctl option + with name "chroot_deny_unix" is created. + +Deny shmat() out of chroot +CONFIG_GRKERNSEC_CHROOT_SHMAT + If you say Y here, processes inside a chroot will not be able to attach + to shared memory segments that were created outside of the chroot jail. + It is recommended that you say Y here. If the sysctl option is enabled, + a sysctl option with name "chroot_deny_shmat" is created. + +Protect outside processes +CONFIG_GRKERNSEC_CHROOT_FINDTASK + If you say Y here, processes inside a chroot will not be able to + kill, send signals with fcntl, ptrace, capget, setpgid, getpgid, + getsid, or view any process outside of the chroot. If the sysctl + option is enabled, a sysctl option with name "chroot_findtask" 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 pivot_root in chroot +CONFIG_GRKERNSEC_CHROOT_PIVOT + If you say Y here, processes inside a chroot will not be able to use + a function called pivot_root() that was introduced in Linux 2.3.41. It + works similar to chroot in that it changes the root filesystem. This + function could be misused in a chrooted process to attempt to break out + of the chroot, and therefore should not be allowed. If the sysctl + option is enabled, a sysctl option with name "chroot_deny_pivot" 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 outside of the chroot. 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. + +Deny fchdir outside of chroot +CONFIG_GRKERNSEC_CHROOT_FCHDIR + If you say Y here, a well-known method of breaking chroots by fchdir'ing + to a file descriptor of the chrooting process that points to a directory + outside the filesystem will be stopped. If the sysctl option + is enabled, a sysctl option with name "chroot_deny_fchdir" 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 + anything 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. + +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. This can cause a large amount of logs if certain + applications (eg. djb's daemontools) are installed on the system, and + is therefore left as an option. If the sysctl option is enabled, a + sysctl option with name "chroot_execlog" is created. + +Deny sysctl writes in chroot +CONFIG_GRKERNSEC_CHROOT_SYSCTL + If you say Y here, an attacker in a chroot will not be able to + write to sysctl entries, either by sysctl(2) or through a /proc + interface. It is strongly recommended that you say Y here. If the + sysctl option is enabled, a sysctl option with name + "chroot_deny_sysctl" 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, rebooting the system, modifying immutable + files, modifying IPC owned by another, and changing the system time. + This is left an option because it can break 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 writable 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 non-root users other than the ones in the + group specified in the main TPE option will only be allowed to + execute files in directories they own that are not group or + world-writable, or in directories owned by root and writable only by + root. If the sysctl option is enabled, a sysctl option with name + "tpe_restrict_all" 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. + +Larger entropy pools +CONFIG_GRKERNSEC_RANDNET + If you say Y here, the entropy pools used for many features of Linux + and grsecurity will be doubled in size. Since several grsecurity + features use additional randomness, it is recommended that you say Y + here. Saying Y here has a similar effect as modifying + /proc/sys/kernel/random/poolsize. + +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. + +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 enabled in the kernel configuration are disabled at boot + if you do not say Y to the "Turn on features by default" option. + 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* + +Turn on features by default +CONFIG_GRKERNSEC_SYSCTL_ON + If you say Y here, instead of having all features enabled in the + kernel configuration disabled at boot time, the features will be + enabled at boot time. It is recommended you say Y here unless + there is some reason you would want all sysctl-tunable features to + be disabled by default. As mentioned elsewhere, it is important + to enable the grsec_lock entry once you have finished modifying + the sysctl entries. + +Number of burst messages +CONFIG_GRKERNSEC_FLOODBURST + This option allows you to choose the maximum number of messages allowed + within the flood time interval you chose in a separate option. The + default should be suitable for most people, however if you find that + many of your logs are being interpreted as flooding, you may want to + raise this value. + +Seconds in between log messages +CONFIG_GRKERNSEC_FLOODTIME + This option allows you to enforce the number of seconds between + grsecurity log messages. The default should be suitable for most + people, however, if you choose to change it, choose a value small enough + to allow informative logs to be produced, but large enough to + prevent flooding. + +Hide kernel processes +CONFIG_GRKERNSEC_ACL_HIDEKERN + If you say Y here, all kernel threads will be hidden to all + processes but those whose subject has the "view hidden processes" + flag. + +Maximum tries before password lockout +CONFIG_GRKERNSEC_ACL_MAXTRIES + This option enforces the maximum number of times a user can attempt + to authorize themselves with the grsecurity RBAC system before being + denied the ability to attempt authorization again for a specified time. + The lower the number, the harder it will be to brute-force a password. + +Time to wait after max password tries, in seconds +CONFIG_GRKERNSEC_ACL_TIMEOUT + This option specifies the time the user must wait after attempting to + authorize to the RBAC system with the maximum number of invalid + passwords. The higher the number, the harder it will be to brute-force + a password. + Disable data cache CONFIG_DCACHE_DISABLE This option allows you to run the kernel with data cache disabled. diff -ruN linux-2.4.29/Makefile linux-2.4.29-BF6-C7_III-grsec/Makefile --- linux-2.4.29/Makefile 2005-01-19 07:10:14.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/Makefile 2005-03-21 17:28:15.629191659 -0700 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 29 -EXTRAVERSION = +EXTRAVERSION = -BF6-C7_III-grsec KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -126,9 +126,10 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o NETWORKS =net/network.o +GRSECURITY =grsecurity/grsec.o LIBS =$(TOPDIR)/lib/lib.a -SUBDIRS =kernel drivers mm fs net ipc lib crypto +SUBDIRS =kernel drivers mm fs net ipc lib crypto grsecurity DRIVERS-n := DRIVERS-y := @@ -194,6 +195,7 @@ DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o DRIVERS-$(CONFIG_CRYPTO) += crypto/crypto.o +DRIVERS-$(CONFIG_COBALT) += drivers/cobalt/cobalt.o DRIVERS := $(DRIVERS-y) @@ -272,7 +274,7 @@ export CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL -export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS +export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS GRSECURITY .S.s: $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $< @@ -291,6 +293,7 @@ $(CORE_FILES) \ $(DRIVERS) \ $(NETWORKS) \ + $(GRSECURITY) \ $(LIBS) \ --end-group \ -o vmlinux @@ -375,6 +378,11 @@ fs lib mm ipc kernel drivers net: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) +cscope: + find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print > cscope.files + find $(SUBDIRS) init include/asm-$(ARCH) include/asm-generic -name '*.[ch]' >> cscope.files + cscope -k -b -q < cscope.files + TAGS: dummy { find include/asm-${ARCH} -name '*.h' -print ; \ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print ; \ diff -ruN linux-2.4.29/arch/alpha/config.in linux-2.4.29-BF6-C7_III-grsec/arch/alpha/config.in --- linux-2.4.29/arch/alpha/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/alpha/config.in 2005-03-21 17:27:01.000000000 -0700 @@ -468,3 +468,12 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -ruN linux-2.4.29/arch/alpha/kernel/osf_sys.c linux-2.4.29-BF6-C7_III-grsec/arch/alpha/kernel/osf_sys.c --- linux-2.4.29/arch/alpha/kernel/osf_sys.c 2003-06-13 08:51:29.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/alpha/kernel/osf_sys.c 2005-03-21 17:27:01.000000000 -0700 @@ -230,6 +230,11 @@ struct file *file = NULL; unsigned long ret = -EBADF; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + #if 0 if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) printk("%s: unimplemented OSF mmap flags %04lx\n", @@ -1357,6 +1362,10 @@ merely specific addresses, but regions of memory -- perhaps this feature should be incorporated into all ports? */ +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if (!(current->flags & PF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit); if (addr != -ENOMEM) @@ -1364,8 +1373,15 @@ } /* Next, try allocating at TASK_UNMAPPED_BASE. */ - addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE), - len, limit); + + addr = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if (current->flags & PF_PAX_RANDMMAP) + addr += current->mm->delta_mmap; +#endif + + addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit); if (addr != -ENOMEM) return addr; diff -ruN linux-2.4.29/arch/alpha/kernel/ptrace.c linux-2.4.29-BF6-C7_III-grsec/arch/alpha/kernel/ptrace.c --- linux-2.4.29/arch/alpha/kernel/ptrace.c 2003-06-13 08:51:29.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/alpha/kernel/ptrace.c 2005-03-21 17:27:01.000000000 -0700 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -275,6 +276,10 @@ read_unlock(&tasklist_lock); if (!child) goto out_notsk; + + if(gr_handle_ptrace(child, request)) + goto out; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out; diff -ruN linux-2.4.29/arch/alpha/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/alpha/mm/fault.c --- linux-2.4.29/arch/alpha/mm/fault.c 2002-11-28 16:53:08.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/alpha/mm/fault.c 2005-03-21 17:27:01.000000000 -0700 @@ -53,6 +53,139 @@ __reload_thread(¤t->thread); } +/* + * PaX: decide what to do with offenders (regs->pc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + * 4 when legitimate ET_EXEC was detected + */ +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + int err; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) { + if (regs->pc >= current->mm->start_code && + regs->pc < current->mm->end_code) + { + if (regs->r26 == regs->pc) + return 1; + regs->pc += current->mm->delta_exec; + return 4; + } + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + do { /* PaX: patched PLT emulation #1 */ + unsigned int ldah, ldq, jmp; + + err = get_user(ldah, (unsigned int *)regs->pc); + err |= get_user(ldq, (unsigned int *)(regs->pc+4)); + err |= get_user(jmp, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((ldah & 0xFFFF0000U)== 0x277B0000U && + (ldq & 0xFFFF0000U) == 0xA77B0000U && + jmp == 0x6BFB0000U) + { + unsigned long r27, addr; + unsigned long addrh = (ldah | 0xFFFFFFFFFFFF0000UL) << 16; + unsigned long addrl = ldq | 0xFFFFFFFFFFFF0000UL; + + addr = regs->r27 + ((addrh ^ 0x80000000UL) + 0x80000000UL) + ((addrl ^ 0x8000UL) + 0x8000UL); + err = get_user(r27, (unsigned long*)addr); + if (err) + break; + + regs->r27 = r27; + regs->pc = r27; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #2 */ + unsigned int ldah, lda, br; + + err = get_user(ldah, (unsigned int *)regs->pc); + err |= get_user(lda, (unsigned int *)(regs->pc+4)); + err |= get_user(br, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((ldah & 0xFFFF0000U)== 0x277B0000U && + (lda & 0xFFFF0000U) == 0xA77B0000U && + (br & 0xFFE00000U) == 0xC3E00000U) + { + unsigned long addr = br | 0xFFFFFFFFFFE00000UL; + unsigned long addrh = (ldah | 0xFFFFFFFFFFFF0000UL) << 16; + unsigned long addrl = lda | 0xFFFFFFFFFFFF0000UL; + + regs->r27 += ((addrh ^ 0x80000000UL) + 0x80000000UL) + ((addrl ^ 0x8000UL) + 0x8000UL); + regs->pc += 12 + (((addr ^ 0x00100000UL) + 0x00100000UL) << 2); + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation */ + unsigned int br; + + err = get_user(br, (unsigned int *)regs->pc); + + if (!err && (br & 0xFFE00000U) == 0xC3800000U) { + unsigned int br2, ldq, nop, jmp; + unsigned long addr = br | 0xFFFFFFFFFFE00000UL, resolver; + + addr = regs->pc + 4 + (((addr ^ 0x00100000UL) + 0x00100000UL) << 2); + err = get_user(br2, (unsigned int *)addr); + err |= get_user(ldq, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + err |= get_user(jmp, (unsigned int *)(addr+12)); + err |= get_user(resolver, (unsigned long *)(addr+16)); + + if (err) + break; + + if (br2 == 0xC3600000U && + ldq == 0xA77B000CU && + nop == 0x47FF041FU && + jmp == 0x6B7B0000U) + { + regs->r28 = regs->pc+4; + regs->r27 = addr+16; + regs->pc = resolver; + return 3; + } + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + /* * This routine handles page faults. It determines the address, @@ -124,7 +257,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(current, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so @@ -133,8 +266,32 @@ good_area: info.si_code = SEGV_ACCERR; if (cause < 0) { - if (!(vma->vm_flags & VM_EXEC)) + if (!(vma->vm_flags & VM_EXEC)) { + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (!(current->flags & PF_PAX_PAGEEXEC) || address != regs->pc) + goto bad_area; + + up_read(&mm->mmap_sem); + switch(pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + case 2: + case 3: + return; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 4: + return; +#endif + } + pax_report_fault(regs, (void*)regs->pc, (void*)rdusp()); + do_exit(SIGKILL); +#else goto bad_area; +#endif + } } else if (!cause) { /* Allow reads even for write-only mappings */ if (!(vma->vm_flags & (VM_READ | VM_WRITE))) diff -ruN linux-2.4.29/arch/arm/config.in linux-2.4.29-BF6-C7_III-grsec/arch/arm/config.in --- linux-2.4.29/arch/arm/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/arm/config.in 2005-03-21 17:27:01.000000000 -0700 @@ -736,3 +736,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/arm/mm/fault-common.c linux-2.4.29-BF6-C7_III-grsec/arch/arm/mm/fault-common.c --- linux-2.4.29/arch/arm/mm/fault-common.c 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/arm/mm/fault-common.c 2005-03-21 17:27:01.000000000 -0700 @@ -254,7 +254,7 @@ goto survive; check_stack: - if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) + if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(tsk, vma, addr)) goto good_area; out: return fault; diff -ruN linux-2.4.29/arch/cris/config.in linux-2.4.29-BF6-C7_III-grsec/arch/cris/config.in --- linux-2.4.29/arch/cris/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/cris/config.in 2005-03-21 17:27:01.000000000 -0700 @@ -276,3 +276,12 @@ source crypto/Config.in source lib/Config.in endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -ruN linux-2.4.29/arch/cris/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/cris/mm/fault.c --- linux-2.4.29/arch/cris/mm/fault.c 2004-02-18 06:36:30.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/cris/mm/fault.c 2005-03-21 17:27:01.000000000 -0700 @@ -327,7 +327,7 @@ if (address + PAGE_SIZE < rdusp()) goto bad_area; } - if (expand_stack(vma, address)) + if (expand_stack(tsk, vma, address)) goto bad_area; /* diff -ruN linux-2.4.29/arch/i386/Makefile linux-2.4.29-BF6-C7_III-grsec/arch/i386/Makefile --- linux-2.4.29/arch/i386/Makefile 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/Makefile 2005-03-21 17:27:01.000000000 -0700 @@ -118,6 +118,9 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE + $(CPP) -C -P -I$(HPATH) -D__KERNEL__ -imacros $(HPATH)/linux/config.h -imacros $(HPATH)/asm-i386/segment.h -imacros $(HPATH)/asm-i386/page.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds + vmlinux: arch/i386/vmlinux.lds FORCE: ; @@ -154,6 +157,7 @@ @$(MAKEBOOT) clean archmrproper: + rm -f arch/i386/vmlinux.lds archdep: @$(MAKEBOOT) dep diff -ruN linux-2.4.29/arch/i386/boot/bootsect.S linux-2.4.29-BF6-C7_III-grsec/arch/i386/boot/bootsect.S --- linux-2.4.29/arch/i386/boot/bootsect.S 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/boot/bootsect.S 2005-03-21 17:27:01.000000000 -0700 @@ -237,7 +237,7 @@ #ifdef __BIG_KERNEL__ # look in setup.S for bootsect_kludge bootsect_kludge = 0x220 # 0x200 + 0x20 which is the size of the - lcall bootsect_kludge # bootsector + bootsect_kludge offset + lcall *bootsect_kludge # bootsector + bootsect_kludge offset #else movw %es, %ax subw $SYSSEG, %ax diff -ruN linux-2.4.29/arch/i386/boot/setup.S linux-2.4.29-BF6-C7_III-grsec/arch/i386/boot/setup.S --- linux-2.4.29/arch/i386/boot/setup.S 2004-02-18 06:36:30.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/boot/setup.S 2005-03-21 17:27:01.000000000 -0700 @@ -637,7 +637,7 @@ cmpw $0, %cs:realmode_swtch jz rmodeswtch_normal - lcall %cs:realmode_swtch + lcall *%cs:realmode_swtch jmp rmodeswtch_end diff -ruN linux-2.4.29/arch/i386/config.in linux-2.4.29-BF6-C7_III-grsec/arch/i386/config.in --- linux-2.4.29/arch/i386/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/config.in 2005-03-21 17:27:16.635964048 -0700 @@ -99,6 +99,7 @@ fi if [ "$CONFIG_M686" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_HAS_TSC y define_bool CONFIG_X86_GOOD_APIC y bool 'PGE extensions (not for Cyrix/Transmeta)' CONFIG_X86_PGE @@ -108,6 +109,7 @@ fi if [ "$CONFIG_MPENTIUMIII" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_HAS_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_PGE y @@ -116,6 +118,7 @@ fi if [ "$CONFIG_MPENTIUM4" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 7 + define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_HAS_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_PGE y @@ -135,6 +138,7 @@ fi if [ "$CONFIG_MK7" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 6 + define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_HAS_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_USE_3DNOW y @@ -277,6 +281,7 @@ define_bool CONFIG_PCI y define_bool CONFIG_ISA n else + source drivers/cobalt/Config.in if [ "$CONFIG_SMP" = "y" ]; then define_bool CONFIG_X86_IO_APIC y define_bool CONFIG_X86_LOCAL_APIC y @@ -487,3 +492,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/i386/config.in.orig linux-2.4.29-BF6-C7_III-grsec/arch/i386/config.in.orig --- linux-2.4.29/arch/i386/config.in.orig 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/config.in.orig 2005-03-21 17:27:01.033284185 -0700 @@ -0,0 +1,501 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/config-language.txt. +# +mainmenu_name "Linux Kernel Configuration" + +define_bool CONFIG_X86 y +define_bool CONFIG_SBUS n + +define_bool CONFIG_UID16 y + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool ' Set version information on all module symbols' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment +comment 'Processor type and features' +choice 'Processor family' \ + "386 CONFIG_M386 \ + 486 CONFIG_M486 \ + 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ + Pentium-Classic CONFIG_M586TSC \ + Pentium-MMX CONFIG_M586MMX \ + Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \ + Pentium-III/Celeron(Coppermine) CONFIG_MPENTIUMIII \ + Pentium-4 CONFIG_MPENTIUM4 \ + K6/K6-II/K6-III CONFIG_MK6 \ + Athlon/Duron/K7 CONFIG_MK7 \ + Opteron/Athlon64/Hammer/K8 CONFIG_MK8 \ + Elan CONFIG_MELAN \ + Crusoe CONFIG_MCRUSOE \ + Winchip-C6 CONFIG_MWINCHIPC6 \ + Winchip-2 CONFIG_MWINCHIP2 \ + Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ + CyrixIII/VIA-C3 CONFIG_MCYRIXIII \ + VIA-C3-2 CONFIG_MVIAC3_2" Pentium-Pro +# +# Define implied options from the CPU selection here +# + +if [ "$CONFIG_M386" = "y" ]; then + define_bool CONFIG_X86_CMPXCHG n + define_bool CONFIG_X86_XADD n + define_int CONFIG_X86_L1_CACHE_SHIFT 4 + define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y + define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n + define_bool CONFIG_X86_PPRO_FENCE y + define_bool CONFIG_X86_F00F_WORKS_OK n +else + define_bool CONFIG_X86_WP_WORKS_OK y + define_bool CONFIG_X86_INVLPG y + define_bool CONFIG_X86_CMPXCHG y + define_bool CONFIG_X86_XADD y + define_bool CONFIG_X86_BSWAP y + define_bool CONFIG_X86_POPAD_OK y + define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n + define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y +fi +if [ "$CONFIG_M486" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 4 + define_bool CONFIG_X86_USE_STRING_486 y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_PPRO_FENCE y + define_bool CONFIG_X86_F00F_WORKS_OK n +fi +if [ "$CONFIG_M586" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_USE_STRING_486 y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_PPRO_FENCE y + define_bool CONFIG_X86_F00F_WORKS_OK n +fi +if [ "$CONFIG_M586TSC" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_USE_STRING_486 y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_PPRO_FENCE y + define_bool CONFIG_X86_F00F_WORKS_OK n +fi +if [ "$CONFIG_M586MMX" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_USE_STRING_486 y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_PPRO_FENCE y + define_bool CONFIG_X86_F00F_WORKS_OK n +fi +if [ "$CONFIG_M686" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_GOOD_APIC y + bool 'PGE extensions (not for Cyrix/Transmeta)' CONFIG_X86_PGE + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_PPRO_FENCE y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MPENTIUMIII" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_PGE y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MPENTIUM4" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 7 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_PGE y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MK6" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y +fi +if [ "$CONFIG_MK8" = "y" ]; then + # for now. may later want to add SSE support and optimized + # functions + define_bool CONFIG_MK7 y +fi +if [ "$CONFIG_MK7" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 6 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_USE_3DNOW y + define_bool CONFIG_X86_PGE y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MELAN" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 4 + define_bool CONFIG_X86_USE_STRING_486 y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MCYRIXIII" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_USE_3DNOW y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MVIAC3_2" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MCRUSOE" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MWINCHIPC6" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MWINCHIP2" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi +if [ "$CONFIG_MWINCHIP3D" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y + define_bool CONFIG_X86_F00F_WORKS_OK y +fi + +bool 'Machine Check Exception' CONFIG_X86_MCE + +tristate 'Toshiba Laptop support' CONFIG_TOSHIBA +tristate 'Dell laptop support' CONFIG_I8K + +tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE +tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR +tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)' CONFIG_EDD +fi + +choice 'High Memory Support' \ + "off CONFIG_NOHIGHMEM \ + 4GB CONFIG_HIGHMEM4G \ + 64GB CONFIG_HIGHMEM64G" off +if [ "$CONFIG_HIGHMEM4G" = "y" -o "$CONFIG_HIGHMEM64G" = "y" ]; then + define_bool CONFIG_HIGHMEM y +else + define_bool CONFIG_HIGHMEM n +fi +if [ "$CONFIG_HIGHMEM64G" = "y" ]; then + define_bool CONFIG_X86_PAE y +fi + +if [ "$CONFIG_HIGHMEM" = "y" ]; then + bool 'HIGHMEM I/O support' CONFIG_HIGHIO +fi + +bool 'Math emulation' CONFIG_MATH_EMULATION +bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR +bool 'Symmetric multi-processing support' CONFIG_SMP +if [ "$CONFIG_SMP" != "y" ]; then + bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC + dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC + if [ "$CONFIG_X86_UP_APIC" = "y" ]; then + define_bool CONFIG_X86_LOCAL_APIC y + fi + if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then + define_bool CONFIG_X86_IO_APIC y + fi +else + int 'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32 + bool 'Multi-node NUMA system support' CONFIG_X86_NUMA + if [ "$CONFIG_X86_NUMA" = "y" ]; then + #Platform Choices + bool ' Multiquad (IBM/Sequent) NUMAQ support' CONFIG_X86_NUMAQ + if [ "$CONFIG_X86_NUMAQ" = "y" ]; then + define_bool CONFIG_X86_CLUSTERED_APIC y + define_bool CONFIG_MULTIQUAD y + fi + bool ' IBM x440 (Summit/EXA) support' CONFIG_X86_SUMMIT + if [ "$CONFIG_X86_SUMMIT" = "y" ]; then + define_bool CONFIG_X86_CLUSTERED_APIC y + fi + fi +fi + +if [ "$CONFIG_X86_NUMA" != "y" ]; then + bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE + if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then + define_bool CONFIG_X86_TSC y + fi +fi + +if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then + define_bool CONFIG_HAVE_DEC_LOCK y +fi +endmenu + +mainmenu_option next_comment +comment 'General setup' + +bool 'Networking support' CONFIG_NET + +# Visual Workstation support is utterly broken. +# If you want to see it working mail an VW540 to hch@infradead.org 8) +#bool 'SGI Visual Workstation support' CONFIG_VISWS +if [ "$CONFIG_VISWS" = "y" ]; then + define_bool CONFIG_X86_VISWS_APIC y + define_bool CONFIG_X86_LOCAL_APIC y + define_bool CONFIG_PCI y + define_bool CONFIG_ISA n +else + if [ "$CONFIG_SMP" = "y" ]; then + define_bool CONFIG_X86_IO_APIC y + define_bool CONFIG_X86_LOCAL_APIC y + fi + bool 'PCI support' CONFIG_PCI + if [ "$CONFIG_PCI" = "y" ]; then + choice ' PCI access mode' \ + "BIOS CONFIG_PCI_GOBIOS \ + Direct CONFIG_PCI_GODIRECT \ + Any CONFIG_PCI_GOANY" Any + if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then + define_bool CONFIG_PCI_BIOS y + fi + if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then + define_bool CONFIG_PCI_DIRECT y + fi + fi + bool 'ISA bus support' CONFIG_ISA +fi + +source drivers/pci/Config.in + +bool 'EISA support' CONFIG_EISA + +if [ "$CONFIG_VISWS" != "y" ]; then + bool 'MCA support' CONFIG_MCA +else + define_bool CONFIG_MCA n +fi + +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + +if [ "$CONFIG_HOTPLUG" = "y" ] ; then + source drivers/pcmcia/Config.in + source drivers/hotplug/Config.in +else + define_bool CONFIG_PCMCIA n + define_bool CONFIG_HOTPLUG_PCI n +fi + +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi +tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER + +bool 'Power Management support' CONFIG_PM + +dep_tristate ' Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM +if [ "$CONFIG_APM" != "n" ]; then + bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND + bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE + bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE + bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK + bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT + bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS + bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF +fi + +source drivers/acpi/Config.in + +endmenu + +source drivers/mtd/Config.in + +source drivers/parport/Config.in + +source drivers/pnp/Config.in + +source drivers/block/Config.in + +source drivers/md/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +source drivers/telephony/Config.in + +mainmenu_option next_comment +comment 'ATA/IDE/MFM/RLL support' + +tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE + +if [ "$CONFIG_IDE" != "n" ]; then + source drivers/ide/Config.in +else + define_bool CONFIG_BLK_DEV_HD n +fi +endmenu + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in +fi +endmenu + +source drivers/message/fusion/Config.in + +source drivers/ieee1394/Config.in + +source drivers/message/i2o/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" -o "$CONFIG_ATM" = "m" ]; then + source drivers/atm/Config.in + fi + fi + endmenu +fi + +source net/ax25/Config.in + +source net/irda/Config.in + +mainmenu_option next_comment +comment 'ISDN subsystem' +if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in + fi +fi +endmenu + +if [ "$CONFIG_ISA" = "y" ]; then + mainmenu_option next_comment + comment 'Old CD-ROM drivers (not SCSI, not IDE)' + + bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI + if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in + fi + endmenu +fi + +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in +source drivers/char/Config.in + +#source drivers/misc/Config.in + +source drivers/media/Config.in + +source fs/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + bool 'VGA text console' CONFIG_VGA_CONSOLE + bool 'Video mode selection support' CONFIG_VIDEO_SELECT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE + source drivers/video/Config.in + fi + endmenu +fi + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +source drivers/usb/Config.in + +source net/bluetooth/Config.in + +mainmenu_option next_comment +comment 'Kernel hacking' + +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + bool ' Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW + bool ' Debug high memory support' CONFIG_DEBUG_HIGHMEM + bool ' Debug memory allocations' CONFIG_DEBUG_SLAB + bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT + bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ + bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER +fi + +int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0 + +endmenu + +source crypto/Config.in +source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/i386/kernel/Makefile linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/Makefile --- linux-2.4.29/arch/i386/kernel/Makefile 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/Makefile 2005-03-21 17:27:16.635964048 -0700 @@ -43,5 +43,6 @@ obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o obj-$(CONFIG_EDD) += edd.o +obj-$(CONFIG_COBALT_RAQ) += cobalt.o include $(TOPDIR)/Rules.make diff -ruN linux-2.4.29/arch/i386/kernel/apm.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/apm.c --- linux-2.4.29/arch/i386/kernel/apm.c 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/apm.c 2005-03-21 17:27:01.000000000 -0700 @@ -614,7 +614,7 @@ __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "lcall *%%ss:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" "setc %%al\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" @@ -666,7 +666,7 @@ __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "lcall *%%ss:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" "setc %%bl\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" @@ -1985,6 +1985,12 @@ __va((unsigned long)0x40 << 4)); _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4)); +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + set_base(gdt2[APM_40 >> 3], + __va((unsigned long)0x40 << 4)); + _set_limit((char *)&gdt2[APM_40 >> 3], 4095 - (0x40 << 4)); +#endif + apm_bios_entry.offset = apm_info.bios.offset; apm_bios_entry.segment = APM_CS; set_base(gdt[APM_CS >> 3], @@ -1993,6 +1999,16 @@ __va((unsigned long)apm_info.bios.cseg_16 << 4)); set_base(gdt[APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + set_base(gdt2[APM_CS >> 3], + __va((unsigned long)apm_info.bios.cseg << 4)); + set_base(gdt2[APM_CS_16 >> 3], + __va((unsigned long)apm_info.bios.cseg_16 << 4)); + set_base(gdt2[APM_DS >> 3], + __va((unsigned long)apm_info.bios.dseg << 4)); +#endif + #ifndef APM_RELAX_SEGMENTS if (apm_info.bios.version == 0x100) { #endif @@ -2002,6 +2018,13 @@ _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1); /* For the DEC Hinote Ultra CT475 (and others?) */ _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + _set_limit((char *)&gdt2[APM_CS >> 3], 64 * 1024 - 1); + _set_limit((char *)&gdt2[APM_CS_16 >> 3], 64 * 1024 - 1); + _set_limit((char *)&gdt2[APM_DS >> 3], 64 * 1024 - 1); +#endif + #ifndef APM_RELAX_SEGMENTS } else { _set_limit((char *)&gdt[APM_CS >> 3], @@ -2010,6 +2033,16 @@ (apm_info.bios.cseg_16_len - 1) & 0xffff); _set_limit((char *)&gdt[APM_DS >> 3], (apm_info.bios.dseg_len - 1) & 0xffff); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + _set_limit((char *)&gdt2[APM_CS >> 3], + (apm_info.bios.cseg_len - 1) & 0xffff); + _set_limit((char *)&gdt2[APM_CS_16 >> 3], + (apm_info.bios.cseg_16_len - 1) & 0xffff); + _set_limit((char *)&gdt2[APM_DS >> 3], + (apm_info.bios.dseg_len - 1) & 0xffff); +#endif + } #endif diff -ruN linux-2.4.29/arch/i386/kernel/cobalt.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/cobalt.c --- linux-2.4.29/arch/i386/kernel/cobalt.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/cobalt.c 2005-03-21 17:27:16.636963900 -0700 @@ -0,0 +1,283 @@ +/* $Id: cobalt.c,v 1.34 2002/11/04 17:54:14 thockin Exp $ */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NMI_PS 10 + +static inline void ledonoff(unsigned long on, unsigned long off); + +static u8 last_err; +static u32 last_address; +static unsigned long nmi_repeats; +static struct timer_list nmi_timer; +static int timer_added; +static unsigned long nmi_count; +static spinlock_t nmi_state_lock = SPIN_LOCK_UNLOCKED; + +/* clla this holding nmi_state_lock */ +static inline void +do_repeats(void) +{ + if (nmi_repeats) { + printk("NMI: last error repeated %lu times\n", nmi_repeats); + nmi_repeats = 0; + } +} + +static void +nmi_throttle_fn(unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave(&nmi_state_lock, flags); + + /* clear any repeated NMIs */ + do_repeats(); + + /* have we had a lot of errors this second */ + if (nmi_count > MAX_NMI_PS) { + printk("NMI: %lu messages were throttled\n", + nmi_count - MAX_NMI_PS); + nmi_count = 0; + } + + /* de-activate the timer - will be reactivated by an NMI */ + del_timer(&nmi_timer); + timer_added = 0; + + spin_unlock_irqrestore(&nmi_state_lock, flags); +} + +void +cobalt_nmi(unsigned char reason, struct pt_regs *regs) +{ + if (cobt_is_5k()) { + static struct pci_dev *cnb_dev; + u8 err; + u32 address = 0; + unsigned long flags; + + /* find our memory controller */ + if (!cnb_dev) { + cnb_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_LE, NULL); + } + if (!cnb_dev) { + EPRINTK("can't find north bridge for NMI status\n"); + return; + } + + /* read the error number */ + pci_read_config_byte(cnb_dev, 0x47, &err); + + /* if a memory error was detected, where? */ + if (err & 0x06) { + pci_read_config_dword(cnb_dev, 0x94, &address); + } + + spin_lock_irqsave(&nmi_state_lock, flags); + + /* set up the timer, if it isn't set to go already */ + if (!timer_added) { + init_timer(&nmi_timer); + nmi_timer.expires = jiffies + HZ; + nmi_timer.function = nmi_throttle_fn; + add_timer(&nmi_timer); + timer_added = 1; + } + + /* if we already printed this error */ + if (last_err && err == last_err && address == last_address) { + nmi_repeats++; + spin_unlock_irqrestore(&nmi_state_lock, flags); + } else { + unsigned long nmi_now; + + /* different error - show repeats */ + do_repeats(); + + /* we only want to do a few messages per second */ + nmi_now = nmi_count++; + + spin_unlock_irqrestore(&nmi_state_lock, flags); + + /* generate a new message */ + if (nmi_now < MAX_NMI_PS) { + /* only remember NMIs that we can print */ + last_err = err; + last_address = address; + + printk("NMI:"); + if (err & 0x40) + printk(" (PCI tx data error)"); + if (err & 0x20) + printk(" (PCI rx data error)"); + if (err & 0x10) + printk(" (PCI address error)"); + if (err & 0x04) + printk(" (DRAM uncorrectable error)"); + if (err & 0x02) + printk(" (DRAM correctable error)"); + if (err & 0x01) + printk(" (Shutdown cycle detected)"); + + if (err & 0x06) { + u8 row, dimm, ecc; + + row = (address >> 29) & 0x7; + pci_read_config_byte(cnb_dev, + 0x7c + (row >> 1), &dimm); + dimm = ((row & 1) ? + (dimm >> 4) : dimm) & 0xf; + pci_read_config_byte(cnb_dev, 0xe8, + &ecc); + + printk(" [memory row %d, DIMM type %d, " + "col=0x%x, row=0x%x, ECC=0x%x]", + row, dimm, + (address >> 15) & 0x3fff, + address & 0x7fff, ecc); + } + printk("\n"); + } + } + + /* clear errors */ + pci_write_config_byte(cnb_dev, 0x47, err); + } else { + /* TODO: make throttling generic, handle GP NMIs */ + printk("NMI: unknown error\n"); + } +} + +void +cobalt_restart(void) +{ + if (cobt_is_3k()) { + /* kick watchdog */ + cobalt_wdt_trigger_reboot(); + } else if (cobt_is_5k()) { + /* set "Enable Hard Reset" bit to 1 */ + outb(0x02, 0x0cf9); + + /* 0-to-1 transition of bit 2 will cause reset of processor */ + outb(0x06, 0x0cf9); + } + mdelay(3000); + + /* we should not get here unless there is a BAD error */ + EPRINTK("can not restart - halting\n"); + machine_halt(); +} + +void +cobalt_halt(void) +{ + int haltok = current_cpu_data.hlt_works_ok; + + if (cobt_is_5k()) { + /* we have soft power-off */ + machine_power_off(); + } + + /* + * we want to do cpu_idle, but we don't actually want to + * call cpu_idle. bleah. + */ + while (1) { + ledonoff(HZ >> 1, HZ >> 1); + if (haltok) { + __asm__("hlt"); + } + } +} + +static inline void +ledonoff(unsigned long on, unsigned long off) +{ +#ifdef CONFIG_COBALT_LED + unsigned long start; + int haltok = current_cpu_data.hlt_works_ok; + + if (on) { + start = jiffies; + cobalt_led_set(cobalt_led_get() | LED_SHUTDOWN); + while (jiffies < start + on) { + if (haltok) __asm__("hlt"); + } + } + + if (off) { + start = jiffies; + cobalt_led_set(cobalt_led_get() & ~LED_SHUTDOWN); + while (jiffies < start + off) { + if (haltok) __asm__("hlt"); + } + } +#endif +} + +void +cobalt_power_off(void) +{ + u16 addr; + + if (cobt_is_monterey()) { + u8 val; + /* use card control reg. 7 to select logical device 2 (APC) */ + addr = superio_ldev_base(PC87317_DEV_RTC); + + /* set up bank 2 */ + outb(PC87317_RTC_CRA, addr); + val = inb(addr + 1) & 0x8f; + outb(val | PC87317_RTC_BANK_2, addr + 1); + + /* power off the machine with APCR1 */ + outb(PC87317_APCR1, addr); + val = inb(addr + 1); + outb(0x20 | val, addr + 1); + } else if (cobt_is_alpine()) { + int i; + /* clear status bits, base addr 3 */ + addr = superio_ldev_base_n(PC87417_DEV_SWC, 3); + for (i = 0; i < 4; i++) { + /* + * if we have an event while running, + * we can't halt unless we clear these + * */ + outb(0xff, addr+i); + } + + /* set sleep state, base addr 2 */ + addr = superio_ldev_base_n(PC87417_DEV_SWC, 2); + /* PM1b_CNT_HIGH @offset 1 - set state to S5 */ + outb(0x34, addr+1); + } + mdelay(3000); + EPRINTK("can not power off\n"); +} + +/* put arch specific stuff to run at init time here */ +static int __init +cobalt_arch_init(void) +{ + return 0; +} +module_init(cobalt_arch_init); diff -ruN linux-2.4.29/arch/i386/kernel/entry.S linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/entry.S --- linux-2.4.29/arch/i386/kernel/entry.S 2003-06-13 08:51:29.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/entry.S 2005-03-21 17:27:01.000000000 -0700 @@ -209,6 +209,17 @@ jae badsys call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value + +#ifdef CONFIG_GRKERNSEC_PAX_RANDKSTACK + cli # need_resched and signals atomic test + cmpl $0,need_resched(%ebx) + jne reschedule + cmpl $0,sigpending(%ebx) + jne signal_return + call SYMBOL_NAME(pax_randomize_kstack) + jmp restore_all +#endif + ENTRY(ret_from_sys_call) cli # need_resched and signals atomic test cmpl $0,need_resched(%ebx) @@ -389,8 +400,56 @@ jmp error_code ENTRY(page_fault) +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + ALIGN + pushl $ SYMBOL_NAME(pax_do_page_fault) +#else pushl $ SYMBOL_NAME(do_page_fault) +#endif + +#ifndef CONFIG_GRKERNSEC_PAX_EMUTRAMP jmp error_code +#else + 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 +#endif ENTRY(machine_check) pushl $0 @@ -402,7 +461,7 @@ pushl $ SYMBOL_NAME(do_spurious_interrupt_bug) jmp error_code -.data +.section .rodata, "a",@progbits ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ .long SYMBOL_NAME(sys_exit) diff -ruN linux-2.4.29/arch/i386/kernel/head.S linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/head.S --- linux-2.4.29/arch/i386/kernel/head.S 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/head.S 2005-03-21 17:27:01.000000000 -0700 @@ -37,10 +37,17 @@ #define X86_VENDOR_ID CPU_PARAMS+36 /* tied to NCAPINTS in cpufeature.h */ /* + * Real beginning of normal "text" segment + */ +ENTRY(stext) +ENTRY(_stext) + +/* * swapper_pg_dir is the main page directory, address 0x00101000 * * On entry, %esi points to the real-mode code as a 32-bit pointer. */ +.global startup_32 startup_32: /* * Set segments to known values @@ -51,9 +58,23 @@ movl %eax,%es movl %eax,%fs movl %eax,%gs + #ifdef CONFIG_SMP - orw %bx,%bx - jz 1f + orw %bx,%bx + jnz 1f +#endif + +/* + * Clear BSS first so that there are no surprises... + * No need to cld as DF is already clear from cld above... + */ + xorl %eax,%eax + movl $ SYMBOL_NAME(__bss_start) - __PAGE_OFFSET,%edi + movl $ SYMBOL_NAME(__bss_end) - __PAGE_OFFSET,%ecx + subl %edi,%ecx + rep + stosb +1: /* * New page tables may be in 4Mbyte page mode and may @@ -71,22 +92,28 @@ */ #define cr4_bits mmu_cr4_features-__PAGE_OFFSET cmpl $0,cr4_bits - je 3f + je 1f movl %cr4,%eax # Turn on paging options (PSE,PAE,..) orl cr4_bits,%eax movl %eax,%cr4 - jmp 3f 1: + +#ifdef CONFIG_SMP + orw %bx,%bx + jnz 3f #endif + /* * Initialize page tables */ movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */ - movl $007,%eax /* "007" doesn't mean with right to kill, but - PRESENT+RW+USER */ + movl $0x63,%eax /* "0x63" is PRESENT+RW+ACCESSED+DIRTY */ 2: stosl +#ifdef CONFIG_X86_PAE + addl $4,%edi +#endif add $0x1000,%eax - cmp $empty_zero_page-__PAGE_OFFSET,%edi + cmp $0x01000063,%eax jne 2b /* @@ -100,9 +127,19 @@ movl %eax,%cr0 /* ..and set paging (PG) bit */ jmp 1f /* flush the prefetch-queue */ 1: + +#if !defined(CONFIG_GRKERNSEC_PAX_KERNEXEC) || defined(CONFIG_SMP) + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + orw %bx,%bx + jz 1f +#endif + movl $1f,%eax jmp *%eax /* make sure eip is relocated */ 1: +#endif + /* Set up the stack pointer */ lss stack_start,%esp @@ -115,16 +152,21 @@ 1: #endif /* CONFIG_SMP */ -/* - * Clear BSS first so that there are no surprises... - * No need to cld as DF is already clear from cld above... - */ - xorl %eax,%eax - movl $ SYMBOL_NAME(__bss_start),%edi - movl $ SYMBOL_NAME(_end),%ecx - subl %edi,%ecx - rep - stosb +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + movl $ __KERNEL_TEXT_OFFSET,%eax + movw %ax,(SYMBOL_NAME(gdt_table) + 18) + rorl $16,%eax + movb %al,(SYMBOL_NAME(gdt_table) + 20) + movb %ah,(SYMBOL_NAME(gdt_table) + 23) + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + movb %al,(SYMBOL_NAME(gdt_table2) + 20) + movb %ah,(SYMBOL_NAME(gdt_table2) + 23) + rorl $16,%eax + movw %ax,(SYMBOL_NAME(gdt_table2) + 18) +#endif + +#endif /* * start system 32-bit setup. We need to re-do some of the things done @@ -272,8 +314,6 @@ jmp L6 # main should never return here, but # just in case, we know what happens. -ready: .byte 0 - /* * We depend on ET to be correct. This checks for 287/387. */ @@ -319,13 +359,6 @@ jne rp_sidt ret -ENTRY(stack_start) - .long SYMBOL_NAME(init_task_union)+8192 - .long __KERNEL_DS - -/* This is the default interrupt "handler" :-) */ -int_msg: - .asciz "Unknown interrupt\n" ALIGN ignore_int: cld @@ -347,6 +380,17 @@ popl %eax iret +.section .rodata,"a" +ready: .byte 0 + +ENTRY(stack_start) + .long SYMBOL_NAME(init_task_union)+8192 + .long __KERNEL_DS + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n" + /* * The interrupt descriptor table has room for 256 idt's, * the global descriptor table is dependent on the number @@ -372,54 +416,146 @@ SYMBOL_NAME(gdt): .long SYMBOL_NAME(gdt_table) +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC +.globl SYMBOL_NAME(gdt2) + .word 0 +gdt_descr2: + .word GDT_ENTRIES*8-1 +SYMBOL_NAME(gdt2): + .long SYMBOL_NAME(gdt_table2) +#endif + /* - * This is initialized to create an identity-mapping at 0-8M (for bootup - * purposes) and another mapping of the 0-8M area at virtual address + * This is initialized to create an identity-mapping at 0-16M (for bootup + * purposes) and another mapping of the 0-16M area at virtual address * PAGE_OFFSET. */ -.org 0x1000 +.section .data.swapper_pg_dir,"a",@progbits ENTRY(swapper_pg_dir) - .long 0x00102007 - .long 0x00103007 - .fill BOOT_USER_PGD_PTRS-2,4,0 - /* default: 766 entries */ - .long 0x00102007 - .long 0x00103007 - /* default: 254 entries */ - .fill BOOT_KERNEL_PGD_PTRS-2,4,0 +#ifdef CONFIG_X86_PAE + .long swapper_pm_dir-__PAGE_OFFSET+1 + .long 0 + .long swapper_pm_dir+512*8-__PAGE_OFFSET+1 + .long 0 + .long swapper_pm_dir+512*16-__PAGE_OFFSET+1 + .long 0 + .long swapper_pm_dir+512*24-__PAGE_OFFSET+1 + .long 0 +#else + .long pg0-__PAGE_OFFSET+63 + .long pg0+1024*4-__PAGE_OFFSET+63 + .long pg0+1024*8-__PAGE_OFFSET+63 + .long pg0+1024*12-__PAGE_OFFSET+63 + .fill BOOT_USER_PGD_PTRS-4,4,0 + /* default: 764 entries */ + .long pg0-__PAGE_OFFSET+67 + .long pg0+1024*4-__PAGE_OFFSET+63 + .long pg0+1024*8-__PAGE_OFFSET+63 + .long pg0+1024*12-__PAGE_OFFSET+63 + /* default: 252 entries */ + .fill BOOT_KERNEL_PGD_PTRS-4,4,0 +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC +ENTRY(kernexec_pg_dir) +#ifdef CONFIG_X86_PAE + .long kernexec_pm_dir-__PAGE_OFFSET+1 + .long 0 + .long kernexec_pm_dir+512*8-__PAGE_OFFSET+1 + .long 0 + .long kernexec_pm_dir+512*16-__PAGE_OFFSET+1 + .long 0 + .long kernexec_pm_dir+512*24-__PAGE_OFFSET+1 + .long 0 +#else + .fill 1024,4,0 +#endif +#endif + +#ifdef CONFIG_X86_PAE +.section .data.swapper_pm_dir,"a",@progbits +ENTRY(swapper_pm_dir) + .long pg0-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*8-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*16-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*24-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*32-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*40-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*48-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*56-__PAGE_OFFSET+63 + .long 0 + .fill BOOT_USER_PMD_PTRS-8,8,0 + /* default: 1024+512-4 entries */ + .long pg0-__PAGE_OFFSET+67 + .long 0 + .long pg0+512*8-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*16-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*24-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*32-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*40-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*48-__PAGE_OFFSET+63 + .long 0 + .long pg0+512*56-__PAGE_OFFSET+63 + .long 0 + /* default: 512-4 entries */ + .fill BOOT_KERNEL_PMD_PTRS-8,8,0 + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC +ENTRY(kernexec_pm_dir) + .fill 512,8,0 + .fill 512,8,0 + .fill 512,8,0 + .fill 512,8,0 +#endif +#endif /* - * The page tables are initialized to only 8MB here - the final page + * The page tables are initialized to only 16MB here - the final page * tables are set up later depending on memory size. */ -.org 0x2000 +.section .data.pg0,"a",@progbits ENTRY(pg0) + .fill 1024*4,4,0 -.org 0x3000 -ENTRY(pg1) +#ifdef CONFIG_X86_PAE + .fill 1024*4,4,0 +#endif /* * empty_zero_page must immediately follow the page tables ! (The * initialization loop counts until empty_zero_page) */ - -.org 0x4000 +.section .rodata.empty_zero_page,"a",@progbits ENTRY(empty_zero_page) - -.org 0x5000 + .fill 1024,4,0 /* - * Real beginning of normal "text" segment + * The IDT has to be page-aligned to simplify the Pentium + * F0 0F bug workaround. We have a special link segment + * for this. */ -ENTRY(stext) -ENTRY(_stext) +.section .rodata.idt,"a",@progbits +ENTRY(idt_table) + .fill 256,8,0 /* * This starts the data section. Note that the above is all * in the text section because it has alignment requirements * that we cannot fulfill any other way. */ -.data +.section .rodata,"a",@progbits ALIGN /* @@ -430,19 +566,41 @@ */ ENTRY(gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ - .quad 0x0000000000000000 /* not used */ - .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ - .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ - .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */ - .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ + .quad 0x0000000000000000 /* not used */ + .quad 0x00cf9b000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ + .quad 0x00cf93000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ + .quad 0x00cffb000000ffff /* 0x23 user 4GB code at 0x00000000 */ + .quad 0x00cff3000000ffff /* 0x2b user 4GB data at 0x00000000 */ + .quad 0x0000000000000000 /* not used */ + .quad 0x0000000000000000 /* not used */ + /* + * The APM segments have byte granularity and their bases + * and limits are set at run time. + */ + .quad 0x0040930000000000 /* 0x40 APM set up for bad BIOS's */ + .quad 0x00409b0000000000 /* 0x48 APM CS code */ + .quad 0x00009b0000000000 /* 0x50 APM CS 16 code (16 bit) */ + .quad 0x0040930000000000 /* 0x58 APM DS data */ + .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */ + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC +ENTRY(gdt_table2) + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x0000000000000000 /* not used */ + .quad 0x00cf9b000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ + .quad 0x00cf93000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ + .quad 0x60c5fb000000ffff /* 0x23 user 1.5GB code at 0x60000000 */ + .quad 0x00c5f3000000ffff /* 0x2b user 1.5GB data at 0x00000000 */ + .quad 0x0000000000000000 /* not used */ .quad 0x0000000000000000 /* not used */ /* * The APM segments have byte granularity and their bases * and limits are set at run time. */ - .quad 0x0040920000000000 /* 0x40 APM set up for bad BIOS's */ - .quad 0x00409a0000000000 /* 0x48 APM CS code */ - .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */ - .quad 0x0040920000000000 /* 0x58 APM DS data */ + .quad 0x0040930000000000 /* 0x40 APM set up for bad BIOS's */ + .quad 0x00409b0000000000 /* 0x48 APM CS code */ + .quad 0x00009b0000000000 /* 0x50 APM CS 16 code (16 bit) */ + .quad 0x0040930000000000 /* 0x58 APM DS data */ .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */ +#endif diff -ruN linux-2.4.29/arch/i386/kernel/i386_ksyms.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/i386_ksyms.c --- linux-2.4.29/arch/i386/kernel/i386_ksyms.c 2004-04-14 07:05:25.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/i386_ksyms.c 2005-03-21 17:27:01.000000000 -0700 @@ -74,6 +74,9 @@ EXPORT_SYMBOL(get_cmos_time); EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC +EXPORT_SYMBOL(gdt2); +#endif EXPORT_SYMBOL(empty_zero_page); #ifdef CONFIG_DEBUG_IOVIRT diff -ruN linux-2.4.29/arch/i386/kernel/init_task.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/init_task.c --- linux-2.4.29/arch/i386/kernel/init_task.c 2001-09-17 16:29:09.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/init_task.c 2005-03-21 17:27:01.000000000 -0700 @@ -29,5 +29,9 @@ * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC +struct tss_struct init_tss[NR_CPUS] __attribute__((__aligned__(SMP_CACHE_BYTES), __section__(".rodata"))) = { [0 ... NR_CPUS-1] = INIT_TSS }; +#else +struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +#endif diff -ruN linux-2.4.29/arch/i386/kernel/ioport.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/ioport.c --- linux-2.4.29/arch/i386/kernel/ioport.c 2003-06-13 08:51:29.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/ioport.c 2005-03-21 17:27:01.000000000 -0700 @@ -14,6 +14,8 @@ #include #include #include +#include +#include /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) @@ -57,10 +59,22 @@ struct thread_struct * t = ¤t->thread; struct tss_struct * tss = init_tss + smp_processor_id(); +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + unsigned long flags, cr3; +#endif + if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; +#ifdef CONFIG_GRKERNSEC_IO + if (turn_on) { + gr_handle_ioperm(); +#else if (turn_on && !capable(CAP_SYS_RAWIO)) +#endif return -EPERM; +#ifdef CONFIG_GRKERNSEC_IO + } +#endif /* * If it's the first ioperm() call in this thread's lifetime, set the * IO bitmap up. ioperm() is much less timing critical than clone(), @@ -78,6 +92,11 @@ * do it in the per-thread copy and in the TSS ... */ set_bitmap(t->io_bitmap, from, num, !turn_on); + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_open_kernel(flags, cr3); +#endif + if (tss->bitmap == IO_BITMAP_OFFSET) { /* already active? */ set_bitmap(tss->io_bitmap, from, num, !turn_on); } else { @@ -85,6 +104,10 @@ tss->bitmap = IO_BITMAP_OFFSET; /* Activate it in the TSS */ } +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_close_kernel(flags, cr3); +#endif + return 0; } @@ -109,8 +132,13 @@ return -EINVAL; /* Trying to gain more privileges? */ if (level > old) { +#ifdef CONFIG_GRKERNSEC_IO + gr_handle_iopl(); + return -EPERM; +#else if (!capable(CAP_SYS_RAWIO)) return -EPERM; +#endif } regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12); return 0; diff -ruN linux-2.4.29/arch/i386/kernel/ldt.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/ldt.c --- linux-2.4.29/arch/i386/kernel/ldt.c 2004-02-18 06:36:30.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/ldt.c 2005-03-21 17:27:01.000000000 -0700 @@ -151,7 +151,7 @@ { int err; unsigned long size; - void *address; + const void *address; err = 0; address = &default_ldt[0]; @@ -214,6 +214,13 @@ } } +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if ((current->flags & PF_PAX_SEGMEXEC) && (ldt_info.contents & 2)) { + error = -EINVAL; + goto out_unlock; + } +#endif + entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | (ldt_info.limit & 0x0ffff); entry_2 = (ldt_info.base_addr & 0xff000000) | @@ -224,7 +231,7 @@ ((ldt_info.seg_not_present ^ 1) << 15) | (ldt_info.seg_32bit << 22) | (ldt_info.limit_in_pages << 23) | - 0x7000; + 0x7100; if (!oldmode) entry_2 |= (ldt_info.useable << 20); diff -ruN linux-2.4.29/arch/i386/kernel/pci-pc.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/pci-pc.c --- linux-2.4.29/arch/i386/kernel/pci-pc.c 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/pci-pc.c 2005-03-21 17:27:01.000000000 -0700 @@ -17,6 +17,7 @@ #include #include #include +#include #include "pci-i386.h" @@ -575,7 +576,6 @@ * we'll make pcibios_present() take a memory start parameter and store * the array there. */ - static struct { unsigned long address; unsigned short segment; @@ -1493,6 +1493,7 @@ if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) pcibios_sort(); #endif + } char * __devinit pcibios_setup(char *str) diff -ruN linux-2.4.29/arch/i386/kernel/process.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/process.c --- linux-2.4.29/arch/i386/kernel/process.c 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/process.c 2005-03-21 17:27:16.637963751 -0700 @@ -48,6 +48,12 @@ #ifdef CONFIG_MATH_EMULATION #include #endif + +#ifdef CONFIG_COBALT_RAQ +#include +#include +#endif + #include #include @@ -209,18 +215,18 @@ doesn't work with at least one type of 486 motherboard. It is easy to stop this code working; hence the copious comments. */ -static unsigned long long +static const unsigned long long real_mode_gdt_entries [3] = { 0x0000000000000000ULL, /* Null descriptor */ - 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ - 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ + 0x00009b000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000093000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ }; static struct { unsigned short size __attribute__ ((packed)); - unsigned long long * base __attribute__ ((packed)); + const unsigned long long * base __attribute__ ((packed)); } real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, real_mode_idt = { 0x3ff, 0 }, @@ -365,6 +371,30 @@ : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); } +/* kill some time at halt/reboot to allow drives with large cache to sync */ +static inline void +wait_for_flush(void) +{ + int i; + static int flushed; + + if (flushed) + return; + flushed = 1; + + printk("waiting for devices to flush"); + for (i = 0 ; i < 10; i++) { + printk("."); + mdelay(500); +#ifdef CONFIG_COBALT_LCD + if (i == 8) + cobalt_lcd_off(); +#endif + } + printk("done\n"); +} + + void machine_restart(char * __unused) { #if CONFIG_SMP @@ -412,6 +442,11 @@ disable_IO_APIC(); #endif + wait_for_flush(); +#ifdef CONFIG_COBALT_RAQ + cobalt_restart(); +#endif + if(!reboot_thru_bios) { /* rebooting needs to touch the page at absolute addr 0 */ *((unsigned short *)__va(0x472)) = reboot_mode; @@ -434,10 +469,18 @@ void machine_halt(void) { + wait_for_flush(); +#ifdef CONFIG_COBALT_RAQ + cobalt_halt(); +#endif } void machine_power_off(void) { + wait_for_flush(); +#ifdef CONFIG_COBALT_RAQ + cobalt_power_off(); +#endif if (pm_power_off) pm_power_off(); } @@ -552,7 +595,7 @@ { struct pt_regs * childregs; - childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1; + childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p - sizeof(unsigned long))) - 1; struct_cpy(childregs, regs); childregs->eax = 0; childregs->esp = esp; @@ -613,6 +656,16 @@ dump->u_fpvalid = dump_fpu (regs, &dump->i387); } +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC +void pax_switch_segments(struct task_struct * tsk) +{ + if (tsk->flags & PF_PAX_SEGMEXEC) + __asm__ __volatile__("lgdt %0": "=m" (gdt_descr2)); + else + __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); +} +#endif + /* * This special macro can be used to load a debugging register */ @@ -650,12 +703,15 @@ *next = &next_p->thread; struct tss_struct *tss = init_tss + smp_processor_id(); +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + unsigned long flags, cr3; +#endif + unlazy_fpu(prev_p); - /* - * Reload esp0, LDT and the page table pointer: - */ - tss->esp0 = next->esp0; +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + pax_switch_segments(next_p); +#endif /* * Save away %fs and %gs. No need to save %es and %ds, as @@ -683,6 +739,15 @@ loaddebug(next, 7); } +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_open_kernel(flags, cr3); +#endif + + /* + * Reload esp0, LDT and the page table pointer: + */ + tss->esp0 = next->esp0; + if (prev->ioperm || next->ioperm) { if (next->ioperm) { /* @@ -705,6 +770,11 @@ */ tss->bitmap = INVALID_IO_BITMAP_OFFSET; } + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_close_kernel(flags, cr3); +#endif + } asmlinkage int sys_fork(struct pt_regs regs) @@ -792,3 +862,43 @@ } #undef last_sched #undef first_sched + +#ifdef CONFIG_GRKERNSEC_PAX_RANDKSTACK +asmlinkage void pax_randomize_kstack(void) +{ + struct tss_struct *tss = init_tss + smp_processor_id(); + unsigned long time; + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + unsigned long flags, cr3; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (!pax_aslr) + return; +#endif + + rdtscl(time); + + /* P4 seems to return a 0 LSB, ignore it */ +#ifdef CONFIG_MPENTIUM4 + time &= 0x3EUL; + time <<= 1; +#else + time &= 0x1FUL; + time <<= 2; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_open_kernel(flags, cr3); +#endif + + tss->esp0 ^= time; + current->thread.esp0 = tss->esp0; + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_close_kernel(flags, cr3); +#endif + +} +#endif diff -ruN linux-2.4.29/arch/i386/kernel/ptrace.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/ptrace.c --- linux-2.4.29/arch/i386/kernel/ptrace.c 2002-08-02 18:39:42.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/ptrace.c 2005-03-21 17:27:01.000000000 -0700 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -177,6 +178,9 @@ if (pid == 1) /* you may not mess with init */ goto out_tsk; + if(gr_handle_ptrace(child, request)) + goto out_tsk; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; @@ -256,6 +260,17 @@ if(addr < (long) &dummy->u_debugreg[4] && ((unsigned long) data) >= TASK_SIZE-3) break; +#ifdef CONFIG_GRKERNSEC + if(addr >= (long) &dummy->u_debugreg[0] && + addr <= (long) &dummy->u_debugreg[3]){ + long reg = (addr - (long) &dummy->u_debugreg[0]) >> 2; + long type = (child->thread.debugreg[7] >> (DR_CONTROL_SHIFT + 4*reg)) & 3; + long align = (child->thread.debugreg[7] >> (DR_CONTROL_SHIFT + 2 + 4*reg)) & 3; + if((type & 1) && (data & align)) + break; + } +#endif + if(addr == (long) &dummy->u_debugreg[7]) { data &= ~DR_CONTROL_RESERVED; for(i=0; i<4; i++) diff -ruN linux-2.4.29/arch/i386/kernel/setup.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/setup.c --- linux-2.4.29/arch/i386/kernel/setup.c 2004-08-07 17:26:04.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/setup.c 2005-03-21 17:27:01.000000000 -0700 @@ -129,7 +129,11 @@ char ignore_irq13; /* set if exception 16 works */ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; +#ifdef CONFIG_X86_PAE +unsigned long mmu_cr4_features = X86_CR4_PAE; +#else unsigned long mmu_cr4_features; +#endif EXPORT_SYMBOL(mmu_cr4_features); /* @@ -170,7 +174,7 @@ extern void mcheck_init(struct cpuinfo_x86 *c); extern void dmi_scan_machine(void); extern int root_mountflags; -extern char _text, _etext, _edata, _end; +extern char _text, _etext, _data, _edata, _end; static int have_cpuid_p(void) __init; @@ -1215,7 +1219,7 @@ code_resource.start = virt_to_bus(&_text); code_resource.end = virt_to_bus(&_etext)-1; - data_resource.start = virt_to_bus(&_etext); + data_resource.start = virt_to_bus(&_data); data_resource.end = virt_to_bus(&_edata)-1; parse_cmdline_early(cmdline_p); @@ -3221,7 +3225,7 @@ set_tss_desc(nr,t); gdt_table[__TSS(nr)].b &= 0xfffffdff; load_TR(nr); - load_LDT(&init_mm.context); + _load_LDT(&init_mm.context); /* * Clear all 6 debug registers: @@ -3287,7 +3291,16 @@ printk(KERN_INFO "Your Pentium Pro seems ok.\n"); return 0; } - + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE +static int __init setup_pax_softmode(char *str) +{ + get_option (&str, &pax_softmode); + return 1; +} +__setup("pax_softmode=", setup_pax_softmode); +#endif + /* * Local Variables: * mode:c diff -ruN linux-2.4.29/arch/i386/kernel/sys_i386.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/sys_i386.c --- linux-2.4.29/arch/i386/kernel/sys_i386.c 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/sys_i386.c 2005-03-21 17:27:01.000000000 -0700 @@ -48,6 +48,11 @@ int error = -EBADF; struct file * file = NULL; +#if defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) || defined(CONFIG_GRKERNSEC_PAX_RANDEXEC) + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); diff -ruN linux-2.4.29/arch/i386/kernel/trampoline.S linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/trampoline.S --- linux-2.4.29/arch/i386/kernel/trampoline.S 2002-11-28 16:53:09.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/trampoline.S 2005-03-21 17:27:01.000000000 -0700 @@ -54,7 +54,7 @@ lmsw %ax # into protected mode jmp flush_instr flush_instr: - ljmpl $__KERNEL_CS, $0x00100000 + ljmpl $__KERNEL_CS, $SYMBOL_NAME(startup_32)-__PAGE_OFFSET # jump to startup_32 in arch/i386/kernel/head.S idt_48: diff -ruN linux-2.4.29/arch/i386/kernel/traps.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/traps.c --- linux-2.4.29/arch/i386/kernel/traps.c 2002-11-28 16:53:09.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/traps.c 2005-03-21 17:27:16.638963602 -0700 @@ -50,19 +50,18 @@ #include #include +#ifdef CONFIG_COBALT_RAQ +#include +#endif + asmlinkage int system_call(void); asmlinkage void lcall7(void); asmlinkage void lcall27(void); -struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, +const struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; -/* - * The IDT has to be page-aligned to simplify the Pentium - * F0 0F bug workaround.. We have a special link segment - * for this. - */ -struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; +extern struct desc_struct idt_table[256]; asmlinkage void divide_error(void); asmlinkage void debug(void); @@ -228,13 +227,13 @@ show_stack((unsigned long*)esp); printk("\nCode: "); - if(regs->eip < PAGE_OFFSET) + if(regs->eip + __KERNEL_TEXT_OFFSET < PAGE_OFFSET) goto bad; for(i=0;i<20;i++) { unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { + if(__get_user(c, &((unsigned char*)regs->eip)[i+__KERNEL_TEXT_OFFSET])) { bad: printk(" Bad EIP value."); break; @@ -256,7 +255,7 @@ if (regs->xcs & 3) goto no_bug; /* Not in kernel */ - eip = regs->eip; + eip = regs->eip + __KERNEL_TEXT_OFFSET; if (eip < PAGE_OFFSET) goto no_bug; @@ -422,15 +421,25 @@ regs->eip = fixup; return; } + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + if ((regs->xcs & 0xFFFF) == __KERNEL_CS) + die("PAX: suspicious general protection fault", regs, error_code); + else +#endif + die("general protection fault", regs, error_code); } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) { +#ifdef CONFIG_COBALT_RAQ + cobalt_nmi(reason, regs); +#else printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); printk("You probably have a hardware problem with your RAM chips\n"); - +#endif /* Clear and disable the memory parity error line. */ reason = (reason & 0xf) | 4; outb(reason, 0x61); @@ -527,13 +536,12 @@ { unsigned int condition; struct task_struct *tsk = current; - unsigned long eip = regs->eip; siginfo_t info; __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); /* If the user set TF, it's simplest to clear it right away. */ - if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK)) + if (!(regs->xcs & 3) && (regs->eflags & TF_MASK) && !(regs->eflags & VM_MASK)) goto clear_TF; /* Mask out spurious debug traps due to lazy DR7 setting */ @@ -779,6 +787,8 @@ #ifndef CONFIG_X86_F00F_WORKS_OK void __init trap_init_f00f_bug(void) { + +#ifndef CONFIG_GRKERNSEC_PAX_KERNEXEC /* * "idt" is magic - it overlaps the idt_descr * variable so that updating idt will automatically @@ -788,6 +798,8 @@ idt = (struct desc_struct *)__fix_to_virt(FIX_F00F); __asm__ __volatile__("lidt %0": "=m" (idt_descr)); +#endif + } #endif @@ -826,7 +838,7 @@ _set_gate(idt_table+n,15,3,addr); } -static void __init set_call_gate(void *a, void *addr) +static void __init set_call_gate(const void *a, void *addr) { _set_gate(a,12,3,addr); } @@ -852,14 +864,45 @@ "rorl $16,%%eax" \ : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type)) -void set_tss_desc(unsigned int n, void *addr) +void set_tss_desc(unsigned int n, const void *addr) { _set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + _set_tssldt_desc(gdt_table2+__TSS(n), (int)addr, 235, 0x89); +#endif + } -void set_ldt_desc(unsigned int n, void *addr, unsigned int size) +void __set_ldt_desc(unsigned int n, const void *addr, unsigned int size) { _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + _set_tssldt_desc(gdt_table2+__LDT(n), (int)addr, ((size << 3)-1), 0x82); +#endif + +} + +void set_ldt_desc(unsigned int n, const void *addr, unsigned int size) +{ + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + unsigned long flags, cr3; + + pax_open_kernel(flags, cr3); +#endif + + _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + _set_tssldt_desc(gdt_table2+__LDT(n), (int)addr, ((size << 3)-1), 0x82); +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_close_kernel(flags, cr3); +#endif + } #ifdef CONFIG_X86_VISWS_APIC diff -ruN linux-2.4.29/arch/i386/kernel/traps.c.orig linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/traps.c.orig --- linux-2.4.29/arch/i386/kernel/traps.c.orig 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/traps.c.orig 2005-03-21 17:27:01.045282401 -0700 @@ -0,0 +1,1042 @@ +/* + * linux/arch/i386/traps.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MCA +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_X86_VISWS_APIC +#include +#include +#endif + +#include +#include + +asmlinkage int system_call(void); +asmlinkage void lcall7(void); +asmlinkage void lcall27(void); + +const struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 } }; + +extern struct desc_struct idt_table[256]; + +asmlinkage void divide_error(void); +asmlinkage void debug(void); +asmlinkage void nmi(void); +asmlinkage void int3(void); +asmlinkage void overflow(void); +asmlinkage void bounds(void); +asmlinkage void invalid_op(void); +asmlinkage void device_not_available(void); +asmlinkage void double_fault(void); +asmlinkage void coprocessor_segment_overrun(void); +asmlinkage void invalid_TSS(void); +asmlinkage void segment_not_present(void); +asmlinkage void stack_segment(void); +asmlinkage void general_protection(void); +asmlinkage void page_fault(void); +asmlinkage void coprocessor_error(void); +asmlinkage void simd_coprocessor_error(void); +asmlinkage void alignment_check(void); +asmlinkage void spurious_interrupt_bug(void); +asmlinkage void machine_check(void); + +int kstack_depth_to_print = 24; + + +/* + * If the address is either in the .text section of the + * kernel, or in the vmalloc'ed module regions, it *may* + * be the address of a calling routine + */ + +#ifdef CONFIG_MODULES + +extern struct module *module_list; +extern struct module kernel_module; + +static inline int kernel_text_address(unsigned long addr) +{ + int retval = 0; + struct module *mod; + + if (addr >= (unsigned long) &_stext && + addr <= (unsigned long) &_etext) + return 1; + + for (mod = module_list; mod != &kernel_module; mod = mod->next) { + /* mod_bound tests for addr being inside the vmalloc'ed + * module area. Of course it'd be better to test only + * for the .text subset... */ + if (mod_bound(addr, 0, mod)) { + retval = 1; + break; + } + } + + return retval; +} + +#else + +static inline int kernel_text_address(unsigned long addr) +{ + return (addr >= (unsigned long) &_stext && + addr <= (unsigned long) &_etext); +} + +#endif + +void show_trace(unsigned long * stack) +{ + int i; + unsigned long addr; + + if (!stack) + stack = (unsigned long*)&stack; + + printk("Call Trace: "); + i = 1; + while (((long) stack & (THREAD_SIZE-1)) != 0) { + addr = *stack++; + if (kernel_text_address(addr)) { + if (i && ((i % 6) == 0)) + printk("\n "); + printk(" [<%08lx>]", addr); + i++; + } + } + printk("\n"); +} + +void show_trace_task(struct task_struct *tsk) +{ + unsigned long esp = tsk->thread.esp; + + /* User space on another CPU? */ + if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1)) + return; + show_trace((unsigned long *)esp); +} + +void show_stack(unsigned long * esp) +{ + unsigned long *stack; + int i; + + // debugging aid: "show_stack(NULL);" prints the + // back trace for this cpu. + + if(esp==NULL) + esp=(unsigned long*)&esp; + + stack = esp; + for(i=0; i < kstack_depth_to_print; i++) { + if (((long) stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + printk("\n"); + show_trace(esp); +} + +/* + * The architecture-independent backtrace generator + */ +void dump_stack(void) +{ + show_stack(0); +} + +void show_registers(struct pt_regs *regs) +{ + int i; + int in_kernel = 1; + unsigned long esp; + unsigned short ss; + + esp = (unsigned long) (®s->esp); + ss = __KERNEL_DS; + if (regs->xcs & 3) { + in_kernel = 0; + esp = regs->esp; + ss = regs->xss & 0xffff; + } + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n", + smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags); + printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", + regs->esi, regs->edi, regs->ebp, esp); + printk("ds: %04x es: %04x ss: %04x\n", + regs->xds & 0xffff, regs->xes & 0xffff, ss); + printk("Process %s (pid: %d, stackpage=%08lx)", + current->comm, current->pid, 4096+(unsigned long)current); + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (in_kernel) { + + printk("\nStack: "); + show_stack((unsigned long*)esp); + + printk("\nCode: "); + if(regs->eip + __KERNEL_TEXT_OFFSET < PAGE_OFFSET) + goto bad; + + for(i=0;i<20;i++) + { + unsigned char c; + if(__get_user(c, &((unsigned char*)regs->eip)[i+__KERNEL_TEXT_OFFSET])) { +bad: + printk(" Bad EIP value."); + break; + } + printk("%02x ", c); + } + } + printk("\n"); +} + +static void handle_BUG(struct pt_regs *regs) +{ + unsigned short ud2; + unsigned short line; + char *file; + char c; + unsigned long eip; + + if (regs->xcs & 3) + goto no_bug; /* Not in kernel */ + + eip = regs->eip + __KERNEL_TEXT_OFFSET; + + if (eip < PAGE_OFFSET) + goto no_bug; + if (__get_user(ud2, (unsigned short *)eip)) + goto no_bug; + if (ud2 != 0x0b0f) + goto no_bug; + if (__get_user(line, (unsigned short *)(eip + 2))) + goto bug; + if (__get_user(file, (char **)(eip + 4)) || + (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) + file = ""; + + printk("kernel BUG at %s:%d!\n", file, line); + +no_bug: + return; + + /* Here we know it was a BUG but file-n-line is unavailable */ +bug: + printk("Kernel BUG\n"); +} + +spinlock_t die_lock = SPIN_LOCK_UNLOCKED; + +void die(const char * str, struct pt_regs * regs, long err) +{ + console_verbose(); + spin_lock_irq(&die_lock); + bust_spinlocks(1); + handle_BUG(regs); + printk("%s: %04lx\n", str, err & 0xffff); + show_registers(regs); + bust_spinlocks(0); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if (!(regs->eflags & VM_MASK) && !(3 & regs->xcs)) + die(str, regs, err); +} + +static inline unsigned long get_cr2(void) +{ + unsigned long address; + + /* get the address */ + __asm__("movl %%cr2,%0":"=r" (address)); + return address; +} + +static void inline do_trap(int trapnr, int signr, char *str, int vm86, + struct pt_regs * regs, long error_code, siginfo_t *info) +{ + if (regs->eflags & VM_MASK) { + if (vm86) + goto vm86_trap; + else + goto trap_signal; + } + + if (!(regs->xcs & 3)) + goto kernel_trap; + + trap_signal: { + struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + if (info) + force_sig_info(signr, info, tsk); + else + force_sig(signr, tsk); + return; + } + + kernel_trap: { + unsigned long fixup = search_exception_table(regs->eip); + if (fixup) + regs->eip = fixup; + else + die(str, regs, error_code); + return; + } + + vm86_trap: { + int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); + if (ret) goto trap_signal; + return; + } +} + +#define DO_ERROR(trapnr, signr, str, name) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ +} + +#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ +} + +#define DO_VM86_ERROR(trapnr, signr, str, name) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ +} + +#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ +} + +DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) +DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) +DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) +DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) +DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) +DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available) +DO_ERROR( 8, SIGSEGV, "double fault", double_fault) +DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) +DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) +DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) +DO_ERROR(12, SIGBUS, "stack segment", stack_segment) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) + +asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) +{ + if (regs->eflags & VM_MASK) + goto gp_in_vm86; + + if (!(regs->xcs & 3)) + goto gp_in_kernel; + + current->thread.error_code = error_code; + current->thread.trap_no = 13; + force_sig(SIGSEGV, current); + return; + +gp_in_vm86: + handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); + return; + +gp_in_kernel: + { + unsigned long fixup; + fixup = search_exception_table(regs->eip); + if (fixup) { + regs->eip = fixup; + return; + } + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + if ((regs->xcs & 0xFFFF) == __KERNEL_CS) + die("PAX: suspicious general protection fault", regs, error_code); + else +#endif + + die("general protection fault", regs, error_code); + } +} + +static void mem_parity_error(unsigned char reason, struct pt_regs * regs) +{ + printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); + printk("You probably have a hardware problem with your RAM chips\n"); + + /* Clear and disable the memory parity error line. */ + reason = (reason & 0xf) | 4; + outb(reason, 0x61); +} + +static void io_check_error(unsigned char reason, struct pt_regs * regs) +{ + unsigned long i; + + printk("NMI: IOCK error (debug interrupt?)\n"); + show_registers(regs); + + /* Re-enable the IOCK line, wait for a few seconds */ + reason = (reason & 0xf) | 8; + outb(reason, 0x61); + i = 2000; + while (--i) udelay(1000); + reason &= ~8; + outb(reason, 0x61); +} + +static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) +{ +#ifdef CONFIG_MCA + /* Might actually be able to figure out what the guilty party + * is. */ + if( MCA_bus ) { + mca_handle_nmi(); + return; + } +#endif + printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); + printk("Dazed and confused, but trying to continue\n"); + printk("Do you have a strange power saving mode enabled?\n"); +} + +asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +{ + unsigned char reason = inb(0x61); + + ++nmi_count(smp_processor_id()); + + if (!(reason & 0xc0)) { +#if CONFIG_X86_LOCAL_APIC + /* + * Ok, so this is none of the documented NMI sources, + * so it must be the NMI watchdog. + */ + if (nmi_watchdog) { + nmi_watchdog_tick(regs); + return; + } +#endif + unknown_nmi_error(reason, regs); + return; + } + if (reason & 0x80) + mem_parity_error(reason, regs); + if (reason & 0x40) + io_check_error(reason, regs); + /* + * Reassert NMI in case it became active meanwhile + * as it's edge-triggered. + */ + outb(0x8f, 0x70); + inb(0x71); /* dummy */ + outb(0x0f, 0x70); + inb(0x71); /* dummy */ +} + +/* + * Our handling of the processor debug registers is non-trivial. + * We do not clear them on entry and exit from the kernel. Therefore + * it is possible to get a watchpoint trap here from inside the kernel. + * However, the code in ./ptrace.c has ensured that the user can + * only set watchpoints on userspace addresses. Therefore the in-kernel + * watchpoint trap can only occur in code which is reading/writing + * from user space. Such code must not hold kernel locks (since it + * can equally take a page fault), therefore it is safe to call + * force_sig_info even though that claims and releases locks. + * + * Code in ./signal.c ensures that the debug control register + * is restored before we deliver any signal, and therefore that + * user code runs with the correct debug control register even though + * we clear it here. + * + * Being careful here means that we don't have to be as careful in a + * lot of more complicated places (task switching can be a bit lazy + * about restoring all the debug state, and ptrace doesn't have to + * find every occurrence of the TF bit that could be saved away even + * by user code) + */ +asmlinkage void do_debug(struct pt_regs * regs, long error_code) +{ + unsigned int condition; + struct task_struct *tsk = current; + siginfo_t info; + + __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); + + /* If the user set TF, it's simplest to clear it right away. */ + if (!(regs->xcs & 3) && (regs->eflags & TF_MASK) && !(regs->eflags & VM_MASK)) + goto clear_TF; + + /* 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]) + goto clear_dr7; + } + + if (regs->eflags & VM_MASK) + goto debug_vm86; + + /* Save debug status register where ptrace can see it */ + tsk->thread.debugreg[6] = condition; + + /* Mask out spurious TF errors due to lazy TF clearing */ + if (condition & DR_STEP) { + /* + * The TF error should be masked out only if the current + * process is not traced and if the TRAP flag has been set + * previously by a tracing process (condition detected by + * the PT_DTRACE flag); remember that the i386 TRAP flag + * can be modified by the process itself in user mode, + * allowing programs to debug themselves without the ptrace() + * interface. + */ + if ((regs->xcs & 3) == 0) + goto clear_TF; + if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) + goto clear_TF; + } + + /* Ok, finally something we can handle */ + tsk->thread.trap_no = 1; + tsk->thread.error_code = error_code; + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + + /* If this is a kernel mode trap, save the user PC on entry to + * the kernel, that's what the debugger can make sense of. + */ + info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : + (void *)regs->eip; + force_sig_info(SIGTRAP, &info, tsk); + + /* Disable additional traps. They'll be re-enabled when + * the signal is delivered. + */ +clear_dr7: + __asm__("movl %0,%%db7" + : /* no output */ + : "r" (0)); + return; + +debug_vm86: + handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); + return; + +clear_TF: + regs->eflags &= ~TF_MASK; + return; +} + +/* + * Note that we play around with the 'TS' bit in an attempt to get + * the correct behaviour even in the presence of the asynchronous + * IRQ13 behaviour + */ +void math_error(void *eip) +{ + struct task_struct * task; + siginfo_t info; + unsigned short cwd, swd; + + /* + * Save the info for the exception handler and clear the error. + */ + task = current; + save_init_fpu(task); + task->thread.trap_no = 16; + task->thread.error_code = 0; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * (~cwd & swd) will mask out exceptions that are not set to unmasked + * status. 0x3f is the exception bits in these regs, 0x200 is the + * C1 reg you need in case of a stack fault, 0x040 is the stack + * fault bit. We should only be taking one exception at a time, + * so if this combination doesn't produce any single exception, + * then we have a bad program that isn't syncronizing its FPU usage + * and it will suffer the consequences since we won't be able to + * fully reproduce the context of the exception + */ + cwd = get_fpu_cwd(task); + swd = get_fpu_swd(task); + switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) { + case 0x000: + default: + break; + case 0x001: /* Invalid Op */ + case 0x041: /* Stack Fault */ + case 0x241: /* Stack Fault | Direction */ + info.si_code = FPE_FLTINV; + /* Should we clear the SF or let user space do it ???? */ + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); +} + +asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) +{ + ignore_irq13 = 1; + math_error((void *)regs->eip); +} + +void simd_math_error(void *eip) +{ + struct task_struct * task; + siginfo_t info; + unsigned short mxcsr; + + /* + * Save the info for the exception handler and clear the error. + */ + task = current; + save_init_fpu(task); + task->thread.trap_no = 19; + task->thread.error_code = 0; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * The SIMD FPU exceptions are handled a little differently, as there + * is only a single status/control register. Thus, to determine which + * unmasked exception was caught we must mask the exception mask bits + * at 0x1f80, and then use these to mask the exception bits at 0x3f. + */ + mxcsr = get_fpu_mxcsr(task); + switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { + case 0x000: + default: + break; + case 0x001: /* Invalid Op */ + info.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); +} + +asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs, + long error_code) +{ + if (cpu_has_xmm) { + /* Handle SIMD FPU exceptions on PIII+ processors. */ + ignore_irq13 = 1; + simd_math_error((void *)regs->eip); + } else { + /* + * Handle strange cache flush from user space exception + * in all other cases. This is undocumented behaviour. + */ + if (regs->eflags & VM_MASK) { + handle_vm86_fault((struct kernel_vm86_regs *)regs, + error_code); + return; + } + die_if_kernel("cache flush denied", regs, error_code); + current->thread.trap_no = 19; + current->thread.error_code = error_code; + force_sig(SIGSEGV, current); + } +} + +asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, + long error_code) +{ +#if 0 + /* No need to warn about this any longer. */ + printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); +#endif +} + +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + * + * Careful.. There are problems with IBM-designed IRQ13 behaviour. + * Don't touch unless you *really* know how it works. + */ +asmlinkage void math_state_restore(struct pt_regs regs) +{ + __asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */ + + if (current->used_math) { + restore_fpu(current); + } else { + init_fpu(); + } + current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */ +} + +#ifndef CONFIG_MATH_EMULATION + +asmlinkage void math_emulate(long arg) +{ + printk("math-emulation not enabled and no coprocessor found.\n"); + printk("killing %s.\n",current->comm); + force_sig(SIGFPE,current); + schedule(); +} + +#endif /* CONFIG_MATH_EMULATION */ + +#ifndef CONFIG_X86_F00F_WORKS_OK +void __init trap_init_f00f_bug(void) +{ + +#ifndef CONFIG_GRKERNSEC_PAX_KERNEXEC + /* + * "idt" is magic - it overlaps the idt_descr + * variable so that updating idt will automatically + * update the idt descriptor.. + */ + __set_fixmap(FIX_F00F, __pa(&idt_table), PAGE_KERNEL_RO); + idt = (struct desc_struct *)__fix_to_virt(FIX_F00F); + + __asm__ __volatile__("lidt %0": "=m" (idt_descr)); +#endif + +} +#endif + +#define _set_gate(gate_addr,type,dpl,addr) \ +do { \ + int __d0, __d1; \ + __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ + "movw %4,%%dx\n\t" \ + "movl %%eax,%0\n\t" \ + "movl %%edx,%1" \ + :"=m" (*((long *) (gate_addr))), \ + "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ + :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ + "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \ +} while (0) + + +/* + * This needs to use 'idt_table' rather than 'idt', and + * thus use the _nonmapped_ version of the IDT, as the + * Pentium F0 0F bugfix can have resulted in the mapped + * IDT being write-protected. + */ +void set_intr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,14,0,addr); +} + +static void __init set_trap_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,15,0,addr); +} + +static void __init set_system_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,15,3,addr); +} + +static void __init set_call_gate(const void *a, void *addr) +{ + _set_gate(a,12,3,addr); +} + +#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\ + *((gate_addr)+1) = ((base) & 0xff000000) | \ + (((base) & 0x00ff0000)>>16) | \ + ((limit) & 0xf0000) | \ + ((dpl)<<13) | \ + (0x00408000) | \ + ((type)<<8); \ + *(gate_addr) = (((base) & 0x0000ffff)<<16) | \ + ((limit) & 0x0ffff); } + +#define _set_tssldt_desc(n,addr,limit,type) \ +__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ + "movw %%ax,2(%2)\n\t" \ + "rorl $16,%%eax\n\t" \ + "movb %%al,4(%2)\n\t" \ + "movb %4,5(%2)\n\t" \ + "movb $0,6(%2)\n\t" \ + "movb %%ah,7(%2)\n\t" \ + "rorl $16,%%eax" \ + : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type)) + +void set_tss_desc(unsigned int n, const void *addr) +{ + _set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + _set_tssldt_desc(gdt_table2+__TSS(n), (int)addr, 235, 0x89); +#endif + +} + +void __set_ldt_desc(unsigned int n, const void *addr, unsigned int size) +{ + _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + _set_tssldt_desc(gdt_table2+__LDT(n), (int)addr, ((size << 3)-1), 0x82); +#endif + +} + +void set_ldt_desc(unsigned int n, const void *addr, unsigned int size) +{ + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + unsigned long flags, cr3; + + pax_open_kernel(flags, cr3); +#endif + + _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + _set_tssldt_desc(gdt_table2+__LDT(n), (int)addr, ((size << 3)-1), 0x82); +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_close_kernel(flags, cr3); +#endif + +} + +#ifdef CONFIG_X86_VISWS_APIC + +/* + * On Rev 005 motherboards legacy device interrupt lines are wired directly + * to Lithium from the 307. But the PROM leaves the interrupt type of each + * 307 logical device set appropriate for the 8259. Later we'll actually use + * the 8259, but for now we have to flip the interrupt types to + * level triggered, active lo as required by Lithium. + */ + +#define REG 0x2e /* The register to read/write */ +#define DEV 0x07 /* Register: Logical device select */ +#define VAL 0x2f /* The value to read/write */ + +static void +superio_outb(int dev, int reg, int val) +{ + outb(DEV, REG); + outb(dev, VAL); + outb(reg, REG); + outb(val, VAL); +} + +static int __attribute__ ((unused)) +superio_inb(int dev, int reg) +{ + outb(DEV, REG); + outb(dev, VAL); + outb(reg, REG); + return inb(VAL); +} + +#define FLOP 3 /* floppy logical device */ +#define PPORT 4 /* parallel logical device */ +#define UART5 5 /* uart2 logical device (not wired up) */ +#define UART6 6 /* uart1 logical device (THIS is the serial port!) */ +#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */ +#define ITYPE 0x71 /* interrupt type register */ + +/* interrupt type bits */ +#define LEVEL 0x01 /* bit 0, 0 == edge triggered */ +#define ACTHI 0x02 /* bit 1, 0 == active lo */ + +static void +superio_init(void) +{ + if (visws_board_type == VISWS_320 && visws_board_rev == 5) { + superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */ + printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n"); + } +} + +static void +lithium_init(void) +{ + set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS); + printk("Lithium PCI Bridge A, Bus Number: %d\n", + li_pcia_read16(LI_PCI_BUSNUM) & 0xff); + set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS); + printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n", + li_pcib_read16(LI_PCI_BUSNUM) & 0xff); + + /* XXX blindly enables all interrupts */ + li_pcia_write16(LI_PCI_INTEN, 0xffff); + li_pcib_write16(LI_PCI_INTEN, 0xffff); +} + +static void +cobalt_init(void) +{ + /* + * On normal SMP PC this is used only with SMP, but we have to + * use it and set it up here to start the Cobalt clock + */ + set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); + printk("Local APIC ID %lx\n", apic_read(APIC_ID)); + printk("Local APIC Version %lx\n", apic_read(APIC_LVR)); + + set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); + printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV)); + + set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); + printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID)); + + /* Enable Cobalt APIC being careful to NOT change the ID! */ + co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE); + + printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID)); +} +#endif +void __init trap_init(void) +{ +#ifdef CONFIG_EISA + if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) + EISA_bus = 1; +#endif + +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); +#endif + + set_trap_gate(0,÷_error); + set_trap_gate(1,&debug); + set_intr_gate(2,&nmi); + set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_gate(4,&overflow); + set_system_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_trap_gate(8,&double_fault); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_intr_gate(14,&page_fault); + set_trap_gate(15,&spurious_interrupt_bug); + set_trap_gate(16,&coprocessor_error); + set_trap_gate(17,&alignment_check); + set_trap_gate(18,&machine_check); + set_trap_gate(19,&simd_coprocessor_error); + + set_system_gate(SYSCALL_VECTOR,&system_call); + + /* + * default LDT is a single-entry callgate to lcall7 for iBCS + * and a callgate to lcall27 for Solaris/x86 binaries + */ + set_call_gate(&default_ldt[0],lcall7); + set_call_gate(&default_ldt[4],lcall27); + + /* + * Should be a barrier for any external CPU state. + */ + cpu_init(); + +#ifdef CONFIG_X86_VISWS_APIC + superio_init(); + lithium_init(); + cobalt_init(); +#endif +} diff -ruN linux-2.4.29/arch/i386/kernel/vm86.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/vm86.c --- linux-2.4.29/arch/i386/kernel/vm86.c 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/kernel/vm86.c 2005-03-21 17:27:01.000000000 -0700 @@ -44,6 +44,7 @@ #include #include #include +#include /* * Known problems: @@ -97,6 +98,10 @@ struct pt_regs *ret; unsigned long tmp; +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + unsigned long flags, cr3; +#endif + if (!current->thread.vm86_info) { printk("no vm86_info: BAD\n"); do_exit(SIGSEGV); @@ -111,7 +116,17 @@ do_exit(SIGSEGV); } tss = init_tss + smp_processor_id(); + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_open_kernel(flags, cr3); +#endif + tss->esp0 = current->thread.esp0 = current->thread.saved_esp0; + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_close_kernel(flags, cr3); +#endif + current->thread.saved_esp0 = 0; ret = KVM86->regs32; return ret; @@ -237,6 +252,11 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk) { struct tss_struct *tss; + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + unsigned long flags, cr3; +#endif + /* * make sure the vm86() system call doesn't try to do anything silly */ @@ -278,8 +298,17 @@ info->regs32->eax = 0; tsk->thread.saved_esp0 = tsk->thread.esp0; tss = init_tss + smp_processor_id(); + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_open_kernel(flags, cr3); +#endif + tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + pax_close_kernel(flags, cr3); +#endif + tsk->thread.screen_bitmap = info->screen_bitmap; if (info->flags & VM86_SCREEN_BITMAP) mark_screen_rdonly(tsk); diff -ruN linux-2.4.29/arch/i386/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/mm/fault.c --- linux-2.4.29/arch/i386/mm/fault.c 2004-08-07 17:26:04.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/mm/fault.c 2005-03-21 17:27:01.000000000 -0700 @@ -19,6 +19,8 @@ #include #include #include /* For unblank_screen() */ +#include +#include #include #include @@ -78,7 +80,7 @@ check_stack: if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, start) == 0) + if (expand_stack(current, vma, start) == 0) goto good_area; bad_area: @@ -127,6 +129,10 @@ asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); extern unsigned long idt; +#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_EMUTRAMP) || defined(CONFIG_GRKERNSEC_PAX_RANDEXEC) +static int pax_handle_fetch_fault(struct pt_regs *regs); +#endif + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -137,23 +143,30 @@ * bit 1 == 0 means read, 1 means write * bit 2 == 0 means kernel, 1 means user-mode */ -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +static int do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address) +#else +asmlinkage int 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_PAGEEXEC unsigned long address; - unsigned long page; +#endif unsigned long fixup; int write; siginfo_t info; +#ifndef CONFIG_GRKERNSEC_PAX_PAGEEXEC /* 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; @@ -202,7 +215,7 @@ if (address + 32 < regs->esp) goto bad_area; } - if (expand_stack(vma, address)) + if (expand_stack(tsk, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so @@ -258,7 +271,7 @@ tsk->thread.screen_bitmap |= 1 << bit; } up_read(&mm->mmap_sem); - return; + return 0; /* * Something tried to access memory that isn't in our memory map.. @@ -267,6 +280,46 @@ bad_area: up_read(&mm->mmap_sem); +#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) + if ((error_code & 4) && !(regs->eflags & X86_EFLAGS_VM)) { + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if ((tsk->flags & PF_PAX_PAGEEXEC) && !(error_code & 3) && (regs->eip == address)) { + pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp); + do_exit(SIGKILL); + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if ((tsk->flags & PF_PAX_SEGMEXEC) && !(error_code & 3) && (regs->eip + SEGMEXEC_TASK_SIZE == address)) { + +#if defined(CONFIG_GRKERNSEC_PAX_EMUTRAMP) || defined(CONFIG_GRKERNSEC_PAX_RANDEXEC) + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 5: + return 0; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + case 4: + return 0; + case 3: + case 2: + return 1; +#endif + + } +#endif + + pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp); + do_exit(SIGKILL); + } +#endif + + } +#endif + /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { tsk->thread.cr2 = address; @@ -278,7 +331,7 @@ /* info.si_code has been set above */ info.si_addr = (void *)address; force_sig_info(SIGSEGV, &info, tsk); - return; + return 0; } /* @@ -291,7 +344,7 @@ if (nr == 6) { do_invalid_op(regs, 0); - return; + return 0; } } @@ -299,7 +352,7 @@ /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { regs->eip = fixup; - return; + return 0; } /* @@ -311,19 +364,42 @@ if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + else if (init_mm.start_code + __KERNEL_TEXT_OFFSET <= address && + address < init_mm.end_code + __KERNEL_TEXT_OFFSET) { + if (tsk->curr_ip) + printk(KERN_ERR "PAX: From %u.%u.%u.%u: %s:%d, uid/euid: %u/%u, attempted to modify kernel code", + NIPQUAD(tsk->curr_ip), tsk->comm, tsk->pid, tsk->uid, tsk->euid); + else + printk(KERN_ERR "PAX: %s:%d, uid/euid: %u/%u, attempted to modify kernel code", + tsk->comm, tsk->pid, tsk->uid, tsk->euid); + } +#endif + else printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n",address); printk(" printing eip:\n"); printk("%08lx\n", regs->eip); - asm("movl %%cr3,%0":"=r" (page)); - page = ((unsigned long *) __va(page))[address >> 22]; - printk(KERN_ALERT "*pde = %08lx\n", page); - if (page & 1) { - page &= PAGE_MASK; - address &= 0x003ff000; - page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; - printk(KERN_ALERT "*pte = %08lx\n", page); + { + unsigned long index = pgd_index(address); + unsigned long pgd_paddr; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + asm("movl %%cr3,%0":"=r" (pgd_paddr)); + pgd = index + (pgd_t *)__va(pgd_paddr); + printk(KERN_ALERT "*pgd = %016llx\n", (u64)pgd_val(*pgd)); + if (pgd_present(*pgd)) { + pmd = pmd_offset(pgd, address); + printk(KERN_ALERT "*pmd = %016llx\n", (u64)pmd_val(*pmd)); + if (pmd_present(*pmd) && !(pmd_val(*pmd) & _PAGE_PSE)) { + pte = pte_offset(pmd, address); + printk(KERN_ALERT "*pte = %016llx\n", (u64)pte_val(*pte)); + } + } } die("Oops", regs, error_code); bust_spinlocks(0); @@ -363,7 +439,7 @@ /* Kernel mode? Handle exceptions or die */ if (!(error_code & 4)) goto no_context; - return; + return 0; vmalloc_fault: { @@ -396,6 +472,466 @@ pte_k = pte_offset(pmd_k, address); if (!pte_present(*pte_k)) goto no_context; - return; + return 0; + } +} +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +/* 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); +} +#endif + +/* + * PaX: decide what to do with offenders (regs->eip = fault address) + * + * returns 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 + * 5 when legitimate ET_EXEC was detected + */ +#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + static const unsigned char trans[8] = {6, 1, 2, 0, 13, 5, 3, 4}; +#endif + +#if defined(CONFIG_GRKERNSEC_PAX_RANDEXEC) || defined(CONFIG_GRKERNSEC_PAX_EMUTRAMP) + int err; +#endif + + if (regs->eflags & X86_EFLAGS_VM) + return 1; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) { + unsigned long esp_4; + if (regs->eip >= current->mm->start_code && + regs->eip < current->mm->end_code) + { + err = get_user(esp_4, (unsigned long*)(regs->esp-4UL)); + if (err || esp_4 == regs->eip) + return 1; + regs->eip += current->mm->delta_exec; + return 5; + } + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + +#ifndef CONFIG_GRKERNSEC_PAX_EMUSIGRT + if (!(current->flags & PF_PAX_EMUTRAMP)) + return 1; +#endif + + do { /* 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) + break; + + if (pop == 0x58 && + mov == 0xb8 && + nr == __NR_sigreturn && + sys == 0x80cd) + { + +#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT + int sig; + struct k_sigaction *ka; + __sighandler_t handler; + + if (get_user(sig, (int *)regs->esp)) + return 1; + if (sig < 1 || sig > _NSIG || sig == SIGKILL || sig == SIGSTOP) + return 1; + ka = ¤t->sig->action[sig-1]; + handler = ka->sa.sa_handler; + if (handler == SIG_DFL || handler == SIG_IGN) { + if (!(current->flags & PF_PAX_EMUTRAMP)) + return 1; + } else if (ka->sa.sa_flags & SA_SIGINFO) + return 1; +#endif + + regs->esp += 4; + regs->eax = nr; + regs->eip += 8; + return 2; + } + } while (0); + + do { /* 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) + break; + + if (mov == 0xb8 && + nr == __NR_rt_sigreturn && + sys == 0x80cd) + { + +#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT + int sig; + struct k_sigaction *ka; + __sighandler_t handler; + + if (get_user(sig, (int *)regs->esp)) + return 1; + if (sig < 1 || sig > _NSIG || sig == SIGKILL || sig == SIGSTOP) + return 1; + ka = ¤t->sig->action[sig-1]; + handler = ka->sa.sa_handler; + if (handler == SIG_DFL || handler == SIG_IGN) { + if (!(current->flags & PF_PAX_EMUTRAMP)) + return 1; + } else if (!(ka->sa.sa_flags & SA_SIGINFO)) + return 1; +#endif + + regs->eax = nr; + regs->eip += 7; + return 3; + } + } while (0); + +#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT + if (!(current->flags & PF_PAX_EMUTRAMP)) + return 1; +#endif + + do { /* PaX: gcc trampoline emulation #1 */ + unsigned char mov1, mov2; + unsigned short jmp; + unsigned long addr1, addr2, ret; + unsigned short call; + + 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) + break; + + err = get_user(call, (unsigned short *)(ret-2)); + if (err) + break; + + 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; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #2 */ + unsigned char mov, jmp; + unsigned long addr1, addr2, ret; + unsigned short call; + + 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) + break; + + err = get_user(call, (unsigned short *)(ret-2)); + if (err) + break; + + 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; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #3 */ + unsigned char mov, jmp; + char offset; + unsigned long addr1, addr2, ret; + unsigned short call; + + 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) + break; + + err = get_user(call, (unsigned short *)(ret-3)); + err |= get_user(offset, (char *)(ret-1)); + if (err) + break; + + if ((mov & 0xF8) == 0xB8 && + jmp == 0xE9 && + call == 0x55FF) + { + unsigned long addr; + + err = get_user(addr, (unsigned long*)(regs->ebp + (unsigned long)(long)offset)); + if (err || regs->eip != addr) + break; + + ((unsigned long *)regs)[trans[mov & 0x07]] = addr1; + regs->eip += addr2 + 10; + return 4; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #4 */ + unsigned char mov, jmp, sib; + char offset; + unsigned long addr1, addr2, ret; + unsigned short call; + + 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) + break; + + err = get_user(call, (unsigned short *)(ret-4)); + err |= get_user(sib, (unsigned char *)(ret-2)); + err |= get_user(offset, (char *)(ret-1)); + if (err) + break; + + if ((mov & 0xF8) == 0xB8 && + jmp == 0xE9 && + call == 0x54FF && + sib == 0x24) + { + unsigned long addr; + + err = get_user(addr, (unsigned long*)(regs->esp + 4 + (unsigned long)(long)offset)); + if (err || regs->eip != addr) + break; + + ((unsigned long *)regs)[trans[mov & 0x07]] = addr1; + regs->eip += addr2 + 10; + return 4; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #5 */ + unsigned char mov, jmp, sib; + unsigned long addr1, addr2, ret, offset; + unsigned short call; + + 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) + break; + + err = get_user(call, (unsigned short *)(ret-7)); + err |= get_user(sib, (unsigned char *)(ret-5)); + err |= get_user(offset, (unsigned long *)(ret-4)); + if (err) + break; + + if ((mov & 0xF8) == 0xB8 && + jmp == 0xE9 && + call == 0x94FF && + sib == 0x24) + { + unsigned long addr; + + err = get_user(addr, (unsigned long*)(regs->esp + 4 + offset)); + if (err || regs->eip != addr) + break; + + ((unsigned long *)regs)[trans[mov & 0x07]] = addr1; + regs->eip += addr2 + 10; + return 4; + } + } while (0); +#endif + + return 1; /* PaX in action */ +} +#endif + +#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (get_user(c, (unsigned char*)pc+i)) { + printk("."); + break; + } + printk("%02x ", c); + } + printk("\n"); + + printk(KERN_ERR "PAX: bytes at SP: "); + for (i = 0; i < 20; i++) { + unsigned long c; + if (get_user(c, (unsigned long*)sp+i)) { + printk("."); + break; + } + printk("%08lx ", c); + } + printk("\n"); +} +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +/* + * 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 mm_struct *mm = current->mm; + unsigned long address; + pte_t *pte; + unsigned char pte_mask; + int ret; + + __asm__("movl %%cr2,%0":"=r" (address)); + + /* It's safe to allow irq's after cr2 has been saved */ + if (likely(regs->eflags & X86_EFLAGS_IF)) + local_irq_enable(); + + if (unlikely((error_code & 5) != 5 || + address >= TASK_SIZE || + (regs->eflags & X86_EFLAGS_VM) || + !(current->flags & PF_PAX_PAGEEXEC))) + return do_page_fault(regs, error_code, address); + + /* PaX: it's our fault, let's handle it if we can */ + + /* PaX: take a look at read faults before acquiring any locks */ + if (unlikely(!(error_code & 2) && (regs->eip == address))) { + /* instruction fetch attempt from a protected page in user mode */ + ret = pax_handle_fetch_fault(regs); + switch (ret) { +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 5: + return 0; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + case 4: + return 0; + case 3: + case 2: + return 1; +#endif + } + pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp); + do_exit(SIGKILL); } + + pte_mask = _PAGE_ACCESSED | _PAGE_USER | ((error_code & 2) << (_PAGE_BIT_DIRTY-1)); + + spin_lock(&mm->page_table_lock); + pte = pax_get_pte(mm, address); + if (unlikely(!pte || !(pte_val(*pte) & _PAGE_PRESENT) || pte_exec(*pte))) { + spin_unlock(&mm->page_table_lock); + do_page_fault(regs, error_code, address); + return 0; + } + + if (unlikely((error_code & 2) && !pte_write(*pte))) { + /* write attempt to a protected page in user mode */ + spin_unlock(&mm->page_table_lock); + do_page_fault(regs, error_code, address); + return 0; + } + + /* + * PaX: fill DTLB with user rights and retry + */ + __asm__ __volatile__ ( + "orb %2,%1\n" +#if defined(CONFIG_M586) || defined(CONFIG_M586TSC) +/* + * PaX: let this uncommented 'invlpg' remind us on the behaviour of Intel's + * (and AMD's) TLBs. namely, they do not cache PTEs that would raise *any* + * page fault when examined during a TLB load attempt. this is true not only + * for PTEs holding a non-present entry but also present entries that will + * raise a page fault (such as those set up by PaX, or the copy-on-write + * mechanism). in effect it means that we do *not* need to flush the TLBs + * for our target pages since their PTEs are simply not in the TLBs at all. + * the best thing in omitting it is that we gain around 15-20% speed in the + * fast path of the page fault handler and can get rid of tracing since we + * can no longer flush unintended entries. + */ + + "invlpg %0\n" +#endif + + "testb $0,%0\n" + "xorb %3,%1\n" + : + : "m" (*(char*)address), "m" (*(char*)pte) , "q" (pte_mask) , "i" (_PAGE_USER) + : "memory", "cc"); + spin_unlock(&mm->page_table_lock); + return 0; } +#endif diff -ruN linux-2.4.29/arch/i386/mm/init.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/mm/init.c --- linux-2.4.29/arch/i386/mm/init.c 2004-04-14 07:05:25.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/mm/init.c 2005-03-21 17:27:01.000000000 -0700 @@ -37,6 +37,7 @@ #include #include #include +#include mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long highstart_pfn, highend_pfn; @@ -122,7 +123,7 @@ /* References to section boundaries */ -extern char _text, _etext, _edata, __bss_start, _end; +extern char _text, _etext, _data, _edata, __bss_start, _end; extern char __init_begin, __init_end; static inline void set_pte_phys (unsigned long vaddr, @@ -178,17 +179,7 @@ pgd = pgd_base + i; for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { -#if CONFIG_X86_PAE - if (pgd_none(*pgd)) { - pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); - if (pmd != pmd_offset(pgd, 0)) - printk("PAE BUG #02!\n"); - } pmd = pmd_offset(pgd, vaddr); -#else - pmd = (pmd_t *)pgd; -#endif for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { if (pmd_none(*pmd)) { pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); @@ -217,25 +208,22 @@ end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); pgd_base = swapper_pg_dir; -#if CONFIG_X86_PAE - for (i = 0; i < PTRS_PER_PGD; i++) - set_pgd(pgd_base + i, __pgd(1 + __pa(empty_zero_page))); -#endif i = __pgd_offset(PAGE_OFFSET); pgd = pgd_base + i; + if (cpu_has_pse) { + set_in_cr4(X86_CR4_PSE); + boot_cpu_data.wp_works_ok = 1; + + if (cpu_has_pge) + set_in_cr4(X86_CR4_PGE); + } + for (; i < PTRS_PER_PGD; pgd++, i++) { vaddr = i*PGDIR_SIZE; if (end && (vaddr >= end)) break; -#if CONFIG_X86_PAE - pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); -#else - pmd = (pmd_t *)pgd; -#endif - if (pmd != pmd_offset(pgd, 0)) - BUG(); + pmd = pmd_offset(pgd, PAGE_OFFSET); for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { vaddr = i*PGDIR_SIZE + j*PMD_SIZE; if (end && (vaddr >= end)) @@ -243,14 +231,10 @@ if (cpu_has_pse) { unsigned long __pe; - set_in_cr4(X86_CR4_PSE); - boot_cpu_data.wp_works_ok = 1; __pe = _KERNPG_TABLE + _PAGE_PSE + __pa(vaddr); /* Make it "global" too if supported */ - if (cpu_has_pge) { - set_in_cr4(X86_CR4_PGE); + if (cpu_has_pge) __pe += _PAGE_GLOBAL; - } set_pmd(pmd, __pmd(__pe)); continue; } @@ -289,17 +273,6 @@ pte = pte_offset(pmd, vaddr); pkmap_page_table = pte; #endif - -#if CONFIG_X86_PAE - /* - * Add low memory identity-mappings - SMP needs it when - * starting up on an AP from real-mode. In the non-PAE - * case we already have these mappings through head.S. - * All user-space mappings are explicitly cleared after - * SMP startup. - */ - pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; -#endif } void __init zap_low_mappings (void) @@ -312,11 +285,7 @@ * us, because pgd_clear() is a no-op on i386. */ for (i = 0; i < USER_PTRS_PER_PGD; i++) -#if CONFIG_X86_PAE - set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); -#else set_pgd(swapper_pg_dir+i, __pgd(0)); -#endif flush_tlb_all(); } @@ -353,17 +322,17 @@ pagetable_init(); load_cr3(swapper_pg_dir); + __flush_tlb_all(); -#if CONFIG_X86_PAE - /* - * We will bail out later - printk doesn't work right now so - * the user would just see a hanging kernel. - */ - if (cpu_has_pae) - set_in_cr4(X86_CR4_PAE); +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + +#ifdef CONFIG_X86_PAE + memcpy(kernexec_pm_dir, swapper_pm_dir, sizeof(kernexec_pm_dir)); +#else + memcpy(kernexec_pg_dir, swapper_pg_dir, sizeof(kernexec_pg_dir)); #endif - __flush_tlb_all(); +#endif #ifdef CONFIG_HIGHMEM kmap_init(); @@ -529,7 +498,7 @@ reservedpages = free_pages_init(); codesize = (unsigned long) &_etext - (unsigned long) &_text; - datasize = (unsigned long) &_edata - (unsigned long) &_etext; + datasize = (unsigned long) &_edata - (unsigned long) &_data; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", @@ -542,10 +511,6 @@ (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) ); -#if CONFIG_X86_PAE - if (!cpu_has_pae) - panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); -#endif if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); @@ -589,6 +554,45 @@ { unsigned long addr; +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + /* PaX: limit KERNEL_CS to actual size */ + { + unsigned long limit; + pgd_t *pgd; + pmd_t *pmd; + + limit = (unsigned long)&_etext >> PAGE_SHIFT; + gdt_table[2].a = (gdt_table[2].a & 0xFFFF0000UL) | (limit & 0x0FFFFUL); + gdt_table[2].b = (gdt_table[2].b & 0xFFF0FFFFUL) | (limit & 0xF0000UL); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + gdt_table2[2].a = (gdt_table2[2].a & 0xFFFF0000UL) | (limit & 0x0FFFFUL); + gdt_table2[2].b = (gdt_table2[2].b & 0xFFF0FFFFUL) | (limit & 0xF0000UL); +#endif + + /* PaX: make KERNEL_CS read-only */ + for (addr = __KERNEL_TEXT_OFFSET; addr < (unsigned long)&_data; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pmd = pmd_offset(pgd, addr); + set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_GLOBAL)); + } + +#ifdef CONFIG_X86_PAE + memcpy(kernexec_pm_dir, swapper_pm_dir, sizeof(kernexec_pm_dir)); +#else + memcpy(kernexec_pg_dir, swapper_pg_dir, sizeof(kernexec_pg_dir)); +#endif + + for (addr = __KERNEL_TEXT_OFFSET; addr < (unsigned long)&_data; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pmd = pmd_offset(pgd, addr); + set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW)); + } + flush_tlb_all(); + } +#endif + + memset(&__init_begin, 0, &__init_end - &__init_begin); addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); diff -ruN linux-2.4.29/arch/i386/mm/ioremap.c linux-2.4.29-BF6-C7_III-grsec/arch/i386/mm/ioremap.c --- linux-2.4.29/arch/i386/mm/ioremap.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/mm/ioremap.c 2005-03-21 17:27:01.000000000 -0700 @@ -49,7 +49,7 @@ if (address >= end) BUG(); do { - pte_t * pte = pte_alloc(&init_mm, pmd, address); + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); diff -ruN linux-2.4.29/arch/i386/vmlinux.lds linux-2.4.29-BF6-C7_III-grsec/arch/i386/vmlinux.lds --- linux-2.4.29/arch/i386/vmlinux.lds 2002-02-25 12:37:53.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/vmlinux.lds 1969-12-31 17:00:00.000000000 -0700 @@ -1,82 +0,0 @@ -/* ld script to make i386 Linux kernel - * Written by Martin Mares ; - */ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -ENTRY(_start) -SECTIONS -{ - . = 0xC0000000 + 0x100000; - _text = .; /* Text and read-only data */ - .text : { - *(.text) - *(.fixup) - *(.gnu.warning) - } = 0x9090 - - _etext = .; /* End of text section */ - - .rodata : { *(.rodata) *(.rodata.*) } - .kstrtab : { *(.kstrtab) } - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - .data : { /* Data */ - *(.data) - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - . = ALIGN(8192); /* init_task */ - .data.init_task : { *(.data.init_task) } - - . = ALIGN(4096); /* Init code and data */ - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(16); - __setup_start = .; - .setup.init : { *(.setup.init) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(4096); - __init_end = .; - - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } - _end = . ; - - /* Sections to be discarded */ - /DISCARD/ : { - *(.text.exit) - *(.data.exit) - *(.exitcall.exit) - } - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } -} diff -ruN linux-2.4.29/arch/i386/vmlinux.lds.S linux-2.4.29-BF6-C7_III-grsec/arch/i386/vmlinux.lds.S --- linux-2.4.29/arch/i386/vmlinux.lds.S 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/i386/vmlinux.lds.S 2005-03-21 17:27:01.053281211 -0700 @@ -0,0 +1,129 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = __PAGE_OFFSET + 0x100000; + .text.startup : { + BYTE(0xEA) /* jmp far */ + LONG(startup_32 + __KERNEL_TEXT_OFFSET - __PAGE_OFFSET) + SHORT(__KERNEL_CS) + } + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + __text_init_start = .; + .text.init (. - __KERNEL_TEXT_OFFSET) : AT (__text_init_start) { + *(.text.init) + . = ALIGN(4*1024*1024) - 1; + BYTE(0) + } + __init_end = . + __KERNEL_TEXT_OFFSET; + +/* + * PaX: this must be kept in synch with the KERNEL_CS base + * in the GDTs in arch/i386/kernel/head.S + */ + _text = .; /* Text and read-only data */ + .text : AT (. + __KERNEL_TEXT_OFFSET) { +#else + .text.init : { *(.text.init) } + . = ALIGN(4096); + __init_end = .; + _text = .; /* Text and read-only data */ + .text : { +#endif + + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + + _etext = .; /* End of text section */ + + . = ALIGN(4096); + . += __KERNEL_TEXT_OFFSET; + .rodata.page_aligned : { + *(.rodata.empty_zero_page) + *(.rodata.idt) + } + .rodata : { *(.rodata) *(.rodata.*) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + +#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC + . = ALIGN(4*1024*1024); +#else + . = ALIGN(32); +#endif + + _data = .; + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + . = ALIGN(8192); + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); + .data.page_aligned : { + *(.data.pg0) + +#ifdef CONFIG_X86_PAE + *(.data.swapper_pm_dir) +#endif + + *(.data.swapper_pg_dir) + } + + _edata = .; /* End of data section */ + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + __bss_end = . ; + + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -ruN linux-2.4.29/arch/ia64/config.in linux-2.4.29-BF6-C7_III-grsec/arch/ia64/config.in --- linux-2.4.29/arch/ia64/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ia64/config.in 2005-03-21 17:27:01.054281063 -0700 @@ -319,3 +319,12 @@ int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0 endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -ruN linux-2.4.29/arch/ia64/ia32/binfmt_elf32.c linux-2.4.29-BF6-C7_III-grsec/arch/ia64/ia32/binfmt_elf32.c --- linux-2.4.29/arch/ia64/ia32/binfmt_elf32.c 2005-01-19 07:09:26.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ia64/ia32/binfmt_elf32.c 2005-03-21 17:27:01.055280914 -0700 @@ -46,6 +46,16 @@ static void elf32_set_personality (void); +#ifdef CONFIG_GRKERNSEC_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE(tsk) ((tsk)->personality == PER_LINUX32 ? 0x08048000UL : 0x4000000000000000UL) +#define PAX_DELTA_MMAP_LSB(tsk) IA32_PAGE_SHIFT +#define PAX_DELTA_MMAP_LEN(tsk) ((tsk)->personality == PER_LINUX32 ? 16 : 43 - IA32_PAGE_SHIFT) +#define PAX_DELTA_EXEC_LSB(tsk) IA32_PAGE_SHIFT +#define PAX_DELTA_EXEC_LEN(tsk) ((tsk)->personality == PER_LINUX32 ? 16 : 43 - IA32_PAGE_SHIFT) +#define PAX_DELTA_STACK_LSB(tsk) IA32_PAGE_SHIFT +#define PAX_DELTA_STACK_LEN(tsk) ((tsk)->personality == PER_LINUX32 ? 16 : 43 - IA32_PAGE_SHIFT) +#endif + #define ELF_PLAT_INIT(_r, load_addr) ia64_elf32_init(_r) #define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) #define elf_map elf32_map @@ -190,8 +200,15 @@ mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = IA32_STACK_TOP; - mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (!(current->flags & PF_PAX_PAGEEXEC)) + mpnt->vm_page_prot = protection_map[(VM_STACK_FLAGS | VM_EXEC) & 0x7]; + else +#endif + + mpnt->vm_page_prot = protection_map[VM_STACK_FLAGS & 0x7]; mpnt->vm_ops = NULL; mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; diff -ruN linux-2.4.29/arch/ia64/ia32/sys_ia32.c linux-2.4.29-BF6-C7_III-grsec/arch/ia64/ia32/sys_ia32.c --- linux-2.4.29/arch/ia64/ia32/sys_ia32.c 2005-01-19 07:09:26.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ia64/ia32/sys_ia32.c 2005-03-21 17:27:01.057280617 -0700 @@ -536,6 +536,11 @@ flags = a.flags; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { file = fget(a.fd); @@ -557,6 +562,11 @@ struct file *file = NULL; unsigned long retval; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); diff -ruN linux-2.4.29/arch/ia64/kernel/ptrace.c linux-2.4.29-BF6-C7_III-grsec/arch/ia64/kernel/ptrace.c --- linux-2.4.29/arch/ia64/kernel/ptrace.c 2004-04-14 07:05:26.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ia64/kernel/ptrace.c 2005-03-21 17:27:01.060280171 -0700 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -1299,6 +1300,9 @@ if (pid == 1) /* no messing around with init! */ goto out_tsk; + if (gr_handle_ptrace(child, request)) + goto out_tsk; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; diff -ruN linux-2.4.29/arch/ia64/kernel/sys_ia64.c linux-2.4.29-BF6-C7_III-grsec/arch/ia64/kernel/sys_ia64.c --- linux-2.4.29/arch/ia64/kernel/sys_ia64.c 2004-02-18 06:36:30.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ia64/kernel/sys_ia64.c 2005-03-21 17:27:01.061280022 -0700 @@ -34,6 +34,13 @@ if (rgn_index(addr)==REGION_HPAGE) addr = 0; #endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap; + else +#endif + if (!addr) addr = TASK_UNMAPPED_BASE; @@ -180,6 +187,11 @@ unsigned long roff; struct file *file = 0; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); diff -ruN linux-2.4.29/arch/ia64/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/ia64/mm/fault.c --- linux-2.4.29/arch/ia64/mm/fault.c 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ia64/mm/fault.c 2005-03-21 17:27:01.061280022 -0700 @@ -36,6 +36,10 @@ if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)) return -ENOMEM; + if ((vma->vm_flags & VM_LOCKED && + ((vma->vm_mm->locked_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_MEMLOCK].rlim_cur && + !capable(CAP_IPC_LOCK)) + return -ENOMEM; vma->vm_end += PAGE_SIZE; vma->vm_mm->total_vm += grow; if (vma->vm_flags & VM_LOCKED) @@ -70,6 +74,53 @@ return pte_present(pte); } +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->cr_iip = fault address) + * + * returns 1 when task should be killed + * 2 when legitimate ET_EXEC was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + int err; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) { + if (regs->cr_iip >= current->mm->start_code && + regs->cr_iip < current->mm->end_code) + { +#if 0 + /* PaX: this needs fixing */ + if (regs->b0 == regs->cr_iip) + return 1; +#endif + regs->cr_iip += current->mm->delta_exec; + return 2; + } + } +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 8; i++) { + unsigned int c; + if (get_user(c, (unsigned int*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { @@ -122,9 +173,29 @@ | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT) | (((isr >> IA64_ISR_R_BIT) & 1UL) << VM_READ_BIT)); - if ((vma->vm_flags & mask) != mask) - goto bad_area; + if ((vma->vm_flags & mask) != mask) { + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (!(vma->vm_flags & VM_EXEC) && (mask & VM_EXEC)) { + if (!(current->flags & PF_PAX_PAGEEXEC) || address != regs->cr_iip) + goto bad_area; + + up_read(&mm->mmap_sem); + switch(pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 2: + return; +#endif + + } + pax_report_fault(regs, (void*)regs->cr_iip, (void*)regs->r12); + do_exit(SIGKILL); + } +#endif + goto bad_area; + } survive: /* * If for any reason at all we couldn't handle the fault, make @@ -159,7 +230,7 @@ if (rgn_index(address) != rgn_index(vma->vm_start) || rgn_offset(address) >= RGN_MAP_LIMIT) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(current, vma, address)) goto bad_area; } else { vma = prev_vma; diff -ruN linux-2.4.29/arch/ia64/mm/init.c linux-2.4.29-BF6-C7_III-grsec/arch/ia64/mm/init.c --- linux-2.4.29/arch/ia64/mm/init.c 2005-01-19 07:09:26.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ia64/mm/init.c 2005-03-21 17:27:01.062279873 -0700 @@ -105,6 +105,7 @@ vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; + vma->vm_mirror = 0; down_write(¤t->mm->mmap_sem); if (insert_vm_struct(current->mm, vma)) { up_write(¤t->mm->mmap_sem); diff -ruN linux-2.4.29/arch/m68k/config.in linux-2.4.29-BF6-C7_III-grsec/arch/m68k/config.in --- linux-2.4.29/arch/m68k/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/m68k/config.in 2005-03-21 17:27:01.063279724 -0700 @@ -557,3 +557,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/m68k/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/m68k/mm/fault.c --- linux-2.4.29/arch/m68k/mm/fault.c 2002-11-28 16:53:09.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/m68k/mm/fault.c 2005-03-21 17:27:01.063279724 -0700 @@ -120,7 +120,7 @@ if (address + 256 < rdusp()) goto map_err; } - if (expand_stack(vma, address)) + if (expand_stack(current, vma, address)) goto map_err; /* diff -ruN linux-2.4.29/arch/mips/config.in linux-2.4.29-BF6-C7_III-grsec/arch/mips/config.in --- linux-2.4.29/arch/mips/config.in 2002-11-28 16:53:09.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/mips/config.in 2005-03-21 17:27:01.064279576 -0700 @@ -7,3 +7,11 @@ define_bool CONFIG_MIPS64 n source arch/mips/config-shared.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/mips/kernel/syscall.c linux-2.4.29-BF6-C7_III-grsec/arch/mips/kernel/syscall.c --- linux-2.4.29/arch/mips/kernel/syscall.c 2005-01-19 07:09:29.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/mips/kernel/syscall.c 2005-03-21 17:27:01.065279427 -0700 @@ -82,6 +82,11 @@ do_color_align = 0; if (filp || (flags & MAP_SHARED)) do_color_align = 1; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if (!(current->flags & PF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -92,6 +97,13 @@ (!vmm || addr + len <= vmm->vm_start)) return addr; } + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap; + else +#endif + addr = TASK_UNMAPPED_BASE; if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); diff -ruN linux-2.4.29/arch/mips/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/mips/mm/fault.c --- linux-2.4.29/arch/mips/mm/fault.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/mips/mm/fault.c 2005-03-21 17:27:01.066279278 -0700 @@ -69,6 +69,24 @@ } } +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -114,7 +132,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(tsk, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -ruN linux-2.4.29/arch/mips64/config.in linux-2.4.29-BF6-C7_III-grsec/arch/mips64/config.in --- linux-2.4.29/arch/mips64/config.in 2002-11-28 16:53:10.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/mips64/config.in 2005-03-21 17:27:01.066279278 -0700 @@ -7,3 +7,11 @@ define_bool CONFIG_MIPS64 y source arch/mips/config-shared.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/mips64/kernel/binfmt_elfn32.c linux-2.4.29-BF6-C7_III-grsec/arch/mips64/kernel/binfmt_elfn32.c --- linux-2.4.29/arch/mips64/kernel/binfmt_elfn32.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/mips64/kernel/binfmt_elfn32.c 2005-03-21 17:27:01.067279130 -0700 @@ -50,6 +50,17 @@ #undef ELF_ET_DYN_BASE #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) +#ifdef CONFIG_GRKERNSEC_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_MMAP_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_EXEC_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_EXEC_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_STACK_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include #include diff -ruN linux-2.4.29/arch/mips64/kernel/binfmt_elfo32.c linux-2.4.29-BF6-C7_III-grsec/arch/mips64/kernel/binfmt_elfo32.c --- linux-2.4.29/arch/mips64/kernel/binfmt_elfo32.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/mips64/kernel/binfmt_elfo32.c 2005-03-21 17:27:01.067279130 -0700 @@ -52,6 +52,17 @@ #undef ELF_ET_DYN_BASE #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) +#ifdef CONFIG_GRKERNSEC_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_MMAP_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_EXEC_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_EXEC_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_STACK_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include #include diff -ruN linux-2.4.29/arch/mips64/kernel/syscall.c linux-2.4.29-BF6-C7_III-grsec/arch/mips64/kernel/syscall.c --- linux-2.4.29/arch/mips64/kernel/syscall.c 2005-01-19 07:09:33.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/mips64/kernel/syscall.c 2005-03-21 17:27:01.068278981 -0700 @@ -80,6 +80,11 @@ do_color_align = 0; if (filp || (flags & MAP_SHARED)) do_color_align = 1; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if (!(current->flags & PF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -90,6 +95,13 @@ (!vmm || addr + len <= vmm->vm_start)) return addr; } + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap; + else +#endif + addr = TASK_UNMAPPED_BASE; if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); diff -ruN linux-2.4.29/arch/mips64/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/mips64/mm/fault.c --- linux-2.4.29/arch/mips64/mm/fault.c 2004-02-18 06:36:30.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/mips64/mm/fault.c 2005-03-21 17:27:01.069278832 -0700 @@ -90,6 +90,24 @@ } } +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -137,7 +155,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(tsk, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -ruN linux-2.4.29/arch/parisc/config.in linux-2.4.29-BF6-C7_III-grsec/arch/parisc/config.in --- linux-2.4.29/arch/parisc/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/parisc/config.in 2005-03-21 17:27:01.069278832 -0700 @@ -204,3 +204,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/parisc/kernel/ioctl32.c linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/ioctl32.c --- linux-2.4.29/arch/parisc/kernel/ioctl32.c 2005-01-19 07:09:34.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/ioctl32.c 2005-03-21 17:27:01.071278535 -0700 @@ -1434,7 +1434,11 @@ * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or super-user. */ +#ifdef CONFIG_GRKERNSEC + if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) +#else if (current->tty == tty || suser()) +#endif return 1; return 0; } diff -ruN linux-2.4.29/arch/parisc/kernel/ptrace.c linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/ptrace.c --- linux-2.4.29/arch/parisc/kernel/ptrace.c 2002-11-28 16:53:10.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/ptrace.c 2005-03-21 17:27:01.073278238 -0700 @@ -15,7 +15,7 @@ #include #include #include - +#include #include #include #include @@ -119,6 +119,9 @@ if (pid == 1) /* no messing around with init! */ goto out_tsk; + if (gr_handle_ptrace(child, request)) + goto out_tsk; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; diff -ruN linux-2.4.29/arch/parisc/kernel/sys_parisc.c linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/sys_parisc.c --- linux-2.4.29/arch/parisc/kernel/sys_parisc.c 2002-11-28 16:53:10.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/sys_parisc.c 2005-03-21 17:27:01.073278238 -0700 @@ -90,6 +90,11 @@ inode = filp->f_dentry->d_inode; } +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap; +#endif + if (inode && (flags & MAP_SHARED) && (inode->i_mapping->i_mmap_shared)) { addr = get_shared_area(inode, addr, len, pgoff); } else { @@ -104,6 +109,12 @@ { struct file * file = NULL; unsigned long error = -EBADF; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) diff -ruN linux-2.4.29/arch/parisc/kernel/sys_parisc32.c linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/sys_parisc32.c --- linux-2.4.29/arch/parisc/kernel/sys_parisc32.c 2005-01-19 07:09:35.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/sys_parisc32.c 2005-03-21 17:27:01.075277940 -0700 @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -177,6 +178,11 @@ struct file *file; int retval; int i; +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif file = open_exec(filename); @@ -184,7 +190,26 @@ if (IS_ERR(file)) return retval; + gr_learn_resource(current, RLIMIT_NPROC, atomic_read(¤t->user->processes), 1); + + if (gr_handle_nproc()) { + allow_write_access(file); + fput(file); + return -EAGAIN; + } + + if (!gr_acl_handle_execve(file->f_dentry, file->f_vfsmnt)) { + allow_write_access(file); + fput(file); + return -EACCES; + } + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + +#ifdef CONFIG_GRKERNSEC_PAX_RANDUSTACK + bprm.p -= (get_random_long() & ~(sizeof(void *)-1)) & ~PAGE_MASK; +#endif + memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); DBG(("do_execve32(%s, %p, %p, %p)\n", filename, argv, envp, regs)); @@ -209,11 +234,24 @@ if (retval < 0) goto out; + if (!gr_tpe_allow(file)) { + retval = -EACCES; + goto out; + } + + if (gr_check_crash_exec(file)) { + retval = -EACCES; + goto out; + } + retval = copy_strings_kernel(1, &bprm.filename, &bprm); if (retval < 0) goto out; bprm.exec = bprm.p; + + gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); + retval = copy_strings32(bprm.envc, envp, &bprm); if (retval < 0) goto out; @@ -222,11 +260,32 @@ if (retval < 0) goto out; +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->rlim, sizeof(old_rlim)); + old_exec_file = current->exec_file; + get_file(file); + current->exec_file = file; +#endif + + gr_set_proc_label(file->f_dentry, file->f_vfsmnt); + retval = search_binary_handler(&bprm,regs); - if (retval >= 0) + if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif /* execve success */ return retval; + } +#ifdef CONFIG_GRKERNSEC + current->acl = old_acl; + memcpy(current->rlim, old_rlim, sizeof(old_rlim)); + fput(current->exec_file); + current->exec_file = old_exec_file; +#endif out: /* Something went wrong, return the inode and free the argument pages*/ allow_write_access(bprm.file); diff -ruN linux-2.4.29/arch/parisc/kernel/traps.c linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/traps.c --- linux-2.4.29/arch/parisc/kernel/traps.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/parisc/kernel/traps.c 2005-03-21 17:27:01.076277792 -0700 @@ -637,9 +637,7 @@ down_read(¤t->mm->mmap_sem); vma = find_vma(current->mm,regs->iaoq[0]); - if (vma && (regs->iaoq[0] >= vma->vm_start) - && (vma->vm_flags & VM_EXEC)) { - + if (vma && (regs->iaoq[0] >= vma->vm_start)) { fault_address = regs->iaoq[0]; fault_space = regs->iasq[0]; diff -ruN linux-2.4.29/arch/parisc/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/parisc/mm/fault.c --- linux-2.4.29/arch/parisc/mm/fault.c 2003-06-13 08:51:31.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/parisc/mm/fault.c 2005-03-21 17:27:01.077277643 -0700 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -53,7 +54,7 @@ static unsigned long parisc_acctyp(unsigned long code, unsigned int inst) { - if (code == 6 || code == 16) + if (code == 6 || code == 7 || code == 16) return VM_EXEC; switch (inst & 0xf0000000) { @@ -139,6 +140,136 @@ } #endif +/* + * PaX: decide what to do with offenders (instruction_pointer(regs) = fault address) + * + * returns 1 when task should be killed + * 2 when rt_sigreturn trampoline was detected + * 3 when unpatched PLT trampoline was detected + * 4 when legitimate ET_EXEC was detected + */ +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + int err; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) { + if (instruction_pointer(regs) >= current->mm->start_code && + instruction_pointer(regs) < current->mm->end_code) + { +#if 0 + /* PaX: this needs fixing */ + if ((regs->gr[2] & ~3UL) == instruction_pointer(regs)) + return 1; +#endif + regs->iaoq[0] += current->mm->delta_exec; + if ((regs->iaoq[1] & ~3UL) >= current->mm->start_code && + (regs->iaoq[1] & ~3UL) < current->mm->end_code) + regs->iaoq[1] += current->mm->delta_exec; + return 4; + } + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + do { /* PaX: unpatched PLT emulation */ + unsigned int bl, depwi; + + err = get_user(bl, (unsigned int*)instruction_pointer(regs)); + err |= get_user(depwi, (unsigned int*)(instruction_pointer(regs)+4)); + + if (err) + break; + + if (bl == 0xEA9F1FDDU && depwi == 0xD6801C1EU) { + unsigned int ldw, bv, ldw2, addr = instruction_pointer(regs)-12; + + err = get_user(ldw, (unsigned int*)addr); + err |= get_user(bv, (unsigned int*)(addr+4)); + err |= get_user(ldw2, (unsigned int*)(addr+8)); + + if (err) + break; + + if (ldw == 0x0E801096U && + bv == 0xEAC0C000U && + ldw2 == 0x0E881095U) + { + unsigned int resolver, map; + + err = get_user(resolver, (unsigned int*)(instruction_pointer(regs)+8)); + err |= get_user(map, (unsigned int*)(instruction_pointer(regs)+12)); + if (err) + break; + + regs->gr[20] = instruction_pointer(regs)+8; + regs->gr[21] = map; + regs->gr[22] = resolver; + regs->iaoq[0] = resolver | 3UL; + regs->iaoq[1] = regs->iaoq[0] + 4; + return 3; + } + } + } while (0); +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + +#ifndef CONFIG_GRKERNSEC_PAX_EMUSIGRT + if (!(current->flags & PF_PAX_EMUTRAMP)) + return 1; +#endif + + do { /* PaX: rt_sigreturn emulation */ + unsigned int ldi1, ldi2, bel, nop; + + err = get_user(ldi1, (unsigned int *)instruction_pointer(regs)); + err |= get_user(ldi2, (unsigned int *)(instruction_pointer(regs)+4)); + err |= get_user(bel, (unsigned int *)(instruction_pointer(regs)+8)); + err |= get_user(nop, (unsigned int *)(instruction_pointer(regs)+12)); + + if (err) + break; + + if ((ldi1 == 0x34190000U || ldi1 == 0x34190002U) && + ldi2 == 0x3414015AU && + bel == 0xE4008200U && + nop == 0x08000240U) + { + regs->gr[25] = (ldi1 & 2) >> 1; + regs->gr[20] = __NR_rt_sigreturn; + regs->gr[31] = regs->iaoq[1] + 16; + regs->sr[0] = regs->iasq[1]; + regs->iaoq[0] = 0x100UL; + regs->iaoq[1] = regs->iaoq[0] + 4; + regs->iasq[0] = regs->sr[2]; + regs->iasq[1] = regs->sr[2]; + return 2; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address) { @@ -164,8 +295,38 @@ acc_type = parisc_acctyp(code,regs->iir); - if ((vma->vm_flags & acc_type) != acc_type) + if ((vma->vm_flags & acc_type) != acc_type) { + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if ((current->flags & PF_PAX_PAGEEXEC) && (acc_type & VM_EXEC) && + (address & ~3UL) == instruction_pointer(regs)) + { + up_read(&mm->mmap_sem); + switch(pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 4: + return; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + case 3: + return; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + case 2: + return; +#endif + + } + pax_report_fault(regs, (void*)instruction_pointer(regs), (void*)regs->gr[30]); + do_exit(SIGKILL); + } +#endif + goto bad_area; + } /* * If for any reason at all we couldn't handle the fault, make @@ -195,7 +356,7 @@ check_expansion: vma = prev_vma; - if (vma && (expand_stack(vma, address) == 0)) + if (vma && (expand_stack(current, vma, address) == 0)) goto good_area; /* diff -ruN linux-2.4.29/arch/ppc/config.in linux-2.4.29-BF6-C7_III-grsec/arch/ppc/config.in --- linux-2.4.29/arch/ppc/config.in 2004-08-07 17:26:04.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ppc/config.in 2005-03-21 17:27:01.077277643 -0700 @@ -666,3 +666,12 @@ int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0 endmenu + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu + diff -ruN linux-2.4.29/arch/ppc/kernel/head_4xx.S linux-2.4.29-BF6-C7_III-grsec/arch/ppc/kernel/head_4xx.S --- linux-2.4.29/arch/ppc/kernel/head_4xx.S 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ppc/kernel/head_4xx.S 2005-03-21 17:27:01.078277494 -0700 @@ -296,15 +296,12 @@ /* Most of the Linux PTE is ready to load into the TLB LO. * We set ZSEL, where only the LS-bit determines user access. - * We set execute, because we don't have the granularity to - * properly set this at the page level (Linux problem). * If shared is set, we cause a zero PID->TID load. * Many of these bits are software only. Bits we don't set * here we (properly should) assume have the appropriate value. */ li r22, 0x0ce2 andc r21, r21, r22 /* Make sure 20, 21 are zero */ - ori r21, r21, _PAGE_HWEXEC /* make it executable */ /* find the TLB index that caused the fault. It has to be here. */ @@ -783,7 +780,6 @@ stw r23, tlb_4xx_index@l(0) 6: - ori r21, r21, _PAGE_HWEXEC /* make it executable */ tlbwe r21, r23, TLB_DATA /* Load TLB LO */ /* Create EPN. This is the faulting address plus a static diff -ruN linux-2.4.29/arch/ppc/kernel/ptrace.c linux-2.4.29-BF6-C7_III-grsec/arch/ppc/kernel/ptrace.c --- linux-2.4.29/arch/ppc/kernel/ptrace.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ppc/kernel/ptrace.c 2005-03-21 17:27:01.079277346 -0700 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -195,6 +196,9 @@ if (pid == 1) /* you may not mess with init */ goto out_tsk; + if (gr_handle_ptrace(child, request)) + goto out_tsk; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; diff -ruN linux-2.4.29/arch/ppc/kernel/syscalls.c linux-2.4.29-BF6-C7_III-grsec/arch/ppc/kernel/syscalls.c --- linux-2.4.29/arch/ppc/kernel/syscalls.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ppc/kernel/syscalls.c 2005-03-21 17:27:01.079277346 -0700 @@ -191,6 +191,11 @@ struct file * file = NULL; int ret = -EBADF; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { if (!(file = fget(fd))) diff -ruN linux-2.4.29/arch/ppc/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/ppc/mm/fault.c --- linux-2.4.29/arch/ppc/mm/fault.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ppc/mm/fault.c 2005-03-21 17:27:01.080277197 -0700 @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include #include @@ -52,6 +55,361 @@ void bad_page_fault(struct pt_regs *, unsigned long, int sig); void do_page_fault(struct pt_regs *, unsigned long, unsigned long); +#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT +void pax_syscall_close(struct vm_area_struct * vma) +{ + vma->vm_mm->call_syscall = 0UL; +} + +static struct page* pax_syscall_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) +{ + struct page* page; + unsigned int *kaddr; + + page = alloc_page(GFP_HIGHUSER); + if (!page) + return page; + + kaddr = kmap(page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x44000002U; /* sc */ + __flush_dcache_icache(kaddr); + kunmap(page); + return page; +} + +static struct vm_operations_struct pax_vm_ops = { + close: pax_syscall_close, + nopage: pax_syscall_nopage, +}; + +static void pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f]; + vma->vm_ops = &pax_vm_ops; + vma->vm_pgoff = 0UL; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + vma->vm_mirror = 0; + insert_vm_struct(current->mm, vma); + ++current->mm->total_vm; +} +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->nip = fault address) + * + * returns 1 when task should be killed + * 2 when patched GOT trampoline was detected + * 3 when patched PLT trampoline was detected + * 4 when unpatched PLT trampoline was detected + * 5 when legitimate ET_EXEC was detected + * 6 when sigreturn trampoline was detected + * 7 when rt_sigreturn trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + int err; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) { + if (regs->nip >= current->mm->start_code && + regs->nip < current->mm->end_code) + { + if (regs->link == regs->nip) + return 1; + + regs->nip += current->mm->delta_exec; + return 5; + } + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + do { /* PaX: patched GOT emulation */ + unsigned int blrl; + + err = get_user(blrl, (unsigned int*)regs->nip); + + if (!err && blrl == 0x4E800021U) { + unsigned long temp = regs->nip; + + regs->nip = regs->link & 0xFFFFFFFCUL; + regs->link = temp + 4UL; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #1 */ + unsigned int b; + + err = get_user(b, (unsigned int *)regs->nip); + + if (!err && (b & 0xFC000003U) == 0x48000000U) { + regs->nip += (((b | 0xFC000000UL) ^ 0x02000000UL) + 0x02000000UL); + return 3; + } + } while (0); + + do { /* PaX: unpatched PLT emulation #1 */ + unsigned int li, b; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(b, (unsigned int *)(regs->nip+4)); + + if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) { + unsigned int rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(rlwinm, (unsigned int*)addr); + err |= get_user(add, (unsigned int*)(addr+4)); + err |= get_user(li2, (unsigned int*)(addr+8)); + err |= get_user(addis2, (unsigned int*)(addr+12)); + err |= get_user(mtctr, (unsigned int*)(addr+16)); + err |= get_user(li3, (unsigned int*)(addr+20)); + err |= get_user(addis3, (unsigned int*)(addr+24)); + err |= get_user(bctr, (unsigned int*)(addr+28)); + + if (err) + break; + + if (rlwinm == 0x556C083CU && + add == 0x7D6C5A14U && + (li2 & 0xFFFF0000U) == 0x39800000U && + (addis2 & 0xFFFF0000U) == 0x3D8C0000U && + mtctr == 0x7D8903A6U && + (li3 & 0xFFFF0000U) == 0x39800000U && + (addis3 & 0xFFFF0000U) == 0x3D8C0000U && + bctr == 0x4E800420U) + { + regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16; + regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->ctr += (addis2 & 0xFFFFU) << 16; + regs->nip = regs->ctr; + return 4; + } + } + } while (0); + +#if 0 + do { /* PaX: unpatched PLT emulation #2 */ + unsigned int lis, lwzu, b, bctr; + + err = get_user(lis, (unsigned int *)regs->nip); + err |= get_user(lwzu, (unsigned int *)(regs->nip+4)); + err |= get_user(b, (unsigned int *)(regs->nip+8)); + err |= get_user(bctr, (unsigned int *)(regs->nip+12)); + + if (err) + break; + + if ((lis & 0xFFFF0000U) == 0x39600000U && + (lwzu & 0xU) == 0xU && + (b & 0xFC000003U) == 0x48000000U && + bctr == 0x4E800420U) + { + unsigned int addis, addi, rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 12 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(addis, (unsigned int*)addr); + err |= get_user(addi, (unsigned int*)(addr+4)); + err |= get_user(rlwinm, (unsigned int*)(addr+8)); + err |= get_user(add, (unsigned int*)(addr+12)); + err |= get_user(li2, (unsigned int*)(addr+16)); + err |= get_user(addis2, (unsigned int*)(addr+20)); + err |= get_user(mtctr, (unsigned int*)(addr+24)); + err |= get_user(li3, (unsigned int*)(addr+28)); + err |= get_user(addis3, (unsigned int*)(addr+32)); + err |= get_user(bctr, (unsigned int*)(addr+36)); + + if (err) + break; + + if ((addis & 0xFFFF0000U) == 0x3D6B0000U && + (addi & 0xFFFF0000U) == 0x396B0000U && + rlwinm == 0x556C083CU && + add == 0x7D6C5A14U && + (li2 & 0xFFFF0000U) == 0x39800000U && + (addis2 & 0xFFFF0000U) == 0x3D8C0000U && + mtctr == 0x7D8903A6U && + (li3 & 0xFFFF0000U) == 0x39800000U && + (addis3 & 0xFFFF0000U) == 0x3D8C0000U && + bctr == 0x4E800420U) + { + regs->gpr[PT_R11] = + regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16; + regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->ctr += (addis2 & 0xFFFFU) << 16; + regs->nip = regs->ctr; + return 4; + } + } + } while (0); +#endif + + do { /* PaX: unpatched PLT emulation #3 */ + unsigned int li, b; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(b, (unsigned int *)(regs->nip+4)); + + if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) { + unsigned int addis, lwz, mtctr, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(addis, (unsigned int*)addr); + err |= get_user(lwz, (unsigned int*)(addr+4)); + err |= get_user(mtctr, (unsigned int*)(addr+8)); + err |= get_user(bctr, (unsigned int*)(addr+12)); + + if (err) + break; + + if ((addis & 0xFFFF0000U) == 0x3D6B0000U && + (lwz & 0xFFFF0000U) == 0x816B0000U && + mtctr == 0x7D6903A6U && + bctr == 0x4E800420U) + { + unsigned int r11; + + addr = (addis << 16) + (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + addr += (((lwz | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + + err = get_user(r11, (unsigned int*)addr); + if (err) + break; + + regs->gpr[PT_R11] = r11; + regs->ctr = r11; + regs->nip = r11; + return 4; + } + } + } while (0); +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT + do { /* PaX: sigreturn emulation */ + unsigned int li, sc; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(sc, (unsigned int *)(regs->nip+4)); + + if (!err && li == 0x38007777U && sc == 0x44000002U) { + struct vm_area_struct *vma; + unsigned long call_syscall; + + down_read(¤t->mm->mmap_sem); + call_syscall = current->mm->call_syscall; + up_read(¤t->mm->mmap_sem); + if (likely(call_syscall)) + goto emulate; + + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_syscall) { + call_syscall = current->mm->call_syscall; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_syscall & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + pax_insert_vma(vma, call_syscall); + current->mm->call_syscall = call_syscall; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->gpr[PT_R0] = 0x7777UL; + regs->nip = call_syscall; + return 6; + } + } while (0); + + do { /* PaX: rt_sigreturn emulation */ + unsigned int li, sc; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(sc, (unsigned int *)(regs->nip+4)); + + if (!err && li == 0x38006666U && sc == 0x44000002U) { + struct vm_area_struct *vma; + unsigned int call_syscall; + + down_read(¤t->mm->mmap_sem); + call_syscall = current->mm->call_syscall; + up_read(¤t->mm->mmap_sem); + if (likely(call_syscall)) + goto rt_emulate; + + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_syscall) { + call_syscall = current->mm->call_syscall; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto rt_emulate; + } + + call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_syscall & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + pax_insert_vma(vma, call_syscall); + current->mm->call_syscall = call_syscall; + up_write(¤t->mm->mmap_sem); + +rt_emulate: + regs->gpr[PT_R0] = 0x6666UL; + regs->nip = call_syscall; + return 7; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + /* * Check whether the instruction at regs->nip is a store using * an update addressing form which will update r1. @@ -112,7 +470,7 @@ * indicate errors in DSISR but can validly be set in SRR1. */ if (regs->trap == 0x400) - error_code &= 0x48200000; + error_code &= 0x58200000; else is_write = error_code & 0x02000000; #endif /* CONFIG_4xx || CONFIG_BOOKE */ @@ -177,7 +535,7 @@ && (!user_mode(regs) || !store_updates_sp(regs))) goto bad_area; } - if (expand_stack(vma, address)) + if (expand_stack(current, vma, address)) goto bad_area; good_area: @@ -245,6 +603,38 @@ /* User mode accesses cause a SIGSEGV */ if (user_mode(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (current->flags & PF_PAX_PAGEEXEC) { + if ((regs->trap == 0x400) && (regs->nip == address)) { + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + case 2: + case 3: + case 4: + return; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 5: + return; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT + case 6: + case 7: + return; +#endif + + } + + pax_report_fault(regs, (void*)regs->nip, (void*)regs->gpr[1]); + do_exit(SIGKILL); + } + } +#endif + info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = code; diff -ruN linux-2.4.29/arch/ppc64/kernel/ioctl32.c linux-2.4.29-BF6-C7_III-grsec/arch/ppc64/kernel/ioctl32.c --- linux-2.4.29/arch/ppc64/kernel/ioctl32.c 2005-01-19 07:09:36.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ppc64/kernel/ioctl32.c 2005-03-21 17:27:01.083276751 -0700 @@ -1824,7 +1824,11 @@ * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or super-user. */ +#ifdef CONFIG_GRKERNSEC + if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) +#else if (current->tty == tty || suser()) +#endif return 1; return 0; } diff -ruN linux-2.4.29/arch/ppc64/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/ppc64/mm/fault.c --- linux-2.4.29/arch/ppc64/mm/fault.c 2004-02-18 06:36:30.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/ppc64/mm/fault.c 2005-03-21 17:27:01.084276602 -0700 @@ -186,7 +186,7 @@ goto bad_area; } - if (expand_stack(vma, address)) { + if (expand_stack(current, vma, address)) { PPCDBG(PPCDBG_MM, "\tdo_page_fault: expand_stack\n"); goto bad_area; } diff -ruN linux-2.4.29/arch/s390/config.in linux-2.4.29-BF6-C7_III-grsec/arch/s390/config.in --- linux-2.4.29/arch/s390/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/s390/config.in 2005-03-21 17:27:01.084276602 -0700 @@ -87,3 +87,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/s390/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/s390/mm/fault.c --- linux-2.4.29/arch/s390/mm/fault.c 2002-11-28 16:53:11.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/s390/mm/fault.c 2005-03-21 17:27:01.085276454 -0700 @@ -210,7 +210,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(tsk, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -ruN linux-2.4.29/arch/s390x/config.in linux-2.4.29-BF6-C7_III-grsec/arch/s390x/config.in --- linux-2.4.29/arch/s390x/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/s390x/config.in 2005-03-21 17:27:01.086276305 -0700 @@ -91,3 +91,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/s390x/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/s390x/mm/fault.c --- linux-2.4.29/arch/s390x/mm/fault.c 2002-11-28 16:53:11.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/s390x/mm/fault.c 2005-03-21 17:27:01.086276305 -0700 @@ -210,7 +210,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(tsk, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -ruN linux-2.4.29/arch/sh/config.in linux-2.4.29-BF6-C7_III-grsec/arch/sh/config.in --- linux-2.4.29/arch/sh/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sh/config.in 2005-03-21 17:27:01.087276156 -0700 @@ -493,3 +493,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/sh/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/sh/mm/fault.c --- linux-2.4.29/arch/sh/mm/fault.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sh/mm/fault.c 2005-03-21 17:27:01.087276156 -0700 @@ -78,7 +78,7 @@ check_stack: if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, start) == 0) + if (expand_stack(current, vma, start) == 0) goto good_area; bad_area: @@ -123,7 +123,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(tsk, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -ruN linux-2.4.29/arch/sh64/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/sh64/mm/fault.c --- linux-2.4.29/arch/sh64/mm/fault.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sh64/mm/fault.c 2005-03-21 17:27:01.088276008 -0700 @@ -191,7 +191,7 @@ #endif goto bad_area; } - if (expand_stack(vma, address)) { + if (expand_stack(tsk, vma, address)) { #ifdef DEBUG_FAULT print_task(tsk); printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n", diff -ruN linux-2.4.29/arch/sparc/boot/Makefile linux-2.4.29-BF6-C7_III-grsec/arch/sparc/boot/Makefile --- linux-2.4.29/arch/sparc/boot/Makefile 2002-08-02 18:39:43.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc/boot/Makefile 2005-03-21 17:27:01.089275859 -0700 @@ -24,7 +24,7 @@ BTOBJS := $(HEAD) init/main.o init/version.o init/do_mounts.o BTLIBS := $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \ - $(DRIVERS) $(NETWORKS) + $(DRIVERS) $(NETWORKS) $(GRSECURITY) # I wanted to make this depend upon BTOBJS so that a parallel # build would work, but this fails because $(HEAD) cannot work diff -ruN linux-2.4.29/arch/sparc/config.in linux-2.4.29-BF6-C7_III-grsec/arch/sparc/config.in --- linux-2.4.29/arch/sparc/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc/config.in 2005-03-21 17:27:01.089275859 -0700 @@ -282,3 +282,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/sparc/kernel/ptrace.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc/kernel/ptrace.c --- linux-2.4.29/arch/sparc/kernel/ptrace.c 2002-08-02 18:39:43.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc/kernel/ptrace.c 2005-03-21 17:27:01.090275710 -0700 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -310,6 +311,9 @@ goto out; } + if(gr_handle_ptrace(child, request)) + goto out_tsk; + if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { if (ptrace_attach(child)) { diff -ruN linux-2.4.29/arch/sparc/kernel/sys_sparc.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc/kernel/sys_sparc.c --- linux-2.4.29/arch/sparc/kernel/sys_sparc.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc/kernel/sys_sparc.c 2005-03-21 17:27:01.090275710 -0700 @@ -54,6 +54,13 @@ return -ENOMEM; if (ARCH_SUN4C_SUN4 && len > 0x20000000) return -ENOMEM; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap; + else +#endif + if (!addr) addr = TASK_UNMAPPED_BASE; @@ -225,6 +232,11 @@ struct file * file = NULL; unsigned long retval = -EBADF; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) diff -ruN linux-2.4.29/arch/sparc/kernel/sys_sunos.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc/kernel/sys_sunos.c --- linux-2.4.29/arch/sparc/kernel/sys_sunos.c 2004-04-14 07:05:27.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc/kernel/sys_sunos.c 2005-03-21 17:27:01.091275561 -0700 @@ -68,6 +68,11 @@ struct file * file = NULL; unsigned long retval, ret_type; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + if(flags & MAP_NORESERVE) { static int cnt; if (cnt++ < 10) diff -ruN linux-2.4.29/arch/sparc/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc/mm/fault.c --- linux-2.4.29/arch/sparc/mm/fault.c 2004-08-07 17:26:04.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc/mm/fault.c 2005-03-21 17:27:01.093275264 -0700 @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include @@ -219,6 +222,264 @@ return safe_compute_effective_address(regs, insn); } +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +void pax_emuplt_close(struct vm_area_struct * vma) +{ + vma->vm_mm->call_dl_resolve = 0UL; +} + +static struct page* pax_emuplt_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) +{ + struct page* page; + unsigned int *kaddr; + + page = alloc_page(GFP_HIGHUSER); + if (!page) + return page; + + kaddr = kmap(page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x9DE3BFA8U; /* save */ + flush_dcache_page(page); + kunmap(page); + return page; +} + +static struct vm_operations_struct pax_vm_ops = { + close: pax_emuplt_close, + nopage: pax_emuplt_nopage, +}; + +static void pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f]; + vma->vm_ops = &pax_vm_ops; + vma->vm_pgoff = 0UL; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + vma->vm_mirror = 0; + insert_vm_struct(current->mm, vma); + ++current->mm->total_vm; +} + +/* + * PaX: decide what to do with offenders (regs->pc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + * 4 when legitimate ET_EXEC was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + int err; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) { + if (regs->pc >= current->mm->start_code && + regs->pc < current->mm->end_code) + { + if (regs->u_regs[UREG_RETPC] + 8UL == regs->pc) + return 1; + + regs->pc += current->mm->delta_exec; + if (regs->npc >= current->mm->start_code && + regs->npc < current->mm->end_code) + regs->npc += current->mm->delta_exec; + return 4; + } + if (regs->pc >= current->mm->start_code + current->mm->delta_exec && + regs->pc < current->mm->end_code + current->mm->delta_exec) + { + regs->pc -= current->mm->delta_exec; + if (regs->npc >= current->mm->start_code + current->mm->delta_exec && + regs->npc < current->mm->end_code + current->mm->delta_exec) + regs->npc -= current->mm->delta_exec; + } + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + do { /* PaX: patched PLT emulation #1 */ + unsigned int sethi1, sethi2, jmpl; + + err = get_user(sethi1, (unsigned int*)regs->pc); + err |= get_user(sethi2, (unsigned int*)(regs->pc+4)); + err |= get_user(jmpl, (unsigned int*)(regs->pc+8)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U) + { + unsigned int addr; + + regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10; + addr = regs->u_regs[UREG_G1]; + addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + { /* PaX: patched PLT emulation #2 */ + unsigned int ba; + + err = get_user(ba, (unsigned int*)regs->pc); + + if (!err && (ba & 0xFFC00000U) == 0x30800000U) { + unsigned int addr; + + addr = regs->pc + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } + + do { /* PaX: patched PLT emulation #3 */ + unsigned int sethi, jmpl, nop; + + err = get_user(sethi, (unsigned int*)regs->pc); + err |= get_user(jmpl, (unsigned int*)(regs->pc+4)); + err |= get_user(nop, (unsigned int*)(regs->pc+8)); + + if (err) + break; + if ((sethi & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U && + nop == 0x01000000U) + { + unsigned int addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 1 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int*)regs->pc); + err |= get_user(ba, (unsigned int*)(regs->pc+4)); + err |= get_user(nop, (unsigned int*)(regs->pc+8)); + + if (err) + break; + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) && + nop == 0x01000000U) + { + unsigned int addr, save, call; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->pc + 4 + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2); + else + addr = regs->pc + 4 + ((((ba | 0xFFF80000U) ^ 0x00040000U) + 0x00040000U) << 2); + + err = get_user(save, (unsigned int*)addr); + err |= get_user(call, (unsigned int*)(addr+4)); + err |= get_user(nop, (unsigned int*)(addr+8)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + struct vm_area_struct *vma; + unsigned long call_dl_resolve; + + down_read(¤t->mm->mmap_sem); + call_dl_resolve = current->mm->call_dl_resolve; + up_read(¤t->mm->mmap_sem); + if (likely(call_dl_resolve)) + goto emulate; + + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_dl_resolve) { + call_dl_resolve = current->mm->call_dl_resolve; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_dl_resolve & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + pax_insert_vma(vma, call_dl_resolve); + current->mm->call_dl_resolve = call_dl_resolve; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->pc = call_dl_resolve; + regs->npc = addr+4; + return 3; + } + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 2 */ + unsigned int save, call, nop; + + err = get_user(save, (unsigned int*)(regs->pc-4)); + err |= get_user(call, (unsigned int*)regs->pc); + err |= get_user(nop, (unsigned int*)(regs->pc+4)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + unsigned int dl_resolve = regs->pc + ((((call | 0xC0000000U) ^ 0x20000000U) + 0x20000000U) << 2); + + regs->u_regs[UREG_RETPC] = regs->pc; + regs->pc = dl_resolve; + regs->npc = dl_resolve+4; + return 3; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, unsigned long address) { @@ -270,7 +531,7 @@ goto good_area; if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if(expand_stack(vma, address)) + if(expand_stack(tsk, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so @@ -282,6 +543,29 @@ if(!(vma->vm_flags & VM_WRITE)) goto bad_area; } else { + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if ((current->flags & PF_PAX_PAGEEXEC) && text_fault && !(vma->vm_flags & VM_EXEC)) { + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + case 2: + case 3: + return; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 4: + return; +#endif + + } + pax_report_fault(regs, (void*)regs->pc, (void*)regs->u_regs[UREG_FP]); + do_exit(SIGKILL); + } +#endif + /* Allow reads even for write-only mappings */ if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; @@ -517,7 +801,7 @@ goto good_area; if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if(expand_stack(vma, address)) + if(expand_stack(tsk, vma, address)) goto bad_area; good_area: info.si_code = SEGV_ACCERR; diff -ruN linux-2.4.29/arch/sparc/mm/init.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc/mm/init.c --- linux-2.4.29/arch/sparc/mm/init.c 2002-11-28 16:53:12.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc/mm/init.c 2005-03-21 17:27:01.093275264 -0700 @@ -350,17 +350,17 @@ /* Initialize the protection map with non-constant, MMU dependent values. */ protection_map[0] = PAGE_NONE; - protection_map[1] = PAGE_READONLY; - protection_map[2] = PAGE_COPY; - protection_map[3] = PAGE_COPY; + protection_map[1] = PAGE_READONLY_NOEXEC; + protection_map[2] = PAGE_COPY_NOEXEC; + protection_map[3] = PAGE_COPY_NOEXEC; protection_map[4] = PAGE_READONLY; protection_map[5] = PAGE_READONLY; protection_map[6] = PAGE_COPY; protection_map[7] = PAGE_COPY; protection_map[8] = PAGE_NONE; - protection_map[9] = PAGE_READONLY; - protection_map[10] = PAGE_SHARED; - protection_map[11] = PAGE_SHARED; + protection_map[9] = PAGE_READONLY_NOEXEC; + protection_map[10] = PAGE_SHARED_NOEXEC; + protection_map[11] = PAGE_SHARED_NOEXEC; protection_map[12] = PAGE_READONLY; protection_map[13] = PAGE_READONLY; protection_map[14] = PAGE_SHARED; diff -ruN linux-2.4.29/arch/sparc/mm/srmmu.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc/mm/srmmu.c --- linux-2.4.29/arch/sparc/mm/srmmu.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc/mm/srmmu.c 2005-03-21 17:27:01.094275115 -0700 @@ -2047,6 +2047,13 @@ BTFIXUPSET_INT(page_shared, pgprot_val(SRMMU_PAGE_SHARED)); BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY)); BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY)); + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + BTFIXUPSET_INT(page_shared_noexec, pgprot_val(SRMMU_PAGE_SHARED_NOEXEC)); + BTFIXUPSET_INT(page_copy_noexec, pgprot_val(SRMMU_PAGE_COPY_NOEXEC)); + BTFIXUPSET_INT(page_readonly_noexec, pgprot_val(SRMMU_PAGE_RDONLY_NOEXEC)); +#endif + BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL)); page_kernel = pgprot_val(SRMMU_PAGE_KERNEL); pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF; diff -ruN linux-2.4.29/arch/sparc64/config.in linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/config.in --- linux-2.4.29/arch/sparc64/config.in 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/config.in 2005-03-21 17:27:01.095274967 -0700 @@ -320,3 +320,11 @@ source crypto/Config.in source lib/Config.in + +mainmenu_option next_comment +comment 'Grsecurity' +bool 'Grsecurity' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grsecurity/Config.in +fi +endmenu diff -ruN linux-2.4.29/arch/sparc64/kernel/ioctl32.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/ioctl32.c --- linux-2.4.29/arch/sparc64/kernel/ioctl32.c 2005-01-19 07:09:39.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/ioctl32.c 2005-03-21 17:27:01.099274372 -0700 @@ -2048,7 +2048,11 @@ * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or super-user. */ +#ifdef CONFIG_GRKERNSEC + if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) +#else if (current->tty == tty || suser()) +#endif return 1; return 0; } diff -ruN linux-2.4.29/arch/sparc64/kernel/ptrace.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/ptrace.c --- linux-2.4.29/arch/sparc64/kernel/ptrace.c 2002-11-28 16:53:12.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/ptrace.c 2005-03-21 17:27:01.100274223 -0700 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -161,6 +162,11 @@ goto out; } + if (gr_handle_ptrace(child, (long)request)) { + pt_error_return(regs, EPERM); + goto out_tsk; + } + if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { if (ptrace_attach(child)) { diff -ruN linux-2.4.29/arch/sparc64/kernel/sys_sparc.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/sys_sparc.c --- linux-2.4.29/arch/sparc64/kernel/sys_sparc.c 2003-08-25 05:44:40.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/sys_sparc.c 2005-03-21 17:27:01.100274223 -0700 @@ -63,6 +63,13 @@ task_size = 0xf0000000UL; if (len > task_size || len > -PAGE_OFFSET) return -ENOMEM; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap; + else +#endif + if (!addr) addr = TASK_UNMAPPED_BASE; @@ -289,6 +296,11 @@ struct file * file = NULL; unsigned long retval = -EBADF; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) diff -ruN linux-2.4.29/arch/sparc64/kernel/sys_sparc32.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.29/arch/sparc64/kernel/sys_sparc32.c 2005-01-19 07:09:39.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/sys_sparc32.c 2005-03-21 17:27:01.102273926 -0700 @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include #include @@ -3241,8 +3243,18 @@ struct file * file; int retval; int i; +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + +#ifdef CONFIG_GRKERNSEC_PAX_RANDUSTACK + bprm.p -= (get_random_long() & ~(sizeof(void *)-1)) & ~PAGE_MASK; +#endif + memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0])); file = open_exec(filename); @@ -3251,6 +3263,20 @@ if (IS_ERR(file)) return retval; + gr_learn_resource(current, RLIMIT_NPROC, atomic_read(¤t->user->processes), 1); + + if (gr_handle_nproc()) { + allow_write_access(file); + fput(file); + return -EAGAIN; + } + + if (!gr_acl_handle_execve(file->f_dentry, file->f_vfsmnt)) { + allow_write_access(file); + fput(file); + return -EACCES; + } + bprm.file = file; bprm.filename = filename; bprm.sh_bang = 0; @@ -3271,11 +3297,24 @@ if (retval < 0) goto out; + if(!gr_tpe_allow(file)) { + retval = -EACCES; + goto out; + } + + if (gr_check_crash_exec(file)) { + retval = -EACCES; + goto out; + } + retval = copy_strings_kernel(1, &bprm.filename, &bprm); if (retval < 0) goto out; bprm.exec = bprm.p; + + gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); + retval = copy_strings32(bprm.envc, envp, &bprm); if (retval < 0) goto out; @@ -3284,11 +3323,32 @@ if (retval < 0) goto out; +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->rlim, sizeof(old_rlim)); + old_exec_file = current->exec_file; + get_file(file); + current->exec_file = file; +#endif + + gr_set_proc_label(file->f_dentry, file->f_vfsmnt); + retval = search_binary_handler(&bprm, regs); - if (retval >= 0) + if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif /* execve success */ return retval; + } +#ifdef CONFIG_GRKERNSEC + current->acl = old_acl; + memcpy(current->rlim, old_rlim, sizeof(old_rlim)); + fput(current->exec_file); + current->exec_file = old_exec_file; +#endif out: /* Something went wrong, return the inode and free the argument pages*/ allow_write_access(bprm.file); diff -ruN linux-2.4.29/arch/sparc64/kernel/sys_sunos32.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/sys_sunos32.c --- linux-2.4.29/arch/sparc64/kernel/sys_sunos32.c 2004-08-07 17:26:04.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/kernel/sys_sunos32.c 2005-03-21 17:27:01.104273629 -0700 @@ -68,6 +68,11 @@ struct file *file = NULL; unsigned long retval, ret_type; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + if(flags & MAP_NORESERVE) { static int cnt; if (cnt++ < 10) diff -ruN linux-2.4.29/arch/sparc64/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/mm/fault.c --- linux-2.4.29/arch/sparc64/mm/fault.c 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/mm/fault.c 2005-03-21 17:27:01.105273480 -0700 @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include #include @@ -306,6 +309,387 @@ unhandled_fault (address, current, regs); } +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT +static void pax_emuplt_close(struct vm_area_struct * vma) +{ + vma->vm_mm->call_dl_resolve = 0UL; +} + +static struct page* pax_emuplt_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) +{ + struct page* page; + unsigned int *kaddr; + + page = alloc_page(GFP_HIGHUSER); + if (!page) + return page; + + kaddr = kmap(page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x9DE3BFA8U; /* save */ + flush_dcache_page(page); + kunmap(page); + return page; +} + +static struct vm_operations_struct pax_vm_ops = { + close: pax_emuplt_close, + nopage: pax_emuplt_nopage, +}; + +static void pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f]; + vma->vm_ops = &pax_vm_ops; + vma->vm_pgoff = 0UL; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + vma->vm_mirror = 0; + insert_vm_struct(current->mm, vma); + ++current->mm->total_vm; +} +#endif + +/* + * PaX: decide what to do with offenders (regs->tpc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + * 4 when legitimate ET_EXEC was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + int err; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) { + if (regs->tpc >= current->mm->start_code && + regs->tpc < current->mm->end_code) + { + if (regs->u_regs[UREG_RETPC] + 8UL == regs->tpc) + return 1; + + regs->tpc += current->mm->delta_exec; + if (regs->tnpc >= current->mm->start_code && + regs->tnpc < current->mm->end_code) + regs->tnpc += current->mm->delta_exec; + return 4; + } + if (regs->tpc >= current->mm->start_code + current->mm->delta_exec && + regs->tpc < current->mm->end_code + current->mm->delta_exec) + { + regs->tpc -= current->mm->delta_exec; + if (regs->tnpc >= current->mm->start_code + current->mm->delta_exec && + regs->tnpc < current->mm->end_code + current->mm->delta_exec) + regs->tnpc -= current->mm->delta_exec; + } + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + do { /* PaX: patched PLT emulation #1 */ + unsigned int sethi1, sethi2, jmpl; + + err = get_user(sethi1, (unsigned int*)regs->tpc); + err |= get_user(sethi2, (unsigned int*)(regs->tpc+4)); + err |= get_user(jmpl, (unsigned int*)(regs->tpc+8)); + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10; + addr = regs->u_regs[UREG_G1]; + addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + { /* PaX: patched PLT emulation #2 */ + unsigned int ba; + + err = get_user(ba, (unsigned int*)regs->tpc); + + if (!err && (ba & 0xFFC00000U) == 0x30800000U) { + unsigned long addr; + + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } + + do { /* PaX: patched PLT emulation #3 */ + unsigned int sethi, jmpl, nop; + + err = get_user(sethi, (unsigned int*)regs->tpc); + err |= get_user(jmpl, (unsigned int*)(regs->tpc+4)); + err |= get_user(nop, (unsigned int*)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U && + nop == 0x01000000U) + { + unsigned long addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #4 */ + unsigned int mov1, call, mov2; + + err = get_user(mov1, (unsigned int*)regs->tpc); + err |= get_user(call, (unsigned int*)(regs->tpc+4)); + err |= get_user(mov2, (unsigned int*)(regs->tpc+8)); + + if (err) + break; + + if (mov1 == 0x8210000FU && + (call & 0xC0000000U) == 0x40000000U && + mov2 == 0x9E100001U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = regs->u_regs[UREG_RETPC]; + addr = regs->tpc + 4 + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #5 */ + unsigned int sethi1, sethi2, or1, or2, sllx, jmpl, nop; + + err = get_user(sethi1, (unsigned int*)regs->tpc); + err |= get_user(sethi2, (unsigned int*)(regs->tpc+4)); + err |= get_user(or1, (unsigned int*)(regs->tpc+8)); + err |= get_user(or2, (unsigned int*)(regs->tpc+12)); + err |= get_user(sllx, (unsigned int*)(regs->tpc+16)); + err |= get_user(jmpl, (unsigned int*)(regs->tpc+20)); + err |= get_user(nop, (unsigned int*)(regs->tpc+24)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + (or1 & 0xFFFFE000U) == 0x82106000U && + (or2 & 0xFFFFE000U) == 0x8A116000U && + sllx == 0x83287020 && + jmpl == 0x81C04005U && + nop == 0x01000000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = ((sethi1 & 0x003FFFFFU) << 10) | (or1 & 0x000003FFU); + regs->u_regs[UREG_G1] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or2 & 0x000003FFU); + addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #6 */ + unsigned int sethi1, sethi2, sllx, or, jmpl, nop; + + err = get_user(sethi1, (unsigned int*)regs->tpc); + err |= get_user(sethi2, (unsigned int*)(regs->tpc+4)); + err |= get_user(sllx, (unsigned int*)(regs->tpc+8)); + err |= get_user(or, (unsigned int*)(regs->tpc+12)); + err |= get_user(jmpl, (unsigned int*)(regs->tpc+16)); + err |= get_user(nop, (unsigned int*)(regs->tpc+20)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + sllx == 0x83287020 && + (or & 0xFFFFE000U) == 0x8A116000U && + jmpl == 0x81C04005U && + nop == 0x01000000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = (sethi1 & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or & 0x3FFU); + addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #7 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int*)regs->tpc); + err |= get_user(ba, (unsigned int*)(regs->tpc+4)); + err |= get_user(nop, (unsigned int*)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (ba & 0xFFF00000U) == 0x30600000U && + nop == 0x01000000U) + { + unsigned long addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 1 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int*)regs->tpc); + err |= get_user(ba, (unsigned int*)(regs->tpc+4)); + err |= get_user(nop, (unsigned int*)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) && + nop == 0x01000000U) + { + unsigned long addr; + unsigned int save, call; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2); + else + addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + + err = get_user(save, (unsigned int*)addr); + err |= get_user(call, (unsigned int*)(addr+4)); + err |= get_user(nop, (unsigned int*)(addr+8)); + + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + struct vm_area_struct *vma; + unsigned long call_dl_resolve; + + down_read(¤t->mm->mmap_sem); + call_dl_resolve = current->mm->call_dl_resolve; + up_read(¤t->mm->mmap_sem); + if (likely(call_dl_resolve)) + goto emulate; + + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_dl_resolve) { + call_dl_resolve = current->mm->call_dl_resolve; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_dl_resolve & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + pax_insert_vma(vma, call_dl_resolve); + current->mm->call_dl_resolve = call_dl_resolve; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->tpc = call_dl_resolve; + regs->tnpc = addr+4; + return 3; + } + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 2 */ + unsigned int save, call, nop; + + err = get_user(save, (unsigned int*)(regs->tpc-4)); + err |= get_user(call, (unsigned int*)regs->tpc); + err |= get_user(nop, (unsigned int*)(regs->tpc+4)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + unsigned long dl_resolve = regs->tpc + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2); + + regs->u_regs[UREG_RETPC] = regs->tpc; + regs->tpc = dl_resolve; + regs->tnpc = dl_resolve+4; + return 3; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + asmlinkage void do_sparc64_fault(struct pt_regs *regs) { struct mm_struct *mm = current->mm; @@ -345,6 +729,7 @@ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; address &= 0xffffffff; } @@ -353,6 +738,34 @@ if (!vma) goto bad_area; +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + /* PaX: detect ITLB misses on non-exec pages */ + if ((current->flags & PF_PAX_PAGEEXEC) && vma->vm_start <= address && + !(vma->vm_flags & VM_EXEC) && (fault_code & FAULT_CODE_ITLB)) + { + if (address != regs->tpc) + goto good_area; + + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT + case 2: + case 3: + goto fault_done; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 4: + goto fault_done; +#endif + + } + pax_report_fault(regs, (void*)regs->tpc, (void*)(regs->u_regs[UREG_FP] + STACK_BIAS)); + do_exit(SIGKILL); + } +#endif + /* Pure DTLB misses do not tell us whether the fault causing * load/store/atomic was a write or not, it only says that there * was no match. So in such a case we (carefully) read the @@ -396,7 +809,7 @@ goto bad_area; } } - if (expand_stack(vma, address)) + if (expand_stack(current, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -ruN linux-2.4.29/arch/sparc64/solaris/misc.c linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/solaris/misc.c --- linux-2.4.29/arch/sparc64/solaris/misc.c 2002-11-28 16:53:12.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/sparc64/solaris/misc.c 2005-03-21 17:27:01.106273331 -0700 @@ -53,6 +53,11 @@ struct file *file = NULL; unsigned long retval, ret_type; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + /* Do we need it here? */ set_personality(PER_SVR4); if (flags & MAP_NORESERVE) { diff -ruN linux-2.4.29/arch/x86_64/ia32/ia32_binfmt.c linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/ia32/ia32_binfmt.c --- linux-2.4.29/arch/x86_64/ia32/ia32_binfmt.c 2005-01-19 07:09:39.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/ia32/ia32_binfmt.c 2005-03-21 17:27:01.107273183 -0700 @@ -28,7 +28,14 @@ #define ELF_NAME "elf/i386" -#define IA32_STACK_TOP IA32_PAGE_OFFSET +#ifdef CONFIG_GRKERNSEC_PAX_RANDUSTACK +#define __IA32_DELTA_STACK (current->mm->delta_stack) +#else +#define __IA32_DELTA_STACK 0UL +#endif + +#define IA32_STACK_TOP (IA32_PAGE_OFFSET - __IA32_DELTA_STACK) + #define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000) #undef ELF_ARCH @@ -129,6 +136,17 @@ #include #include +#ifdef CONFIG_GRKERNSEC_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE(tsk) ((tsk)->thread.flags & THREAD_IA32 ? 0x08048000UL : 0x400000UL) + +#define PAX_DELTA_MMAP_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_MMAP_LEN(tsk) ((tsk)->thread.flags & THREAD_IA32 ? 16 : 24) +#define PAX_DELTA_EXEC_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_EXEC_LEN(tsk) ((tsk)->thread.flags & THREAD_IA32 ? 16 : 24) +#define PAX_DELTA_STACK_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_STACK_LEN(tsk) ((tsk)->thread.flags & THREAD_IA32 ? 16 : 24) +#endif + typedef struct user_i387_ia32_struct elf_fpregset_t; typedef struct user32_fxsr_struct elf_fpxregset_t; @@ -243,7 +261,13 @@ mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = IA32_STACK_TOP; - mpnt->vm_flags = vm_stack_flags32; + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + mpnt->vm_flags = VM_STACK_FLAGS; +#else + mpnt->vm_flags = vm_stack_flags32; +#endif + mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? PAGE_COPY_EXEC : PAGE_COPY; mpnt->vm_ops = NULL; diff -ruN linux-2.4.29/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/ia32/ia32_ioctl.c --- linux-2.4.29/arch/x86_64/ia32/ia32_ioctl.c 2005-01-19 07:09:39.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/ia32/ia32_ioctl.c 2005-03-21 17:27:01.110272737 -0700 @@ -1952,7 +1952,11 @@ * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or super-user. */ +#ifdef CONFIG_GRKERNSEC + if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) +#else if (current->tty == tty || suser()) +#endif return 1; return 0; } diff -ruN linux-2.4.29/arch/x86_64/ia32/sys_ia32.c linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/ia32/sys_ia32.c --- linux-2.4.29/arch/x86_64/ia32/sys_ia32.c 2005-01-19 07:09:39.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/ia32/sys_ia32.c 2005-03-21 17:27:01.111272588 -0700 @@ -327,6 +327,11 @@ if (a.offset & ~PAGE_MASK) return -EINVAL; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (a.flags & MAP_MIRROR) + return -EINVAL; +#endif + if (!(a.flags & MAP_ANONYMOUS)) { file = fget(a.fd); if (!file) @@ -2114,6 +2119,11 @@ unsigned long error; struct file * file = NULL; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + return -EINVAL; +#endif + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); diff -ruN linux-2.4.29/arch/x86_64/kernel/ptrace.c linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/kernel/ptrace.c --- linux-2.4.29/arch/x86_64/kernel/ptrace.c 2003-06-13 08:51:32.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/kernel/ptrace.c 2005-03-21 17:27:01.112272439 -0700 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -201,6 +202,9 @@ if (pid == 1) /* you may not mess with init */ goto out_tsk; + if (gr_handle_ptrace(child, request)) + goto out_tsk; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; diff -ruN linux-2.4.29/arch/x86_64/kernel/setup64.c linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/kernel/setup64.c --- linux-2.4.29/arch/x86_64/kernel/setup64.c 2004-04-14 07:05:28.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/kernel/setup64.c 2005-03-21 17:27:01.113272291 -0700 @@ -36,8 +36,15 @@ correct flags everywhere. */ unsigned long __supported_pte_mask = ~0UL; static int do_not_nx __initdata = 0; -unsigned long vm_stack_flags = __VM_STACK_FLAGS; -unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +unsigned long vm_stack_flags = VM_GROWSDOWN | __VM_DATA_DEFAULT_FLAGS; +unsigned long vm_stack_flags32 = VM_GROWSDOWN | __VM_DATA_DEFAULT_FLAGS; +#else +unsigned long vm_stack_flags = __VM_STACK_FLAGS; +unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; +#endif + unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; unsigned long vm_force_exec32 = PROT_EXEC; diff -ruN linux-2.4.29/arch/x86_64/kernel/sys_x86_64.c linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/kernel/sys_x86_64.c --- linux-2.4.29/arch/x86_64/kernel/sys_x86_64.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/kernel/sys_x86_64.c 2005-03-21 17:27:01.113272291 -0700 @@ -46,6 +46,11 @@ if (off & ~PAGE_MASK) goto out; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (flags & MAP_MIRROR) + goto out; +#endif + error = -EBADF; file = NULL; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); @@ -54,7 +59,6 @@ if (!file) goto out; } - down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT); up_write(¤t->mm->mmap_sem); @@ -72,6 +76,13 @@ unsigned long end = TASK_SIZE; if (current->thread.flags & THREAD_IA32) { + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = TASK_UNMAPPED_32 + current->mm->delta_mmap; + else +#endif + if (!addr) addr = TASK_UNMAPPED_32; end = 0xffff0000; @@ -82,10 +93,24 @@ base down for this case. This may give conflicts with the heap, but we assume that malloc falls back to mmap. Give it 1GB of playground for now. -AK */ + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = 0x40000000 + (current->mm->delta_mmap & 0x0FFFFFFFU); + else +#endif + if (!addr) addr = 0x40000000; end = 0x80000000; } else { + +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp)) + addr = TASK_UNMAPPED_64 + current->mm->delta_mmap; + else +#endif + if (!addr) addr = TASK_UNMAPPED_64; end = TASK_SIZE; diff -ruN linux-2.4.29/arch/x86_64/mm/fault.c linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/mm/fault.c --- linux-2.4.29/arch/x86_64/mm/fault.c 2004-04-14 07:05:28.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/arch/x86_64/mm/fault.c 2005-03-21 17:27:01.114272142 -0700 @@ -173,6 +173,62 @@ return prefetch; } +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->rip = fault address) + * + * returns 1 when task should be killed + * 2 when legitimate ET_EXEC was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + int err; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) { + if (regs->rip >= current->mm->start_code && + regs->rip < current->mm->end_code) + { + if (current->thread.flags & THREAD_IA32) { + unsigned int esp_4; + + err = get_user(esp_4, (unsigned int*)(regs->rsp-4UL)); + if (err || esp_4 == regs->rip) + return 1; + } else { + unsigned long esp_8; + + err = get_user(esp_8, (unsigned long*)(regs->rsp-8UL)); + if (err || esp_8 == regs->rip) + return 1; + } + + regs->rip += current->mm->delta_exec; + return 2; + } + } +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned int c; + if (get_user(c, (unsigned char*)pc+i)) { + printk("."); + break; + } + printk("%08x ", c); + } + printk("\n"); +} +#endif + int page_fault_trace; int exception_trace = 1; @@ -260,13 +316,30 @@ if (address + 128 < regs->rsp) goto bad_area; } - if (expand_stack(vma, address)) + if (expand_stack(tsk, vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so * we can handle it.. */ good_area: + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if ((current->flags & PF_PAX_PAGEEXEC) && (error_code & 16) && !(vma->vm_flags & VM_EXEC)) { + up_read(&mm->mmap_sem); + switch(pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + case 2: + return; +#endif + + } + pax_report_fault(regs, (void*)regs->rip, (void*)regs->rsp); + do_exit(SIGKILL); + } +#endif + info.si_code = SEGV_ACCERR; write = 0; switch (error_code & 3) { diff -ruN linux-2.4.29/drivers/Makefile linux-2.4.29-BF6-C7_III-grsec/drivers/Makefile --- linux-2.4.29/drivers/Makefile 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/Makefile 2005-03-21 17:27:16.639963454 -0700 @@ -49,4 +49,6 @@ subdir-$(CONFIG_BLUEZ) += bluetooth +subdir-$(CONFIG_COBALT) += cobalt + include $(TOPDIR)/Rules.make diff -ruN linux-2.4.29/drivers/char/Makefile linux-2.4.29-BF6-C7_III-grsec/drivers/char/Makefile --- linux-2.4.29/drivers/char/Makefile 2004-08-07 17:26:04.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/char/Makefile 2005-03-21 17:27:16.639963454 -0700 @@ -271,7 +271,7 @@ obj-$(CONFIG_AU1X00_GPIO) += au1000_gpio.o obj-$(CONFIG_AU1X00_USB_TTY) += au1000_usbtty.o obj-$(CONFIG_AU1X00_USB_RAW) += au1000_usbraw.o -obj-$(CONFIG_COBALT_LCD) += lcd.o +obj-$(CONFIG_COBALT_MIPS_LCD) += lcd.o obj-$(CONFIG_QIC02_TAPE) += tpqic02.o diff -ruN linux-2.4.29/drivers/char/keyboard.c linux-2.4.29-BF6-C7_III-grsec/drivers/char/keyboard.c --- linux-2.4.29/drivers/char/keyboard.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/char/keyboard.c 2005-03-21 17:27:01.115271993 -0700 @@ -545,6 +545,16 @@ if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) && !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) return; + +#if defined(CONFIG_GRKERNSEC_PROC) || defined(CONFIG_GRKERNSEC_PROC_MEMMAP) + { + void *func = spec_fn_table[value]; + if (func == show_state || func == show_ptregs || + func == show_mem) + return; + } +#endif + spec_fn_table[value](); } diff -ruN linux-2.4.29/drivers/char/mem.c linux-2.4.29-BF6-C7_III-grsec/drivers/char/mem.c --- linux-2.4.29/drivers/char/mem.c 2004-08-07 17:26:04.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/char/mem.c 2005-03-21 17:27:01.116271845 -0700 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,10 @@ #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) extern void tapechar_init(void); #endif + +#ifdef CONFIG_GRKERNSEC +extern struct file_operations grsec_fops; +#endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) @@ -115,6 +120,11 @@ unsigned long p = *ppos; unsigned long end_mem; +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_mem_write(); + return -EPERM; +#endif + end_mem = __pa(high_memory); if (p >= end_mem) return 0; @@ -187,6 +197,12 @@ { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; +#ifdef CONFIG_GRKERNSEC_KMEM + if (gr_handle_mem_mmap(offset, vma)) + return -EPERM; +#endif + + /* * Accessing memory above the top the kernel knows about or * through a file pointer that was marked O_SYNC will be @@ -286,6 +302,11 @@ ssize_t virtr = 0; char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_kmem_write(); + return -EPERM; +#endif + if (p < (unsigned long) high_memory) { wrote = count; if (count > (unsigned long) high_memory - p) @@ -402,7 +423,23 @@ count = size; zap_page_range(mm, addr, count); - zeromap_page_range(addr, count, PAGE_COPY); + zeromap_page_range(addr, count, vma->vm_page_prot); + +#if defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) || defined(CONFIG_GRKERNSEC_PAX_RANDEXEC) + if (vma->vm_flags & VM_MIRROR) { + unsigned long addr_m; + struct vm_area_struct * vma_m; + + addr_m = vma->vm_start + vma->vm_mirror; + vma_m = find_vma(mm, addr_m); + if (vma_m && vma_m->vm_start == addr_m && (vma_m->vm_flags & VM_MIRROR)) { + addr_m = addr + vma->vm_mirror; + zap_page_range(mm, addr_m, count); + } else + printk(KERN_ERR "PAX: VMMIRROR: read_zero bug, %08lx, %08lx\n", + addr, vma->vm_start); + } +#endif size -= count; buf += count; @@ -525,6 +562,15 @@ static int open_port(struct inode * inode, struct file * filp) { +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_open_port(); + return -EPERM; +#endif + return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; +} + +static int open_mem(struct inode * inode, struct file * filp) +{ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; } @@ -582,6 +628,11 @@ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long size = vma->vm_end - vma->vm_start; +#ifdef CONFIG_GRKERNSEC_KMEM + if (gr_handle_mem_mmap(offset, vma)) + return -EPERM; +#endif + /* * If the user is not attempting to mmap a high memory address then * the standard mmap_mem mechanism will work. High memory addresses @@ -617,7 +668,6 @@ #define full_lseek null_lseek #define write_zero write_null #define read_full read_zero -#define open_mem open_port #define open_kmem open_mem static struct file_operations mem_fops = { @@ -693,6 +743,11 @@ case 9: filp->f_op = &urandom_fops; break; +#ifdef CONFIG_GRKERNSEC + case 12: + filp->f_op = &grsec_fops; + break; +#endif default: return -ENXIO; } @@ -719,7 +774,10 @@ {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, {7, "full", S_IRUGO | S_IWUGO, &full_fops}, {8, "random", S_IRUGO | S_IWUSR, &random_fops}, - {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops} + {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, +#ifdef CONFIG_GRKERNSEC + {12,"grsec", S_IRUSR | S_IWUGO, &grsec_fops} +#endif }; int i; diff -ruN linux-2.4.29/drivers/char/misc.c linux-2.4.29-BF6-C7_III-grsec/drivers/char/misc.c --- linux-2.4.29/drivers/char/misc.c 2004-02-18 06:36:31.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/char/misc.c 2005-03-21 17:27:16.640963305 -0700 @@ -266,7 +266,7 @@ #ifdef CONFIG_TOSHIBA tosh_init(); #endif -#ifdef CONFIG_COBALT_LCD +#ifdef CONFIG_COBALT_MIPS_LCD lcd_init(); #endif #ifdef CONFIG_I8K diff -ruN linux-2.4.29/drivers/char/random.c linux-2.4.29-BF6-C7_III-grsec/drivers/char/random.c --- linux-2.4.29/drivers/char/random.c 2005-01-19 07:09:48.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/char/random.c 2005-03-21 17:27:01.117271696 -0700 @@ -262,9 +262,15 @@ /* * Configuration information */ +#ifdef CONFIG_GRKERNSEC_RANDNET +#define DEFAULT_POOL_SIZE 1024 +#define SECONDARY_POOL_SIZE 256 +#define BATCH_ENTROPY_SIZE 512 +#else #define DEFAULT_POOL_SIZE 512 #define SECONDARY_POOL_SIZE 128 #define BATCH_ENTROPY_SIZE 256 +#endif #define USE_SHA /* @@ -389,6 +395,7 @@ /* * Static global variables */ + static struct entropy_store *random_state; /* The default global store */ static struct entropy_store *sec_random_state; /* secondary store */ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); @@ -2215,6 +2222,29 @@ return halfMD4Transform(hash, keyptr->secret); } +#ifdef CONFIG_GRKERNSEC +/* the following function is provided by PaX under the GPL */ +unsigned long get_random_long(void) +{ + static time_t rekey_time; + static __u32 secret[12]; + time_t t; + + /* + * Pick a random secret every REKEY_INTERVAL seconds + */ + t = CURRENT_TIME; + if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) { + rekey_time = t; + get_random_bytes(secret, sizeof(secret)); + } + + secret[1] = halfMD4Transform(secret+8, secret); + secret[0] = halfMD4Transform(secret+8, secret); + return *(unsigned long *)secret; +} +#endif + #ifdef CONFIG_SYN_COOKIES /* * Secure SYN cookie computation. This is the algorithm worked out by diff -ruN linux-2.4.29/drivers/char/tty_io.c linux-2.4.29-BF6-C7_III-grsec/drivers/char/tty_io.c --- linux-2.4.29/drivers/char/tty_io.c 2005-01-19 07:09:53.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/char/tty_io.c 2005-03-21 17:27:01.119271398 -0700 @@ -1775,7 +1775,11 @@ retval = -ENODEV; filp->f_flags = saved_flags; +#ifdef CONFIG_GRKERNSEC + if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_TTY_CONFIG)) +#else if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser()) +#endif retval = -EBUSY; if (retval) { @@ -1882,7 +1886,11 @@ char ch, mbz = 0; struct tty_ldisc *ld; +#ifdef CONFIG_GRKERNSEC + if ((current->tty != tty) && !capable(CAP_SYS_TTY_CONFIG)) +#else if ((current->tty != tty) && !suser()) +#endif return -EPERM; if (get_user(ch, arg)) return -EFAULT; @@ -1922,7 +1930,11 @@ if (inode->i_rdev == SYSCONS_DEV || inode->i_rdev == CONSOLE_DEV) { struct file *f; +#ifdef CONFIG_GRKERNSEC + if (!capable(CAP_SYS_TTY_CONFIG)) +#else if (!suser()) +#endif return -EPERM; spin_lock(&redirect_lock); f = redirect; @@ -1974,7 +1986,11 @@ * This tty is already the controlling * tty for another session group! */ +#ifdef CONFIG_GRKERNSEC + if ((arg == 1) && capable(CAP_SYS_ADMIN)) { +#else if ((arg == 1) && suser()) { +#endif /* * Steal it away */ diff -ruN linux-2.4.29/drivers/char/vt.c linux-2.4.29-BF6-C7_III-grsec/drivers/char/vt.c --- linux-2.4.29/drivers/char/vt.c 2005-01-19 07:09:53.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/char/vt.c 2005-03-21 17:27:01.120271250 -0700 @@ -179,6 +179,11 @@ case KDSKBENT: if (!perm) return -EPERM; +#ifdef CONFIG_GRKERNSEC + if (!capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; +#endif + if (!i && v == K_NOSUCHMAP) { /* disallocate map */ key_map = key_maps[s]; @@ -301,6 +306,11 @@ if (!perm) return -EPERM; +#ifdef CONFIG_GRKERNSEC + if (!capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; +#endif + q = func_table[i]; first_free = funcbufptr + (funcbufsize - funcbufleft); for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) @@ -443,7 +453,11 @@ * to be the owner of the tty, or super-user. */ perm = 0; +#ifdef CONFIG_GRKERNSEC + if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) +#else if (current->tty == tty || suser()) +#endif perm = 1; kbd = kbd_table + console; @@ -1037,12 +1051,20 @@ return do_unimap_ioctl(cmd, (struct unimapdesc *)arg, perm); case VT_LOCKSWITCH: +#ifdef CONFIG_GRKERNSEC + if (!capable(CAP_SYS_TTY_CONFIG)) +#else if (!suser()) +#endif return -EPERM; vt_dont_switch = 1; return 0; case VT_UNLOCKSWITCH: +#ifdef CONFIG_GRKERNSEC + if (!capable(CAP_SYS_TTY_CONFIG)) +#else if (!suser()) +#endif return -EPERM; vt_dont_switch = 0; return 0; diff -ruN linux-2.4.29/drivers/cobalt/Config.in linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/Config.in --- linux-2.4.29/drivers/cobalt/Config.in 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/Config.in 2005-03-21 17:27:16.640963305 -0700 @@ -0,0 +1,42 @@ +# +# Cobalt Networks hardware support +# +mainmenu_option next_comment +comment 'Sun and Cobalt Networks support' +bool 'Support for Sun and Cobalt Networks x86 systems' CONFIG_COBALT + +if [ "$CONFIG_COBALT" != "n" ]; then + bool ' Cobalt RaQ/Qube hardware' CONFIG_COBALT_RAQ + if [ "$CONFIG_COBALT_RAQ" != "n" ]; then + bool ' Gen III (3000 series) system support' CONFIG_COBALT_GEN_III + bool ' Gen V (5000 series) system support' CONFIG_COBALT_GEN_V + bool ' Create legacy /proc files' CONFIG_COBALT_OLDPROC + bool ' Cobalt Bootloader Support' CONFIG_COBALT_BOOTLOADER + + comment 'Cobalt hardware options' + + bool ' Front panel (LCD) support' CONFIG_COBALT_LCD + if [ "$CONFIG_COBALT_LCD" != "n" ]; then + bool ' Use compatible device number' CONFIG_COBALT_LCD_DEV_COMPAT + bool ' Twiddle LCD on boot' CONFIG_COBALT_LCD_TWIDDLE + fi + bool ' Software controlled LED support' CONFIG_COBALT_LED + tristate ' Serial number support' CONFIG_COBALT_SERNUM + if [ "$CONFIG_KDB" != "y" ]; then + bool ' Watchdog timer support' CONFIG_COBALT_WDT + fi + bool ' System sensors support' CONFIG_COBALT_SENSORS + tristate ' Fan tachometer support' CONFIG_COBALT_FANS + tristate ' Memory information support' CONFIG_COBALT_RAMINFO + bool ' Disk drive ruler support' CONFIG_COBALT_RULER + if [ "$CONFIG_COBALT_GEN_V" != "n" ]; then + bool ' Cobalt ACPI support' CONFIG_COBALT_ACPI + else + define_bool CONFIG_COBALT_ACPI n + fi + if [ "$CONFIG_COBALT_ACPI" != "n" ]; then + bool ' /proc/acpi emulation' CONFIG_COBALT_EMU_ACPI + fi + fi +fi +endmenu diff -ruN linux-2.4.29/drivers/cobalt/Makefile linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/Makefile --- linux-2.4.29/drivers/cobalt/Makefile 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/Makefile 2005-03-21 17:27:16.641963156 -0700 @@ -0,0 +1,20 @@ +# +# Makefile for the Sun/Cobalt device drivers +# + +O_TARGET := cobalt.o + +export-objs := init.o systype.o wdt.o i2c.o + +obj-$(CONFIG_COBALT) += init.o systype.o +obj-$(CONFIG_COBALT_RAQ) += i2c.o wdt.o +obj-$(CONFIG_COBALT_ACPI) += acpi.o +obj-$(CONFIG_COBALT_SERNUM) += serialnum.o +obj-$(CONFIG_COBALT_LCD) += lcd.o +obj-$(CONFIG_COBALT_LED) += net.o led.o +obj-$(CONFIG_COBALT_SENSORS) += sensors.o +obj-$(CONFIG_COBALT_FANS) += fans.o +obj-$(CONFIG_COBALT_RAMINFO) += raminfo.o +obj-$(CONFIG_COBALT_RULER) += ruler.o + +include $(TOPDIR)/Rules.make diff -ruN linux-2.4.29/drivers/cobalt/README linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/README --- linux-2.4.29/drivers/cobalt/README 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/README 2005-03-21 17:27:16.641963156 -0700 @@ -0,0 +1,19 @@ +Notes on Cobalt's drivers: + +You will notice in several places constructs such as this: + + if (cobt_is_3k()) { + foo(); + } else if (cobt_is_5k()) { + bar(); + } + +The goal here is to only compile in code that is needed, but to allow one to +define support for both 3k and 5k (and more?) style systems. The systype +check macros are very simple and clean. They check whether config-time +support for the generation has been enabled, and (if so) whether the current +systype matches the spcified generation. This leaves the code free from +#ifdef cruft, but lets the compiler throw out unsupported generation-specific +code with if (0) detection. + +-- diff -ruN linux-2.4.29/drivers/cobalt/acpi.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/acpi.c --- linux-2.4.29/drivers/cobalt/acpi.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/acpi.c 2005-03-21 17:27:16.644962710 -0700 @@ -0,0 +1,1988 @@ + /* + * cobalt acpi driver + * Copyright (c) 2000, Cobalt Networks, Inc. + * Copyright (c) 2001, Sun Microsystems, Inc. + * $Id: acpi.c,v 1.32 2002/06/26 19:08:54 duncan Exp $ + * + * author: asun@cobalt.com, thockin@sun.com + * + * this driver just sets stuff up for ACPI interrupts + * + * if acpi support really existed in the kernel, we would read + * data from the ACPI tables. however, it doesn't. as a result, + * we use some hardcoded values. + * + * This should be SMP safe. The only data that needs protection is the acpi + * handler list. It gets scanned at timer-interrupts, must use + * irqsave/restore locks. Read/write locks would be useful if there were any + * other times that the list was read but never written. --TPH + * + * /proc/acpi emulation emulates the /proc/acpi/events interface supplied by + * the INTEL acpi drivers. A lot of the code to handle it has been adapted + * from there. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define POWER_BUTTON_SHUTDOWN 0 + +#define ACPI_IRQ 10 /* XXX: hardcoded interrupt */ +#define ACPI_NAME "sci" +#define ACPI_MAGIC 0xc0b7ac21 + +#define SUPERIO_EVENT 0xff +#define OSB4_EVENT 0x40 +#define OSB4_INDEX_PORT SERVERWORKS_ACPI_INDEX_PORT +#define OSB4_DATA_PORT SERVERWORKS_ACPI_DATA_PORT + +#define GEN_ACPI_TMR_STS (0x1 << 0) +#define GEN_ACPI_BM_STS (0x1 << 4) +#define GEN_ACPI_GBL_STS (0x1 << 5) +#define GEN_ACPI_PWRBTN_STS (0x1 << 8) +#define GEN_ACPI_SLPBTN_STS (0x1 << 9) +#define GEN_ACPI_RTC_STS (0x1 << 10) +#define GEN_ACPI_WAK_STS (0x1 << 15) + +#ifdef CONFIG_COBALT_EMU_ACPI +static int cobalt_acpi_setup_proc(void); +static int cobalt_acpi_open_event(struct inode *inode, struct file *file); +static int cobalt_acpi_close_event(struct inode *inode, struct file *file); +static ssize_t cobalt_acpi_read_event(struct file *file, char *buf, + size_t count, loff_t *ppos); +static unsigned int cobalt_acpi_poll_event(struct file *file, poll_table *wait); +#endif + + + +typedef struct +{ + u16 hw_type; + cobalt_acpi_hw_handler hw_handler; + cobalt_acpi_enable_handler en_handler; + void *data; + struct list_head link; +} hw_handler_datum; + +typedef struct +{ + u16 hw_type; + u16 table_len; + u16 *table; + struct list_head link; +} trans_table_datum; + +typedef struct +{ + cobalt_acpi_evt_handler handler; + u16 ev_type; + void *data; + struct list_head link; +} evt_handler_datum; + +typedef struct +{ + cobalt_acpi_evt evt; + struct list_head link; +} evt_list_datum; + +static LIST_HEAD( hw_handler_list ); +static spinlock_t hw_handler_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD( trans_table_list ); +static spinlock_t trans_table_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD( evt_handler_list ); +static spinlock_t evt_handler_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD( dispatch_queue ); +static spinlock_t dispatch_queue_lock = SPIN_LOCK_UNLOCKED; + +typedef struct +{ + u16 hw_type; + + /* block lengths */ + u16 pm1_evt_len; + u16 pm1_cnt_len; + u16 pm2_cnt_len; + u16 pm_tmr_len; + u16 gpe0_len; + u16 gpe1_len; + + /* block I/O locations */ + u16 pm1a_evt_blk; + u16 pm1b_evt_blk; + u16 pm1a_cnt_blk; + u16 pm1b_cnt_blk; + u16 pm2_cnt_blk; + u16 pm_tmr_blk; + u16 p_blk; + u16 gpe0_blk; + u16 gpe1_blk; + + /* ponters to strings for the io names */ + char *pm1a_evt_nam; + char *pm1b_evt_nam; + char *pm1a_cnt_nam; + char *pm1b_cnt_nam; + char *pm2_cnt_nam; + char *pm_tmr_nam; + char *p_nam; + char *gpe0_nam; + char *gpe1_nam; + + /* reference counts for events */ + atomic_t tmr_ref_cnt; + atomic_t bm_ref_cnt; + atomic_t gbl_ref_cnt; + atomic_t pwrbtn_ref_cnt; + atomic_t slpbtn_ref_cnt; + atomic_t rtc_ref_cnt; + atomic_t wak_ref_cnt; + atomic_t *gpe_ref_cnt; + + +} generic_acpi_regions; + + +static void cobalt_acpi_enable_event( u16 ev_type, int en ); +static void cobalt_acpi_run_enable_handler( u16 hw_type, u16 ev_type, + u16 ev_data, int en); +static int cobalt_acpi_apply_evt_handlers( evt_list_datum *d ); +static int cobalt_acpi_run_dispatch_queue( void ); +static void acpi_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void cobalt_acpi_cleanup( void ); + +static int register_acpi_regions( generic_acpi_regions *regions, char * subsys_name ); +static int unregister_acpi_regions( generic_acpi_regions *regions ); +static void cobalt_acpi_handle_pm1_blk( u16 io_addr, u16 len, + generic_acpi_regions * regions ); +static void cobalt_acpi_handle_gpe_blk( u16 io_addr, u16 len, + generic_acpi_regions * regions ); +static int cobalt_acpi_generic_hw_handler( int irq, void *dev_id, + struct pt_regs *regs, void * data ); + +static int cobalt_acpi_osb4_init( void ); +static int cobalt_acpi_osb4_cleanup( void ); +static int get_osb4_regions( generic_acpi_regions *regions); + +static int cobalt_acpi_csb5_init( void ); +static int cobalt_acpi_csb5_cleanup( void ); +static int get_csb5_regions( generic_acpi_regions *regions); + +static int cobalt_acpi_pc8731x_init( void ); +static int cobalt_acpi_pc8731x_cleanup( void ); +static int get_pc8731x_regions( generic_acpi_regions *regions ); + +static int cobalt_acpi_pc8741x_init( void ); +static int cobalt_acpi_pc8741x_cleanup( void ); +static int get_pc8741x_regions( generic_acpi_regions *regions ); + +static int cobalt_acpi_monterey_init( void ); +static int cobalt_acpi_monterey_cleanup( void ); + +static int cobalt_acpi_alpine_init( void ); +static int cobalt_acpi_alpine_cleanup( void ); + +static __inline__ struct list_head *list_pop( struct list_head *head ) +{ + struct list_head *e; + + if( list_empty( head ) ) + return NULL; + + e = head->next; + list_del( e ); + return e; +} + +static __inline__ u16 get_reg(u16 index, u16 data, u8 port) +{ + u16 reg; + + outb(port, index); + reg = inb(data); + outb(port + 1, index); + reg |= inb(data) << 8; + return reg; +} + +/* + * + * Main ACPI Subsystem Code + * + */ + +extern int cobalt_acpi_register_hw_handler( u16 hw_type, + cobalt_acpi_hw_handler hw_handler, + cobalt_acpi_enable_handler en_handler, + void *data ) +{ + hw_handler_datum *d; + unsigned long flags; + + if( ! (d = (hw_handler_datum *) kmalloc( sizeof( hw_handler_datum ), GFP_ATOMIC )) ) + return -ENOMEM; + + d->hw_type = hw_type; + d->hw_handler = hw_handler; + d->en_handler = en_handler; + d->data = data; + + spin_lock_irqsave( &hw_handler_list_lock, flags ); + list_add( &(d->link), &hw_handler_list ); + spin_unlock_irqrestore( &hw_handler_list_lock, flags ); + + return 0; +} + +extern int cobalt_acpi_unregister_hw_handler( cobalt_acpi_hw_handler handler ) +{ + struct list_head *pos; + unsigned long flags; + + spin_lock_irqsave( &hw_handler_list_lock, flags ); + list_for_each( pos, &hw_handler_list ) + { + if( list_entry( pos, hw_handler_datum, link )->hw_handler == handler ) + { + list_del( pos ); + spin_unlock_irqrestore( &hw_handler_list_lock, flags ); + + kfree( list_entry( pos, hw_handler_datum, link ) ); + return 0; + } + + }; + + spin_unlock_irqrestore( &hw_handler_list_lock, flags ); + return -1; +} + +extern int cobalt_acpi_register_trans_table( u16 hw_type, u16 table_len, u16 *table ) +{ + trans_table_datum *d; + unsigned long flags; + + if( ! (d = (trans_table_datum *) kmalloc( sizeof( trans_table_datum ), GFP_ATOMIC )) ) + return -ENOMEM; + + d->hw_type = hw_type; + d->table_len = table_len; + d->table = table; + + spin_lock_irqsave( &trans_table_list_lock, flags ); + list_add( &(d->link), &trans_table_list ); + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + + return 0; +} + +extern int cobalt_acpi_unregister_trans_table( u16 hw_type ) +{ + struct list_head *pos; + unsigned long flags; + + spin_lock_irqsave( &trans_table_list_lock, flags ); + list_for_each( pos, &trans_table_list ) + { + if( list_entry( pos, trans_table_datum, link )->hw_type == hw_type ) + { + list_del( pos ); + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + + kfree( list_entry( pos, trans_table_datum, link ) ); + return 0; + } + + }; + + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + return -1; +} + +extern int cobalt_acpi_register_evt_handler( cobalt_acpi_evt_handler handler, + u16 ev_type, + void *data ) +{ + evt_handler_datum *d; + unsigned long flags; + + if( ! (d = (evt_handler_datum *) kmalloc( sizeof( evt_handler_datum ), GFP_ATOMIC )) ) + return -ENOMEM; + + d->handler = handler; + d->data = data; + d->ev_type = ev_type; + + spin_lock_irqsave( &evt_handler_list_lock, flags ); + list_add( &(d->link), &evt_handler_list ); + spin_unlock_irqrestore( &evt_handler_list_lock, flags ); + + cobalt_acpi_enable_event( ev_type, 1 ); + + return 0; +} + +extern int cobalt_acpi_unregister_evt_handler( cobalt_acpi_evt_handler handler ) +{ + struct list_head *pos; + unsigned long flags; + + + spin_lock_irqsave( &evt_handler_list_lock, flags ); + list_for_each( pos, &evt_handler_list ) + { + if( list_entry( pos, evt_handler_datum, link )->handler == handler ) + { + list_del( pos ); + spin_unlock_irqrestore( &evt_handler_list_lock, flags ); + + cobalt_acpi_enable_event( list_entry( pos, + evt_handler_datum, + link )->ev_type, 0 ); + + kfree( list_entry( pos, evt_handler_datum, link ) ); + return 0; + } + + }; + + spin_unlock_irqrestore( &evt_handler_list_lock, flags ); + return -EINVAL; +} + +static void cobalt_acpi_enable_event( u16 ev_type, int en ) +{ + if( ev_type >= 0x8000 ) + { + struct list_head *pos; + trans_table_datum *d; + int i; + unsigned long flags; + + spin_lock_irqsave( &trans_table_list_lock, flags ); + list_for_each( pos, &trans_table_list ) + { + d = list_entry( pos, trans_table_datum, link ); + for( i=0 ; itable_len ; i++ ) + { + if( d->table[i] == ev_type ) + { + cobalt_acpi_run_enable_handler( d->hw_type, + COBALT_ACPI_EVT_GPE, + i, en ); + } + } + } + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + } + else + cobalt_acpi_run_enable_handler( COBALT_ACPI_HW_ANY, ev_type, 0, en); +} + +static void cobalt_acpi_run_enable_handler( u16 hw_type, u16 ev_type, + u16 ev_data, int en) +{ + struct list_head *pos; + unsigned long flags; + hw_handler_datum *d; + + spin_lock_irqsave(&hw_handler_list_lock, flags); + list_for_each( pos, &hw_handler_list ) + { + d = list_entry( pos, hw_handler_datum, link ); + if( (!hw_type) || (d->hw_type == hw_type) ) + d->en_handler( ev_type, ev_data, en, d->data ); + } + spin_unlock_irqrestore(&hw_handler_list_lock, flags); + +} + +static int cobalt_acpi_translate_event( cobalt_acpi_evt *evt ) +{ + struct list_head *pos; + unsigned long flags; + trans_table_datum *d; + + if( evt->ev_type != COBALT_ACPI_EVT_GPE ) + return 0; + + spin_lock_irqsave( &trans_table_list_lock, flags ); + list_for_each( pos, &trans_table_list ) + { + d = list_entry( pos, trans_table_datum, link ); + if( d->hw_type == evt->hw_type ) + { + if( evt->ev_data >= d->table_len ) + goto err_out; + + if( d->table[ evt->ev_data ] != COBALT_ACPI_EVT_NONE ) + { + evt->ev_type = d->table[ evt->ev_data ]; + evt->ev_data = 0; + } + + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + return 0; + } + } + + err_out: + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + return -1; +} + +extern int cobalt_acpi_post_event( cobalt_acpi_evt evt ) +{ + evt_list_datum *d; + unsigned long flags; + + if( ! (d = (evt_list_datum *) kmalloc( sizeof( evt_handler_datum ), GFP_ATOMIC )) ) + return -ENOMEM; + + + cobalt_acpi_translate_event( &evt ); + + memcpy( &(d->evt), &evt, sizeof(evt) ); + + spin_lock_irqsave( &dispatch_queue_lock, flags ); + list_add_tail( &(d->link), &dispatch_queue ); + spin_unlock_irqrestore( &dispatch_queue_lock, flags ); + + return 0; +} + +static int cobalt_acpi_apply_evt_handlers( evt_list_datum *d ) +{ + struct list_head *pos; + evt_handler_datum *evt_h; + int ret,err = 0; + unsigned long flags; + + spin_lock_irqsave( &evt_handler_list_lock, flags ); + list_for_each( pos, &evt_handler_list ) + { + evt_h = list_entry( pos, evt_handler_datum, link ); + if( (! evt_h->ev_type) || (evt_h->ev_type == d->evt.ev_type) ) + { + if( (ret = evt_h->handler( &d->evt, evt_h->data )) < 0 ) + err = ret; + } + } + spin_unlock_irqrestore( &evt_handler_list_lock, flags ); + + return err; +} + +static int cobalt_acpi_run_dispatch_queue( void ) +{ + struct list_head *pos; + int ret; + int err=0; + evt_list_datum *d; + unsigned long flags; + + spin_lock_irqsave( &dispatch_queue_lock, flags ); + while( (pos = list_pop( &dispatch_queue )) ) + { + d = list_entry( pos, evt_list_datum, link ); + if( (ret = cobalt_acpi_apply_evt_handlers( d )) < 0 ) + err = ret; +#ifdef CONFIG_COBALT_EMU_ACPI + cobalt_acpi_generate_proc_evt( &d->evt ); +#endif + kfree( d ); + } + spin_unlock_irqrestore( &dispatch_queue_lock, flags ); + + return err; +} + +static void acpi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct list_head *pos; + hw_handler_datum *d; + int ret=0, err=0; + unsigned long flags; + + spin_lock_irqsave(&hw_handler_list_lock, flags); + list_for_each( pos, &hw_handler_list ) + { + d = list_entry( pos, hw_handler_datum, link ); + if( (ret = d->hw_handler( irq, dev_id, regs, d->data )) < 0 ) + err = ret; + + } + spin_unlock_irqrestore(&hw_handler_list_lock, flags); + + if( (err = cobalt_acpi_run_dispatch_queue()) < 0 ) + err = ret; + + if( err ) + EPRINTK( "error at interrupt time of type %d.\n", err ); + + return; +} + + + + +int __init cobalt_acpi_init(void) +{ + int err; + + printk(KERN_INFO "Initializing Cobalt ACPI driver.\n"); + + if( cobt_is_monterey() ) + cobalt_acpi_monterey_init(); + else if( cobt_is_alpine() ) + cobalt_acpi_alpine_init(); + + if( cobt_is_5k() ) + { + if( pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL ) ) + { + if( (err = cobalt_acpi_osb4_init()) < 0 ) + { + goto cleanup; + } + } + + if( pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL ) ) + { + if( (err = cobalt_acpi_csb5_init()) < 0 ) + { + goto cleanup; + } + } + + switch( superio_type() ) + { + case SIO_TYPE_PC8731X: + if( (err = cobalt_acpi_pc8731x_init()) ) + { + goto cleanup; + } + break; + + case SIO_TYPE_PC8741X: + if( (err = cobalt_acpi_pc8741x_init()) ) + { + goto cleanup; + } + break; + + case SIO_TYPE_UNKNOWN: + EPRINTK("unknown superio type\n"); + break; + } + + /* setup an interrupt handler for an ACPI SCI */ + err = request_irq(ACPI_IRQ, acpi_interrupt, + SA_SHIRQ, ACPI_NAME, (void *)ACPI_MAGIC); + if (err) { + EPRINTK("can't assign ACPI IRQ (%d)\n", ACPI_IRQ); + return err; + } + +#ifdef CONFIG_COBALT_EMU_ACPI + cobalt_acpi_setup_proc(); +#endif + } + + /* enable some events we may want */ + cobalt_acpi_enable_event( COBALT_ACPI_EVT_PWRBTN, 1 ); + + return 0; + + cleanup: + cobalt_acpi_cleanup(); + return err; +} + +static void cobalt_acpi_cleanup( void ) +{ + cobalt_acpi_osb4_cleanup(); + cobalt_acpi_csb5_cleanup(); + cobalt_acpi_pc8731x_cleanup(); + cobalt_acpi_pc8741x_cleanup(); + + if( cobt_is_monterey() ) + cobalt_acpi_monterey_cleanup(); + if( cobt_is_alpine() ) + cobalt_acpi_alpine_cleanup(); +} + +/* + * + * Generic ACPI HW Support + * + */ + +static __inline__ char *region_name( char * subsys_name, char * blk_name ) +{ + char * new_name; + + if( !( new_name = (char *) kmalloc( strlen(subsys_name) + strlen(blk_name) + 14, + GFP_ATOMIC)) ) + return NULL; + + sprintf( new_name, "%s (%s)", subsys_name, blk_name ); + return new_name; +} + +static void free_region_names( generic_acpi_regions *regions ) +{ + if( regions->pm1a_evt_nam ) + kfree( regions->pm1a_evt_nam ); + + if( regions->pm1b_evt_nam ) + kfree( regions->pm1b_evt_nam ); + + if( regions->pm1a_cnt_nam ) + kfree( regions->pm1a_cnt_nam ); + + if( regions->pm1b_cnt_nam ) + kfree( regions->pm1b_cnt_nam ); + + if( regions->pm2_cnt_nam ) + kfree( regions->pm2_cnt_nam ); + + if( regions->pm_tmr_nam ) + kfree( regions->pm_tmr_nam ); + + if( regions->p_nam ) + kfree( regions->p_nam ); + + if( regions->gpe0_nam ) + kfree( regions->gpe0_nam ); + + if( regions->gpe1_nam ) + kfree( regions->gpe1_nam ); +} + +static int register_acpi_regions( generic_acpi_regions *regions, char * subsys_name ) +{ + int i; + + if( regions->pm1a_evt_blk && regions->pm1_evt_len ) + { + if( !(regions->pm1a_evt_nam = region_name( subsys_name, "pm1a_evt_blk" )) ) + goto cleanup0; + + if( !request_region( regions->pm1a_evt_blk, regions->pm1_evt_len, + regions->pm1a_evt_nam ) ) + goto cleanup0; + } + + if( regions->pm1b_evt_blk && regions->pm1_evt_len ) + { + if( !(regions->pm1b_evt_nam = region_name( subsys_name, "pm1b_evt_blk" )) ) + goto cleanup0; + + if( !request_region( regions->pm1b_evt_blk, regions->pm1_evt_len, + regions->pm1b_evt_nam) ) + goto cleanup1; + } + + if( regions->pm1a_cnt_blk && regions->pm1_cnt_len ) + { + if( !(regions->pm1a_cnt_nam = region_name( subsys_name, "pm1a_cnt_blk" )) ) + goto cleanup1; + + if( !request_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len, + regions->pm1a_cnt_nam ) ) + goto cleanup2; + } + + if( regions->pm1b_cnt_blk && regions->pm1_cnt_len ) + { + if( !(regions->pm1b_cnt_nam = region_name( subsys_name, "pm1b_cnt_blk" )) ) + goto cleanup2; + + if( !request_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len, + regions->pm1b_cnt_nam ) ) + goto cleanup3; + } + + if( regions->pm2_cnt_blk && regions->pm2_cnt_len ) + { + if( !(regions->pm2_cnt_nam = region_name( subsys_name, "pm2_cnt_blk" )) ) + goto cleanup3; + + if( !request_region( regions->pm2_cnt_blk, regions->pm2_cnt_len, + regions->pm2_cnt_nam ) ) + goto cleanup4; + } + + if( regions->pm_tmr_blk && regions->pm_tmr_len ) + { + if( !(regions->pm_tmr_nam = region_name( subsys_name, "pm_tmp_blk" )) ) + goto cleanup4; + + if( !request_region( regions->pm_tmr_blk, regions->pm_tmr_len, + regions->pm_tmr_nam ) ) + goto cleanup5; + } + + if( regions->p_blk ) + { + if( !(regions->p_nam = region_name( subsys_name, "p_blk" )) ) + goto cleanup5; + + if( !request_region( regions->p_blk, 6, regions->p_nam ) ) + goto cleanup6; + } + + if( regions->gpe0_blk && regions->gpe0_len ) + { + if( !(regions->gpe0_nam = region_name( subsys_name, "gpe0_blk" )) ) + goto cleanup6; + + if( !request_region( regions->gpe0_blk, regions->gpe0_len, + regions->gpe0_nam ) ) + goto cleanup7; + } + + if( regions->gpe1_blk && regions->gpe1_len ) + { + if( !(regions->gpe1_nam = region_name( subsys_name, "gpe1_blk" )) ) + goto cleanup7; + + if( !request_region( regions->gpe1_blk, regions->gpe1_len, + regions->gpe1_nam ) ) + goto cleanup8; + } + + if( (regions->gpe_ref_cnt = (atomic_t *) kmalloc( sizeof( atomic_t ) * + regions->gpe0_len * 8, + GFP_ATOMIC)) == NULL ) + goto cleanup9; + + memset( regions->gpe_ref_cnt, 0x0, sizeof( atomic_t ) * regions->gpe0_len * 8 ); + + /* disable all events and ack them */ + if( regions->pm1a_evt_blk ) + { + outw( 0x0000, regions->pm1a_evt_blk + regions->pm1_evt_len/2 ); + outw( 0xffff, regions->pm1a_evt_blk ); + } + + if( regions->pm1b_evt_blk ) + { + outw( 0x0000, regions->pm1b_evt_blk + regions->pm1_evt_len/2 ); + outw( 0xffff, regions->pm1b_evt_blk ); + } + + if( regions->gpe0_blk ) + { + for( i=0 ; i<(regions->gpe0_len/2) ; i++ ) + { + outb( 0x00, regions->gpe0_blk + regions->gpe0_len/2 + i ); + outb( 0xff, regions->gpe0_blk + i ); + } + } + + if( regions->gpe1_blk ) + { + for( i=0 ; i<(regions->gpe1_len/2) ; i++ ) + { + outb( 0x00, regions->gpe1_blk + regions->gpe1_len/2 + i ); + outb( 0xff, regions->gpe1_blk + i ); + } + } + + return 0; + + cleanup9: + if( regions->gpe1_blk ) + { + release_region( regions->gpe1_blk, regions->gpe1_len ); + regions->gpe1_blk = 0; + } + + cleanup8: + if( regions->gpe0_blk ) + { + release_region( regions->gpe0_blk, regions->gpe0_len ); + regions->gpe0_blk = 0; + } + + cleanup7: + if( regions->p_blk ) + { + release_region( regions->p_blk, 6 ); + regions->p_blk = 0; + } + + cleanup6: + if( regions->pm_tmr_blk ) + { + release_region( regions->pm_tmr_blk, regions->pm_tmr_len ); + regions->pm_tmr_blk = 0; + } + + cleanup5: + if( regions->pm2_cnt_blk ) + { + release_region( regions->pm2_cnt_blk, regions->pm2_cnt_len ); + regions->pm2_cnt_blk = 0; + } + + cleanup4: + if( regions->pm1b_cnt_blk ) + { + release_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len ); + regions->pm1b_cnt_blk = 0; + } + + cleanup3: + if( regions->pm1a_cnt_blk ) + { + release_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len ); + regions->pm1a_cnt_blk = 0; + } + + cleanup2: + if( regions->pm1b_evt_blk ) + { + release_region( regions->pm1b_evt_blk, regions->pm1_evt_len ); + regions->pm1b_evt_blk = 0; + } + + cleanup1: + if( regions->pm1a_evt_blk ) + { + release_region( regions->pm1a_evt_blk, regions->pm1_evt_len ); + regions->pm1a_evt_blk = 0; + } + + cleanup0: + free_region_names( regions ); + + return -EBUSY; +} + +static int unregister_acpi_regions( generic_acpi_regions *regions ) +{ + if( regions->pm1a_evt_blk && regions->pm1_evt_len ) + { + release_region( regions->pm1a_evt_blk, regions->pm1_evt_len ); + regions->pm1a_evt_blk = 0; + } + + if( regions->pm1b_evt_blk && regions->pm1_evt_len ) + { + release_region( regions->pm1b_evt_blk, regions->pm1_evt_len ); + regions->pm1b_evt_blk = 0; + } + + if( regions->pm1a_cnt_blk && regions->pm1_cnt_len ) + { + release_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len ); + regions->pm1a_cnt_blk = 0; + } + + if( regions->pm1b_cnt_blk && regions->pm1_cnt_len ) + { + release_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len ); + regions->pm1b_cnt_blk = 0; + } + + if( regions->pm2_cnt_blk && regions->pm2_cnt_len ) + { + release_region( regions->pm2_cnt_blk, regions->pm2_cnt_len ); + regions->pm2_cnt_blk = 0; + } + + if( regions->pm_tmr_blk && regions->pm_tmr_len ) + { + release_region( regions->pm_tmr_blk, regions->pm_tmr_len ); + regions->pm_tmr_blk = 0; + } + + if( regions->p_blk ) + { + release_region( regions->p_blk, 6 ); + regions->p_blk = 0; + } + + if( regions->gpe0_blk && regions->gpe0_len ) + { + release_region( regions->gpe0_blk, regions->gpe0_len ); + regions->gpe0_blk = 0; + } + + if( regions->gpe1_blk && regions->gpe1_len ) + { + release_region( regions->gpe1_blk, regions->gpe1_len ); + regions->gpe1_blk = 0; + } + + if( regions->gpe_ref_cnt ) + kfree( regions->gpe_ref_cnt ); + + free_region_names( regions ); + + return 0; +} + +static void cobalt_acpi_handle_pm1_blk( u16 io_addr, u16 len, + generic_acpi_regions * regions ) +{ + cobalt_acpi_evt evt; + u16 sts, en; + + evt.hw_type = regions->hw_type; + + if( (sts = inw( io_addr )) && + (en = inw( io_addr + len/2 )) ) + { + + + /* clear status bits */ + outw( sts, io_addr); + + if( (en & GEN_ACPI_TMR_STS) && + (sts & GEN_ACPI_TMR_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_TMR; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_BM_STS) && + (sts & GEN_ACPI_BM_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_BM; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_GBL_STS) && + (sts & GEN_ACPI_GBL_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_GBL; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_PWRBTN_STS) && + (sts & GEN_ACPI_PWRBTN_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_PWRBTN; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_SLPBTN_STS) && + (sts & GEN_ACPI_SLPBTN_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_SLPBTN; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_RTC_STS) && + (sts & GEN_ACPI_RTC_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_RTC; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (sts & GEN_ACPI_WAK_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_WAK; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + } +} + +static void cobalt_acpi_handle_gpe_blk( u16 io_addr, u16 len, + generic_acpi_regions * regions ) +{ + cobalt_acpi_evt evt; + int i,j; + u8 sts, en; + + evt.hw_type = regions->hw_type; + evt.ev_type = COBALT_ACPI_EVT_GPE; + + for( i=0 ; i<(len/2) ; i++ ) + { + sts = inb( io_addr + i ); + en = inb( io_addr + len/2 + i ); + + /* clear status bits */ + outb( sts, io_addr); + + for( j=0 ; j<8 ; j++ ) + { + if( (en & 0x1) && + (sts & 0x1) ) + { + evt.ev_data = i*8 + j; + cobalt_acpi_post_event( evt ); + } + en >>= 1; + sts >>= 1; + } + } +} + +static int cobalt_acpi_generic_hw_handler( int irq, void *dev_id, + struct pt_regs *regs, void * data ) +{ + generic_acpi_regions * regions = (generic_acpi_regions *) data; + cobalt_acpi_evt evt; + + evt.hw_type = regions->hw_type; + + /* various PM events */ + if( regions->pm1a_evt_blk ) + cobalt_acpi_handle_pm1_blk( regions->pm1a_evt_blk, regions->pm1_evt_len, regions ); + + if( regions->pm1b_evt_blk ) + cobalt_acpi_handle_pm1_blk( regions->pm1b_evt_blk, regions->pm1_evt_len, regions ); + + if( regions->gpe0_blk ) + cobalt_acpi_handle_gpe_blk( regions->gpe0_blk, regions->gpe0_len, regions ); + + if( regions->gpe1_blk ) + cobalt_acpi_handle_gpe_blk( regions->gpe1_blk, regions->gpe1_len, regions ); + + + return 0; +} + +static int cobalt_acpi_generic_en_handler( u16 ev_type, u16 ev_data, int en, void *data ) +{ + generic_acpi_regions * regions = (generic_acpi_regions *) data; + int block, offset; + u8 data8; + u16 data16; + + switch( ev_type ) + { + case COBALT_ACPI_EVT_TMR: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_TMR_STS; + atomic_inc( ®ions->tmr_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->tmr_ref_cnt ) ) + data16 &= ~GEN_ACPI_TMR_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_BM: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_BM_STS; + atomic_inc( ®ions->bm_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->bm_ref_cnt ) ) + data16 &= ~GEN_ACPI_BM_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_GBL: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_GBL_STS; + atomic_inc( ®ions->gbl_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->gbl_ref_cnt ) ) + data16 &= ~GEN_ACPI_GBL_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_PWRBTN: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_PWRBTN_STS; + atomic_inc( ®ions->pwrbtn_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->pwrbtn_ref_cnt ) ) + data16 &= ~GEN_ACPI_PWRBTN_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_SLPBTN: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_SLPBTN_STS; + atomic_inc( ®ions->slpbtn_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->slpbtn_ref_cnt ) ) + data16 &= ~GEN_ACPI_SLPBTN_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_RTC: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_RTC_STS; + atomic_inc( ®ions->rtc_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->rtc_ref_cnt ) ) + data16 &= ~GEN_ACPI_RTC_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_WAK: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_WAK_STS; + atomic_inc( ®ions->wak_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->wak_ref_cnt ) ) + data16 &= ~GEN_ACPI_WAK_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_GPE: + if( (ev_data/8) >= (regions->gpe0_len / 2) ) + return -EINVAL; + + block = ev_data / 8; + offset = ev_data % 8; + + data8 = inb( regions->gpe0_blk + (regions->gpe0_len / 2) + block ); + + if( en ) + { + data8 |= 0x1 << offset; + atomic_inc( ®ions->gpe_ref_cnt[ev_data] ); + } + else + { + if( atomic_dec_and_test( ®ions->gpe_ref_cnt[ev_data] ) ) + data8 &= ~( 0x1 << offset ); + } + + outb( data8, regions->gpe0_blk + (regions->gpe0_len / 2) + block ); + + break; + + default: + return -EINVAL; + + } + + return 0; +} + +/* + * + * Generic ServerWorks region code + * + */ + +static int get_serverworks_regions( generic_acpi_regions *regions, u16 type ) +{ + int reg; + + memset( regions, 0x0, sizeof( *regions ) ); + + regions->hw_type = type; + + regions->pm1_evt_len = 4; + regions->pm1_cnt_len = 2; + regions->pm_tmr_len = 4; + regions->gpe0_len = 8; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x20)) ) + regions->pm1a_evt_blk = (u16) reg; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x22)) ) + regions->pm1a_cnt_blk = (u16) reg; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x24)) ) + regions->pm_tmr_blk = (u16) reg; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x26)) ) + regions->p_blk = (u16) reg; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x28)) ) + regions->gpe0_blk = (u16) reg; + + if( type == COBALT_ACPI_HW_OSB4 ) + { + regions->pm2_cnt_len = 1; + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x2E)) ) + regions->pm2_cnt_blk = (u16) reg; + } + + switch( type ) + { + case COBALT_ACPI_HW_OSB4: + return register_acpi_regions( regions, "OSB4" ); + + case COBALT_ACPI_HW_CSB5: + return register_acpi_regions( regions, "CSB5" ); + } + + return -EINVAL; + +} + +/* + * + * ServerWorks OSB4 + * + */ + +static generic_acpi_regions osb4_regions; + +static int cobalt_acpi_osb4_init( void ) +{ + int err; + + if( (err = get_osb4_regions( &osb4_regions )) < 0 ) + return err; + + if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_OSB4, + cobalt_acpi_generic_hw_handler, + cobalt_acpi_generic_en_handler, + &osb4_regions )) < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_osb4_cleanup( void ) +{ + unregister_acpi_regions( &osb4_regions ); + return 0; +} + +static int get_osb4_regions( generic_acpi_regions *regions) +{ + return get_serverworks_regions( regions, COBALT_ACPI_HW_OSB4 ); +} + +/* + * + * ServerWorks CSB5 + * + */ + +/* static generic_acpi_regions csb5_regions; */ + +static generic_acpi_regions csb5_regions; + +static int cobalt_acpi_csb5_init( void ) +{ + int err; + + if( (err = get_csb5_regions( &csb5_regions )) < 0 ) + return err; + + if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_CSB5, + cobalt_acpi_generic_hw_handler, + cobalt_acpi_generic_en_handler, + &csb5_regions )) < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_csb5_cleanup( void ) +{ + unregister_acpi_regions( &csb5_regions ); + return 0; +} + +static int get_csb5_regions( generic_acpi_regions *regions) +{ + return get_serverworks_regions( regions, COBALT_ACPI_HW_CSB5 ); +} + +/* + * + * NatSemi PC8731x + * + */ +static generic_acpi_regions pc8731x_regions; + +static int cobalt_acpi_pc8731x_init( void ) +{ + int err; + + if( (err = get_pc8731x_regions( &pc8731x_regions )) < 0 ) + return err; + + if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_PC8731X, + cobalt_acpi_generic_hw_handler, + cobalt_acpi_generic_en_handler, + &pc8731x_regions )) < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_pc8731x_cleanup( void ) +{ + unregister_acpi_regions( &pc8731x_regions ); + return 0; +} + +static int get_pc8731x_regions( generic_acpi_regions *regions ) +{ + int reg; + u16 addr; + + memset( regions, 0x0, sizeof( *regions ) ); + + regions->hw_type = COBALT_ACPI_HW_PC8731X; + + regions->pm1_evt_len = 4; + regions->pm1_cnt_len = 2; + regions->pm_tmr_len = 4; + regions->gpe0_len = 4; + + /* superi/o -- select pm logical device and get base address */ + addr = superio_ldev_base(PC87317_DEV_PM); + if( addr ) + { + /* get registers */ + if( (reg = get_reg(addr, addr + 1, 0x08)) ) + regions->pm1a_evt_blk = reg; + + if( (reg = get_reg(addr, addr + 1, 0x0a)) ) + regions->pm_tmr_blk = reg; + + if( (reg = get_reg(addr, addr + 1, 0x0c)) ) + regions->pm1a_cnt_blk = reg; + + if( (reg = get_reg(addr, addr + 1, 0x0e)) ) + regions->gpe0_blk = reg; + } + + return register_acpi_regions( regions, "pc8731x" ); +} + +/* + * + * NatSemi PC8741x + * + */ + +static generic_acpi_regions pc8741x_regions; + +static int cobalt_acpi_pc8741x_init( void ) +{ + int err; + + if( (err = get_pc8741x_regions( &pc8741x_regions )) < 0 ) + return err; + + if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_PC8741X, + cobalt_acpi_generic_hw_handler, + cobalt_acpi_generic_en_handler, + &pc8741x_regions )) < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_pc8741x_cleanup( void ) +{ + unregister_acpi_regions( &pc8741x_regions ); + return 0; +} + +static int get_pc8741x_regions( generic_acpi_regions *regions ) +{ + int reg; + + memset( regions, 0x0, sizeof( *regions ) ); + + regions->hw_type = COBALT_ACPI_HW_PC8741X; + + regions->pm1_evt_len = 4; + regions->pm1_cnt_len = 2; + regions->pm_tmr_len = 4; + regions->gpe0_len = 8; + + /* get registers */ + if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 1)) ) + regions->pm1a_evt_blk = reg; + + if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 2)) ) + regions->pm1a_cnt_blk = reg; + + if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 3)) ) + regions->gpe0_blk = reg; + + return register_acpi_regions( regions, "pc8741x" ); +} + +/* + * + * Platform support + * + */ + +/* + * + * Monterey + * + */ + +static u16 cobalt_acpi_monterey_osb4_table[] = { +/* GPE 0 */ COBALT_ACPI_EVT_NONE, +/* GPE 1 */ COBALT_ACPI_EVT_NONE, +/* GPE 2 */ COBALT_ACPI_EVT_NONE, +/* GPE 3 */ COBALT_ACPI_EVT_NONE, +/* GPE 4 */ COBALT_ACPI_EVT_NONE, +/* GPE 5 */ COBALT_ACPI_EVT_NONE, +/* GPE 6 */ COBALT_ACPI_EVT_SLED, +/* GPE 7 */ COBALT_ACPI_EVT_NONE, +/* GPE 8 */ COBALT_ACPI_EVT_NONE, +/* GPE 9 */ COBALT_ACPI_EVT_NONE, +/* GPE 10 */ COBALT_ACPI_EVT_NONE, +/* GPE 11 */ COBALT_ACPI_EVT_NONE, +/* GPE 12 */ COBALT_ACPI_EVT_NONE, +/* GPE 13 */ COBALT_ACPI_EVT_NONE, +/* GPE 14 */ COBALT_ACPI_EVT_NONE, +/* GPE 15 */ COBALT_ACPI_EVT_NONE }; + +static u16 cobalt_acpi_monterey_superio_table[] = { +/* GPE 0 */ COBALT_ACPI_EVT_NONE, +/* GPE 1 */ COBALT_ACPI_EVT_NONE, +/* GPE 2 */ COBALT_ACPI_EVT_NONE, +/* GPE 3 */ COBALT_ACPI_EVT_NONE, +/* GPE 4 */ COBALT_ACPI_EVT_NONE, +/* GPE 5 */ COBALT_ACPI_EVT_NONE, +/* GPE 6 */ COBALT_ACPI_EVT_NONE, +/* GPE 7 */ COBALT_ACPI_EVT_NONE, +/* GPE 8 */ COBALT_ACPI_EVT_NONE, +/* GPE 9 */ COBALT_ACPI_EVT_NONE, +/* GPE 10 */ COBALT_ACPI_EVT_NONE, +/* GPE 11 */ COBALT_ACPI_EVT_NONE, +/* GPE 12 */ COBALT_ACPI_EVT_NONE, +/* GPE 13 */ COBALT_ACPI_EVT_NONE, +/* GPE 14 */ COBALT_ACPI_EVT_NONE, +/* GPE 15 */ COBALT_ACPI_EVT_NONE, +/* GPE 16 */ COBALT_ACPI_EVT_NONE, +/* GPE 17 */ COBALT_ACPI_EVT_NONE, +/* GPE 18 */ COBALT_ACPI_EVT_NONE, +/* GPE 19 */ COBALT_ACPI_EVT_NONE, +/* GPE 20 */ COBALT_ACPI_EVT_NONE, +/* GPE 21 */ COBALT_ACPI_EVT_NONE, +/* GPE 22 */ COBALT_ACPI_EVT_NONE, +/* GPE 23 */ COBALT_ACPI_EVT_NONE, +/* GPE 24 */ COBALT_ACPI_EVT_NONE, +/* GPE 25 */ COBALT_ACPI_EVT_NONE, +/* GPE 26 */ COBALT_ACPI_EVT_NONE, +/* GPE 27 */ COBALT_ACPI_EVT_NONE, +/* GPE 28 */ COBALT_ACPI_EVT_NONE, +/* GPE 29 */ COBALT_ACPI_EVT_NONE, +/* GPE 30 */ COBALT_ACPI_EVT_NONE, +/* GPE 31 */ COBALT_ACPI_EVT_NONE }; + +static int cobalt_acpi_monterey_init( void ) +{ + int err; + + err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_OSB4, + sizeof( cobalt_acpi_monterey_osb4_table )/sizeof( u16 ), + cobalt_acpi_monterey_osb4_table ); + if( err < 0 ) + return err; + + err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_PC8731X, + sizeof( cobalt_acpi_monterey_superio_table )/sizeof( u16 ), + cobalt_acpi_monterey_superio_table ); + if( err < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_monterey_cleanup( void ) +{ + cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_OSB4 ); + cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_PC8731X ); + + return 0; +} + +/* + * + * Alpine + * + */ + +static u16 cobalt_acpi_alpine_csb5_table[] = { +/* GPE 0 */ COBALT_ACPI_EVT_NONE, +/* GPE 1 */ COBALT_ACPI_EVT_NONE, +/* GPE 2 */ COBALT_ACPI_EVT_NONE, +/* GPE 3 */ COBALT_ACPI_EVT_FAN, +/* GPE 4 */ COBALT_ACPI_EVT_NONE, +/* GPE 5 */ COBALT_ACPI_EVT_SM_INT, +/* GPE 6 */ COBALT_ACPI_EVT_THERM, +/* GPE 7 */ COBALT_ACPI_EVT_NONE, +/* GPE 8 */ COBALT_ACPI_EVT_NONE, +/* GPE 9 */ COBALT_ACPI_EVT_NONE, +/* GPE 10 */ COBALT_ACPI_EVT_NONE, +/* GPE 11 */ COBALT_ACPI_EVT_NONE, +/* GPE 12 */ COBALT_ACPI_EVT_NONE, +/* GPE 13 */ COBALT_ACPI_EVT_NONE, +/* GPE 14 */ COBALT_ACPI_EVT_NONE, +/* GPE 15 */ COBALT_ACPI_EVT_NONE }; + +static u16 cobalt_acpi_alpine_superio_table[] = { +/* GPE 0 */ COBALT_ACPI_EVT_NONE, +/* GPE 1 */ COBALT_ACPI_EVT_NONE, +/* GPE 2 */ COBALT_ACPI_EVT_NONE, +/* GPE 3 */ COBALT_ACPI_EVT_NONE, +/* GPE 4 */ COBALT_ACPI_EVT_NONE, +/* GPE 5 */ COBALT_ACPI_EVT_NONE, +/* GPE 6 */ COBALT_ACPI_EVT_NONE, +/* GPE 7 */ COBALT_ACPI_EVT_NONE, +/* GPE 8 */ COBALT_ACPI_EVT_NONE, +/* GPE 9 */ COBALT_ACPI_EVT_NONE, +/* GPE 10 */ COBALT_ACPI_EVT_NONE, +/* GPE 11 */ COBALT_ACPI_EVT_NONE, +/* GPE 12 */ COBALT_ACPI_EVT_NONE, +/* GPE 13 */ COBALT_ACPI_EVT_NONE, +/* GPE 14 */ COBALT_ACPI_EVT_NONE, +/* GPE 15 */ COBALT_ACPI_EVT_NONE, +/* GPE 16 */ COBALT_ACPI_EVT_NONE, +/* GPE 17 */ COBALT_ACPI_EVT_NONE, +/* GPE 18 */ COBALT_ACPI_EVT_NONE, +/* GPE 19 */ COBALT_ACPI_EVT_NONE, +/* GPE 20 */ COBALT_ACPI_EVT_NONE, +/* GPE 21 */ COBALT_ACPI_EVT_NONE, +/* GPE 22 */ COBALT_ACPI_EVT_NONE, +/* GPE 23 */ COBALT_ACPI_EVT_NONE, +/* GPE 24 */ COBALT_ACPI_EVT_NONE, +/* GPE 25 */ COBALT_ACPI_EVT_NONE, +/* GPE 26 */ COBALT_ACPI_EVT_NONE, +/* GPE 27 */ COBALT_ACPI_EVT_NONE, +/* GPE 28 */ COBALT_ACPI_EVT_NONE, +/* GPE 29 */ COBALT_ACPI_EVT_NONE, +/* GPE 30 */ COBALT_ACPI_EVT_NONE, +/* GPE 31 */ COBALT_ACPI_EVT_NONE }; + +static int cobalt_acpi_alpine_init( void ) +{ + int err; + + err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_CSB5, + sizeof( cobalt_acpi_alpine_csb5_table )/sizeof( u16 ), + cobalt_acpi_alpine_csb5_table ); + if( err < 0 ) + return err; + + err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_PC8741X, + sizeof( cobalt_acpi_alpine_superio_table )/sizeof( u16 ), + cobalt_acpi_alpine_superio_table ); + if( err < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_alpine_cleanup( void ) +{ + cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_CSB5 ); + cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_PC8741X ); + + return 0; +} + +/* + * end platform support + */ +#ifdef CONFIG_COBALT_EMU_ACPI +/* + * This is all necessary because we don't have BIOS support for ACPI yet. + * We can fake it here, and when full support is ready just yank this. + */ +typedef struct { + char *device_type; + char *device_instance; + u32 event_type; + u32 event_data; + struct list_head list; +} cobalt_acpi_event_t; + +#define COBALT_ACPI_MAX_STRING_LENGTH 80 + +static LIST_HEAD(cobalt_acpi_event_list); +static DECLARE_WAIT_QUEUE_HEAD(cobalt_acpi_event_wait_queue); +static int event_is_open = 0; +static spinlock_t cobalt_acpi_event_lock = SPIN_LOCK_UNLOCKED; + +static struct proc_dir_entry *cobalt_acpi_proc_root; +static struct proc_dir_entry *cobalt_acpi_proc_event; + +static struct file_operations proc_event_ops = { + open: cobalt_acpi_open_event, + read: cobalt_acpi_read_event, + release: cobalt_acpi_close_event, + poll: cobalt_acpi_poll_event, +}; + +static int +cobalt_acpi_setup_proc(void) +{ + cobalt_acpi_proc_root = proc_mkdir("acpi", NULL); + if (!cobalt_acpi_proc_root) { + return -ENOMEM; + } + + cobalt_acpi_proc_event = create_proc_entry("event", S_IRUSR, + cobalt_acpi_proc_root); + if (!cobalt_acpi_proc_event) { + return -ENOMEM; + } + + cobalt_acpi_proc_event->proc_fops = &proc_event_ops; + + return 0; +} + + +int +cobalt_acpi_generate_proc_evt( cobalt_acpi_evt * evt ) +{ + cobalt_acpi_event_t *event = NULL, *tmp; + u32 flags = 0; + char *dev_type; + char *dev_instance; + u32 event_type; + u32 event_data; + struct list_head *pos; + + /* drop event on the floor if no one's listening */ + if (!event_is_open) + return 0; + + event_type = (evt->ev_type << 0x10) | + evt->hw_type; + event_data = evt->ev_data; + + + /* + * Check to see if an event of this type is already + * pending + */ + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + list_for_each( pos, &cobalt_acpi_event_list ) + { + tmp = list_entry(pos, cobalt_acpi_event_t, list); + if( (tmp->event_type == event_type) && + (tmp->event_data == event_data) ) + { + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + return 0; + } + + + } + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + + + /* parse the event struct */ + switch( evt->ev_type ) + { + case COBALT_ACPI_EVT_TMR: + dev_type = "generic"; + dev_instance = "timer"; + break; + + case COBALT_ACPI_EVT_BM: + dev_type = "generic"; + dev_instance = "bus-master"; + break; + + case COBALT_ACPI_EVT_GBL: + dev_type = "generic"; + dev_instance = "global"; + break; + + case COBALT_ACPI_EVT_PWRBTN: + dev_type = "button"; + dev_instance = "power"; + break; + + case COBALT_ACPI_EVT_SLPBTN: + dev_type = "button"; + dev_instance = "sleep"; + break; + + case COBALT_ACPI_EVT_RTC: + dev_type = "generic"; + dev_instance = "rtc"; + break; + + case COBALT_ACPI_EVT_WAK: + dev_type = "generic"; + dev_instance = "wake"; + break; + + case COBALT_ACPI_EVT_GPE: + dev_type = "generic"; + dev_instance = "gpe"; + break; + + case COBALT_ACPI_EVT_SLED: + dev_type = "cobalt"; + dev_instance = "sled"; + break; + + case COBALT_ACPI_EVT_THERM: + dev_type = "cobalt"; + dev_instance = "therm_trip"; + break; + + case COBALT_ACPI_EVT_FAN: + dev_type = "cobalt"; + dev_instance = "fan"; + break; + + case COBALT_ACPI_EVT_SM_INT: + dev_type = "cobalt"; + dev_instance = "sm_int"; + break; + + case COBALT_ACPI_EVT_VOLT: + dev_type = "cobalt"; + dev_instance = "volt_trip"; + break; + + default: + dev_type = "unknown"; + dev_instance = "unknown"; + break; + } + + + /* + * Allocate a new event structure. + */ + event = kmalloc(sizeof(*event), GFP_ATOMIC); + if (!event) + goto alloc_error; + + event->device_type=NULL; + event->device_instance=NULL; + + event->device_type = kmalloc(strlen(dev_type) + sizeof(char), + GFP_ATOMIC); + if (!event->device_type) + goto alloc_error; + + event->device_instance = kmalloc(strlen(dev_instance) + sizeof(char), + GFP_ATOMIC ); + if (!event->device_instance) + goto alloc_error; + + /* + * Set event data. + */ + strcpy(event->device_type, dev_type); + strcpy(event->device_instance, dev_instance); + event->event_type = event_type; + event->event_data = event_data; + + /* + * Add to the end of our event list. + */ + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + list_add_tail(&event->list, &cobalt_acpi_event_list); + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + + /* + * Signal waiting threads (if any). + */ + wake_up_interruptible(&cobalt_acpi_event_wait_queue); + + return 0; + +alloc_error: + if(event) + { + if (event->device_instance) + kfree(event->device_instance); + + if (event->device_type) + kfree(event->device_type); + + kfree(event); + } + + return -ENOMEM; +} + + +static int +cobalt_acpi_open_event(struct inode *inode, struct file *file) +{ + int flags; + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + + if (event_is_open) + goto out_busy; + + event_is_open = 1; + + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + return 0; + +out_busy: + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + return -EBUSY; +} + + +static int +cobalt_acpi_close_event(struct inode *inode, struct file *file) +{ + unsigned long flags; + struct list_head *pos; + cobalt_acpi_event_t *tmp; + + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + + while( (pos = list_pop( &cobalt_acpi_event_list )) ) + { + tmp = list_entry(pos, cobalt_acpi_event_t, list); + if (tmp->device_instance) + kfree(tmp->device_instance); + + if (tmp->device_type) + kfree(tmp->device_type); + + kfree( tmp ); + } + event_is_open = 0; + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + return 0; +} + +#define ACPI_MAX_STRING_LENGTH 80 +static ssize_t +cobalt_acpi_read_event(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + cobalt_acpi_event_t *event = NULL; + unsigned long flags = 0; + static char str[ACPI_MAX_STRING_LENGTH]; + static int strsize; + static char *ptr; + + if (!strsize) { + DECLARE_WAITQUEUE(wait, current); + + if (list_empty(&cobalt_acpi_event_list)) { + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&cobalt_acpi_event_wait_queue, &wait); + + if (list_empty(&cobalt_acpi_event_list)) { + schedule(); + } + + remove_wait_queue(&cobalt_acpi_event_wait_queue, &wait); + set_current_state(TASK_RUNNING); + + if (signal_pending(current)) { + return -ERESTARTSYS; + } + } + + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + event = list_entry(cobalt_acpi_event_list.next, + cobalt_acpi_event_t, list); + list_del(&event->list); + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + + strsize = sprintf(str, "%s %s %08x %08x\n", + event->device_type, event->device_instance, + event->event_type, event->event_data); + ptr = str; + + kfree(event->device_type); + kfree(event->device_instance); + kfree(event); + } + if (strsize < count) + count = strsize; + + if (copy_to_user(buf, ptr, count)) + return -EFAULT; + + *ppos += count; + strsize -= count; + ptr += count; + + return count; +} + +static unsigned int +cobalt_acpi_poll_event(struct file *file, poll_table *wait) +{ + poll_wait(file, &cobalt_acpi_event_wait_queue, wait); + if (!list_empty(&cobalt_acpi_event_list)) + return POLLIN | POLLRDNORM; + return 0; +} + +#endif /* CONFIG_COBALT_EMU_ACPI */ diff -ruN linux-2.4.29/drivers/cobalt/fans.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/fans.c --- linux-2.4.29/drivers/cobalt/fans.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/fans.c 2005-03-21 17:27:16.645962562 -0700 @@ -0,0 +1,413 @@ +/* $Id: fans.c,v 1.18 2002/03/16 21:33:02 duncan Exp $ + * Copyright (c) 2000-2001 Sun Microsystems, Inc + * + * This should be SMP safe. The critical data (the info list) and the + * critical code (inb()/outb() calls) are protected by fan_lock. It is + * locked at the only external access points - the proc read()/write() + * methods. --TPH + */ +#include +#if defined(CONFIG_COBALT_FANS) || defined(CONFIG_COBALT_FANS_MODULE) + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* GPIO base is assigned by BIOS, perhaps we should probe it */ +#define GPIO_BASE 0x600 +#define FAN_GPIO_MAX 8 +#define FAN_RPM(fn,ms) ((fn).hcyl * (60000000 / (fn).poles) / (ms)) +#define FAN_VALID(f) ((f)->mask && (f)->poles) +#define FAN_CACHE_TIME 2 /* seconds */ +#define FAN_SAMPLE_LEN 50 /* milliseconds */ + +/* + * fans are attached to GPIO pins + * each pin is part of a port, multiple fans are controlled by a port + */ +struct fan_info { + int id; /* fan number */ + uint8_t mask; /* mask within the port */ + int poles; /* # of magnetic poles (divisor) */ + int hcyl; /* # of half cycles */ + unsigned rpm; /* calculated fan speed */ + char *type; /* FAN description */ +}; + +struct fan_gpio { + int port; /* GPIO Port */ + uint16_t base; /* GPDI (data in) base address */ + uint8_t latch; /* latched 'data in' value */ + long tcache; /* latched 'epoch' value */ + struct fan_info fan[FAN_GPIO_MAX]; +}; + +/* the current fanlist */ +static struct fan_gpio *sys_fanlist; +static spinlock_t fan_lock = SPIN_LOCK_UNLOCKED; + +static struct fan_gpio fan_gpio_raqxtr[] = { + { + port: 1, + base: GPIO_BASE, + fan: { + { mask: 0x2, poles: 4, type: "processor" }, + { mask: 0x4, poles: 4, type: "processor" }, + { mask: 0 }, + }, + }, + { + port: 2, + base: GPIO_BASE+4, + fan: { + { mask: 0x10, poles: 4 }, + { mask: 0x20, poles: 4 }, + { mask: 0x40, poles: 4 }, + { mask: 0x80, poles: 4 }, + { mask: 0 }, + }, + }, + { port: -1 } +}; + +static struct fan_gpio fan_gpio_alpine[] = { + { + port: 2, + base: GPIO_BASE+7, + fan: { + { mask: 0x4, poles: 4 }, + { mask: 0x8, poles: 4 }, + { mask: 0x10, poles: 4 }, + { mask: 0x20, poles: 4, type: "power supply" }, + { mask: 0x40, poles: 4, type: "processor" }, + { mask: 0 }, + }, + }, + { port: -1 } +}; + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC +static struct proc_dir_entry *proc_faninfo; +#endif /* CONFIG_COBALT_OLDPROC */ +static struct proc_dir_entry *proc_cfaninfo; +#endif /* CONFIG_PROC_FS */ + +static struct fan_info *fan_info_find(int id); +static int fan_control(struct fan_info *fi, int todo); +static int fan_info_print(char *buffer); +static int fan_read_proc(char *buf, char **start, off_t pos, + int len, int *eof, void *x); +static int fan_write_proc(struct file *file, const char *buf, + unsigned long len, void *x); + +int __init +cobalt_fan_init(void) +{ + if (cobt_is_monterey()) { + sys_fanlist = (struct fan_gpio *)fan_gpio_raqxtr; + } else if (cobt_is_alpine()) { + sys_fanlist = (struct fan_gpio *)fan_gpio_alpine; + } else { + sys_fanlist = NULL; + return -ENOSYS; + } + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + proc_faninfo = create_proc_entry("faninfo", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, NULL); + if (!proc_faninfo) { + EPRINTK("can't create /proc/faninfo\n"); + return -ENOENT; + } + proc_faninfo->owner = THIS_MODULE; + proc_faninfo->read_proc = fan_read_proc; + proc_faninfo->write_proc = fan_write_proc; +#endif /* CONFIG_COBALT_OLDPROC */ + proc_cfaninfo = create_proc_entry("faninfo", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, proc_cobalt); + if (!proc_cfaninfo) { + EPRINTK("can't create /proc/cobalt/faninfo\n"); + return -ENOENT; + } + proc_cfaninfo->owner = THIS_MODULE; + proc_cfaninfo->read_proc = fan_read_proc; + proc_cfaninfo->write_proc = fan_write_proc; +#endif /* CONFIG_PROC_FS */ + + return 0; +} + +static void __exit +cobalt_fan_exit(void) +{ +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + if (proc_faninfo) { + remove_proc_entry("faninfo", NULL); + } +#endif /* CONFIG_COBALT_OLDPROC */ + if (proc_cfaninfo) { + remove_proc_entry("faninfo", proc_cobalt); + } +#endif /* CONFIG_PROC_FS */ + + sys_fanlist = NULL; +} + +/* + * Samples fan tachometer square wave to calculate and report RPM + */ +static int +get_faninfo(char *buffer) +{ + struct fan_gpio *fg; + struct timeval utime; + unsigned long elapsed, start; + int i, val, len; + + if (!sys_fanlist || !cobt_is_5k()) { + /* software is keyed off this string - do not change it ! */ + return sprintf(buffer, "Fan monitoring not supported.\n"); + } + + /* save start timestamp */ + do_gettimeofday(&utime); + start = utime.tv_usec; + + /* initialize 'previous' values. we do edge detection by + * looking for transitions from previous values */ + for (fg = sys_fanlist; fg->port >= 0; fg++) { + if (fg->tcache && utime.tv_sec < fg->tcache+FAN_CACHE_TIME) { + return fan_info_print(buffer); + } + fg->tcache = utime.tv_sec; + fg->latch = inb(fg->base); + for (i = 0; i < FAN_GPIO_MAX; i++) { + fg->fan[i].hcyl = 0; + fg->fan[i].rpm = 0; + } + } + + /* We are counting the number of halfcycles in a square wave + * that pass in a given amount of time to determine frequency */ + do { + for (fg=sys_fanlist; fg->port>=0; fg++) { + val = inb(fg->base); + for (i=0; ifan[i]; + if (FAN_VALID(p)) { + if ((val ^ fg->latch) & p->mask) { + p->hcyl++; + } + } + } + fg->latch = val; + } + + do_gettimeofday(&utime); + if (utime.tv_usec > start) { + elapsed = utime.tv_usec - start; + } else { + elapsed = utime.tv_usec + 1000001 - start; + } + + } while (elapsed < (FAN_SAMPLE_LEN) * 1000); + + /* Fan rpm = 60 / ( t * poles ) + * where t is 1/2 the period and poles are the number of + * magnetic poles for the fan. + * + * For the Sunon KDE1204PKBX fans on Raq XTR, poles = 4 + * So, in terms of cycles, + * + * rpm = 60 s/m halfcycles + * ------ * -------------- * 1,000,000 us/s * 2 + * 4 2 * elapsed us + * + * = (60,000,000 / 4 poles) * halfcycles / elapsed + * = 15,000,000 * halfcycles / elapsed + * + * Note, by this method and sampling for 50ms, our accuracy + * is +/- 300 rpm. The fans are spec'ed for +/- 1000 rpm + */ + for (val=len=0, fg=sys_fanlist; fg->port>=0; fg++) { + for (i=0; ifan[i]; + if (FAN_VALID(p)) { + p->id = val++; + p->rpm = FAN_RPM(fg->fan[i], elapsed); + len += sprintf(buffer+len, "fan %d : %u\n", + p->id, p->rpm); + } + } + } + + return len; +} + +static int +fan_info_print(char *buffer) +{ + struct fan_gpio *fg; + int i, len=0; + + if (!sys_fanlist) { + return -1; + } + + for (fg=sys_fanlist; fg->port>=0; fg++) { + for (i=0; ifan[i]; + if (FAN_VALID(p)) { + len += sprintf(buffer+len, "fan %d : %u\n", + p->id, p->rpm); + } + } + } + + return len; +} + +/* FIXME: generify */ +static int +fan_control(struct fan_info *fi, int todo) +{ + if (fi && cobt_is_alpine()) { + switch (fi->id) { + case 4: { + /* CPU FAN */ + uint8_t gpdo = inb(GPIO_BASE+6); + + if (todo) { + gpdo &= ~fi->mask; /* 0 = on */ + } else { + gpdo |= fi->mask; /* 1 = off */ + } + outb(gpdo, GPIO_BASE+6); + return 0; + } + default: + return -ENODEV; + } + } + + return -ENOSYS; +} + +static struct fan_info * +fan_info_find(int id) +{ + struct fan_gpio *fg; + int i; + + if (!sys_fanlist) { + return NULL; + } + + for (fg=sys_fanlist; fg->port>=0; fg++) { + for (i=0; ifan[i])) { + if (fg->fan[i].id == id) { + return &fg->fan[i]; + } + } + } + } + + return NULL; +} + +#ifdef CONFIG_PROC_FS +static int +fan_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + int plen; + + MOD_INC_USE_COUNT; + + spin_lock(&fan_lock); + plen = get_faninfo(buf); + spin_unlock(&fan_lock); + + MOD_DEC_USE_COUNT; + + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} + +static int +fan_write_proc(struct file *file, const char *buf, unsigned long len, void *x) +{ + char *page; + int retval = -EINVAL; + + MOD_INC_USE_COUNT; + + if (len > PAGE_SIZE) { + MOD_DEC_USE_COUNT; + return -EOVERFLOW; + } + + page = (char *)__get_free_page(GFP_KERNEL); + if (!page) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + if (copy_from_user(page, buf, len)) { + free_page((unsigned long)page); + MOD_DEC_USE_COUNT; + return -EFAULT; + } + page[len] = '\0'; + + /* format: `fan ID COMMAND' */ + if (len>5 && !strncmp("fan ", page, 4)) { + if (*(page+4) != '\0') { + struct fan_info *finf; + char *nextpg = NULL; + + spin_lock(&fan_lock); + finf = fan_info_find(simple_strtoul(page+4,&nextpg,0)); + if (!finf) { + retval = -ENOENT; + } else if (nextpg != '\0') { + if (!strncmp("on", nextpg+1, 2)) { + retval = fan_control(finf, 1); + } + else if (!strncmp("off", nextpg+1, 3)) { + retval = fan_control(finf, 0); + } + } + spin_unlock(&fan_lock); + } + } + + free_page((unsigned long)page); + MOD_DEC_USE_COUNT; + + return (retval < 0) ? retval : len; +} +#endif /* CONFIG_PROC_FS */ + +#if defined(CONFIG_COBALT_FANS_MODULE) +module_init(cobalt_fan_init); +module_exit(cobalt_fan_exit); + +MODULE_AUTHOR("Sun Cobalt"); +MODULE_DESCRIPTION("Sun Cobalt fan tachometers"); +#endif + +#endif /* CONFIG_COBALT_FANS || CONFIG_COBALT_FANS_MODULE */ diff -ruN linux-2.4.29/drivers/cobalt/i2c.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/i2c.c --- linux-2.4.29/drivers/cobalt/i2c.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/i2c.c 2005-03-21 17:27:16.646962413 -0700 @@ -0,0 +1,517 @@ +/* + * $Id: i2c.c,v 1.19 2002/09/17 23:41:29 sparker Exp $ + * i2c.c : Cobalt I2C driver support + * + * Copyright (C) 2000 Cobalt Networks, Inc. + * Copyright (C) 2001 Sun Microsystems, Inc. + * + * This should be SMP safe. All the exported functions lock on enter and + * unlock on exit. These exported functions may be called at interupt time, + * so we have to use the IRQ safe locks. NOTE: no function herein may call + * any exported function herein. --TPH + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define I2C_3K_STATUS 0x00 +#define I2C_3K_CMD 0x01 +#define I2C_3K_START 0x02 +#define I2C_3K_ADDR 0x03 +#define I2C_3K_LOW_DATA 0x04 +#define I2C_3K_HIGH_DATA 0x05 +#define I2C_3K_BLOCK_DATA 0x06 +#define I2C_3K_INDEX 0x07 +#define I2C_3K_STATUS_IDLE 0x04 +#define I2C_3K_CMD_RW_BYTE 0x20 +#define I2C_3K_CMD_RW_WORD 0x30 +#define I2C_3K_CMD_RW_BLOCK 0xC0 +#define I2C_3K_CMD_RESET_PTR 0x80 + +#define I2C_5K_HOST_STATUS 0x00 +#define I2C_5K_SLAVE_STATUS 0x01 +#define I2C_5K_HOST_CONTROL 0x02 +#define I2C_5K_HOST_COMMAND 0x03 +#define I2C_5K_HOST_ADDR 0x04 +#define I2C_5K_DATA_0 0x05 +#define I2C_5K_DATA_1 0x06 +#define I2C_5K_BLOCK_DATA 0x07 +#define I2C_5K_SLAVE_CONTROL 0x08 +#define I2C_5K_SHADOW_COMMAND 0x09 +#define I2C_5K_SLAVE_EVENT 0x0a +#define I2C_5K_SLAVE_DATA 0x0c +#define I2C_5K_HOST_STATUS_BUSY 0x01 +#define I2C_5K_HOST_CMD_START 0x40 +#define I2C_5K_HOST_CMD_QUICK_RW (0 << 2) +#define I2C_5K_HOST_CMD_BYTE_RW (1 << 2) +#define I2C_5K_HOST_CMD_BYTE_DATA_RW (2 << 2) +#define I2C_5K_HOST_CMD_WORD_DATA_RW (3 << 2) +#define I2C_5K_HOST_CMD_BLOCK_DATA_RW (5 << 2) + +#define I2C_WRITE 0 +#define I2C_READ 1 + +/* this delay was determined empirically */ +#define I2C_WRITE_UDELAY 1000 + +struct cobalt_i2c_data { + const unsigned char status; + const unsigned char addr; + const unsigned char index; + const unsigned char data_low; + const unsigned char data_high; + const unsigned char data_block; + const unsigned char rw_byte; + const unsigned char rw_word; + const unsigned char rw_block; + unsigned int io_port; +}; + +struct cobalt_i2c_data cobalt_i2c_3k = { + I2C_3K_STATUS, + I2C_3K_ADDR, + I2C_3K_INDEX, + I2C_3K_LOW_DATA, + I2C_3K_HIGH_DATA, + I2C_3K_BLOCK_DATA, + I2C_3K_CMD_RW_BYTE, + I2C_3K_CMD_RW_WORD, + I2C_3K_CMD_RW_BLOCK, + 0L +}; + +struct cobalt_i2c_data cobalt_i2c_5k = { + I2C_5K_HOST_STATUS, + I2C_5K_HOST_ADDR, + I2C_5K_HOST_COMMAND, + I2C_5K_DATA_0, + I2C_5K_DATA_1, + I2C_5K_BLOCK_DATA, + I2C_5K_HOST_CMD_BYTE_DATA_RW, + I2C_5K_HOST_CMD_WORD_DATA_RW, + I2C_5K_HOST_CMD_BLOCK_DATA_RW, + 0L +}; + +/* a global pointer for our i2c data */ +struct cobalt_i2c_data *i2c_data; + +#define I2C_REG(r) (i2c_data->io_port + i2c_data->r) +#define I2C_CMD(c) (i2c_data->c) + +#define I2C_LOCK (1 << 0) +#define I2C_DEAD (1 << 1) +static int i2c_state; + +static int initialized; + +static inline int +do_i2c_lock(void) +{ + int i = 0; + + if (test_bit(I2C_DEAD, &i2c_state)) + return -1; + + while (test_and_set_bit(I2C_LOCK, &i2c_state)) { + if (i++ > 5) + return -1; + udelay(10); + } + udelay(1); + return 0; +} + +static inline void +do_i2c_unlock(void) +{ + clear_bit(I2C_LOCK, &i2c_state); +} + +/* do a little squelching */ +#define NOISE_RATE (5*HZ) +static int +i2c_noisy(void) +{ + static unsigned long last_time; + static unsigned int messages; + + if ((long) (jiffies - last_time) > NOISE_RATE) { + last_time = jiffies; + if (messages) { + WPRINTK("skipped %u kernel messages\n", messages); + messages = 0; + } + return 0; + } + messages++; + return 1; +} + +static int +i2c_wait_for_smi(void) +{ + static unsigned int shutup = 0; + int timeout=10; + int status; + + while (timeout--) { + udelay(100); /* wait */ + status = inb_p(I2C_REG(status)); + + if (cobt_is_3k()) { + if (status & I2C_3K_STATUS_IDLE) { + return 0; + } + } else if (cobt_is_5k()) { + if (!(status & I2C_5K_HOST_STATUS_BUSY)) { + return 0; + } + } + outb_p(status, I2C_REG(status)); + } + + /* still busy - complain */ + if (!i2c_noisy()) { + if (++shutup > 2) { + EPRINTK("i2c seems to be dead - sorry\n"); + set_bit(I2C_DEAD, &i2c_state); + } else { + WPRINTK("i2c timeout: status busy (0x%x), resetting\n", + status); + } + } + + /* punch the abort bit */ + if (cobt_is_3k()) { + outb_p(4, i2c_data->io_port + I2C_3K_CMD); + } else if (cobt_is_5k()) { + outb_p(2, i2c_data->io_port + I2C_5K_HOST_CONTROL); + outb_p(1, i2c_data->io_port + I2C_5K_HOST_CONTROL); + } + + return -1; +} + +static inline int +i2c_setup(const int dev, const int index, const int r) +{ + if (i2c_wait_for_smi() < 0) + return -1; + + /* clear status */ + outb_p(0xff, I2C_REG(status)); + + /* device address */ + outb_p((dev|r) & 0xff, I2C_REG(addr)); + + /* I2C index */ + outb_p(index & 0xff, I2C_REG(index)); + + return 0; +} + +static inline int +i2c_cmd(const unsigned char command) +{ + if (cobt_is_3k()) { + outb_p(command, i2c_data->io_port + I2C_3K_CMD); + outb_p(0xff, i2c_data->io_port + I2C_3K_START); + } else if (cobt_is_5k()) { + outb_p(I2C_5K_HOST_CMD_START | command, + i2c_data->io_port + I2C_5K_HOST_CONTROL); + } + + if (i2c_wait_for_smi() < 0) + return -1; + + return 0; +} + +int +cobalt_i2c_init(void) +{ + struct pci_dev *i2cdev = NULL; + + if( ! initialized ) { + if (cobt_is_3k()) { + i2c_data = &cobalt_i2c_3k; + i2cdev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M7101, NULL); + if (!i2cdev) { + EPRINTK("can't find PMU for i2c access\n"); + return -1; + } + pci_read_config_dword(i2cdev, 0x14, &i2c_data->io_port); + } else if (cobt_is_5k()) { + i2c_data = &cobalt_i2c_5k; + i2cdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, i2cdev); + if (!i2cdev) { + i2cdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, i2cdev); + if (!i2cdev) { + EPRINTK("can't find OSB4 or CSB5 for i2c access\n"); + return -1; + } + } + pci_read_config_dword(i2cdev, 0x90, &i2c_data->io_port); + } + + i2c_data->io_port &= 0xfff0; + if (!i2c_data->io_port) { + EPRINTK("i2c IO port not found\n"); + } + initialized = 1; + } + + return 0; +} + +int +cobalt_i2c_reset(void) +{ + int r; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (cobt_is_3k()) { + /* clear status */ + outb_p(0xff, i2c_data->io_port + I2C_3K_STATUS); + /* reset SMB devs */ + outb_p(0x08, i2c_data->io_port + I2C_3K_CMD); + /* start command */ + outb_p(0xff, i2c_data->io_port + I2C_3K_START); + } else if (cobt_is_5k()) { + /* clear status */ + outb_p(0x2, i2c_data->io_port + I2C_5K_HOST_CONTROL); + outb_p(0x1, i2c_data->io_port + I2C_5K_HOST_CONTROL); + outb_p(0xff, i2c_data->io_port + I2C_5K_HOST_STATUS); + outb_p(I2C_5K_HOST_CMD_START | 0x08, + i2c_data->io_port + I2C_5K_HOST_CONTROL); + } + + r = i2c_wait_for_smi(); + + do_i2c_unlock(); + + return r; +} + +int +cobalt_i2c_read_byte(const int dev, const int index) +{ + int val = 0; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_READ) < 0 + || i2c_cmd(I2C_CMD(rw_byte)) < 0) { + val = -1; + } + + if (val == 0) { + val = inb_p(I2C_REG(data_low)); + } + + do_i2c_unlock(); + + return val; +} + +int +cobalt_i2c_read_word(const int dev, const int index) +{ + int val = 0; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_READ) < 0 + || i2c_cmd(I2C_CMD(rw_word)) < 0) { + val = -1; + } + + if (val == 0) { + val = inb_p(I2C_REG(data_low)); + val += inb_p(I2C_REG(data_high)) << 8; + } + + do_i2c_unlock(); + + return val; +} + +int +cobalt_i2c_read_block(const int dev, const int index, + unsigned char *data, int count) +{ + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_READ) < 0) { + do_i2c_unlock(); + return -1; + } + + outb_p(count & 0xff, I2C_REG(data_low)); + outb_p(count & 0xff, I2C_REG(data_high)); + + if (i2c_cmd(I2C_CMD(rw_block)) < 0) { + do_i2c_unlock(); + return -1; + } + + while (count) { + /* read a byte of block data */ + *data = inb_p(I2C_REG(data_block)); + data++; + count--; + } + + do_i2c_unlock(); + + return 0; +} + +int +cobalt_i2c_write_byte(const int dev, const int index, const u8 val) +{ + int r = 0; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_WRITE) < 0) { + r = -1; + } + + if (r == 0) { + outb_p(val & 0xff, I2C_REG(data_low)); + + if (i2c_cmd(I2C_CMD(rw_byte)) < 0) { + r = -1; + } + } + + udelay(I2C_WRITE_UDELAY); + + do_i2c_unlock(); + + return r; +} + +int +cobalt_i2c_write_word(const int dev, const int index, const u16 val) +{ + int r = 0; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_WRITE) < 0) { + r = -1; + } + + if (r == 0) { + outb_p(val & 0xff, I2C_REG(data_low)); + outb_p((val >> 8) & 0xff, I2C_REG(data_high)); + + if (i2c_cmd(I2C_CMD(rw_word)) < 0) { + r = -1; + } + } + + udelay(I2C_WRITE_UDELAY); + + do_i2c_unlock(); + + return r; +} + +int +cobalt_i2c_write_block(int dev, int index, unsigned char *data, int count) +{ + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_WRITE) < 0) { + do_i2c_unlock(); + return -1; + } + + outb_p(count & 0xff, I2C_REG(data_low)); + outb_p(count & 0xff, I2C_REG(data_high)); + + if (i2c_cmd(I2C_CMD(rw_block)) < 0) { + do_i2c_unlock(); + return -1; + } + + while (count) { + /* write a byte of block data */ + outb_p(*data, I2C_REG(data_block)); + data++; + count--; + } + + udelay(I2C_WRITE_UDELAY); + + do_i2c_unlock(); + + return 0; +} + +EXPORT_SYMBOL(cobalt_i2c_reset); +EXPORT_SYMBOL(cobalt_i2c_read_byte); +EXPORT_SYMBOL(cobalt_i2c_read_word); +EXPORT_SYMBOL(cobalt_i2c_read_block); +EXPORT_SYMBOL(cobalt_i2c_write_byte); +EXPORT_SYMBOL(cobalt_i2c_write_word); +EXPORT_SYMBOL(cobalt_i2c_write_block); diff -ruN linux-2.4.29/drivers/cobalt/init.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/init.c --- linux-2.4.29/drivers/cobalt/init.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/init.c 2005-03-21 17:27:16.646962413 -0700 @@ -0,0 +1,111 @@ +/* $Id: init.c,v 1.22 2002/11/04 17:54:15 thockin Exp $ */ +/* + * Copyright (c) 2001 Sun Microsystems + * Generic initialization, to reduce pollution of other files + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static int cobalt_proc_init(void); +extern int cobalt_i2c_init(void); +extern int cobalt_net_init(void); +extern int cobalt_systype_init(void); +extern void cobalt_boardrev_init(void); +extern int cobalt_led_init(void); +extern int cobalt_lcd_init(void); +extern int cobalt_serialnum_init(void); +extern int cobalt_wdt_init(void); +extern int cobalt_sensors_init(void); +extern int cobalt_fan_init(void); +extern int cobalt_acpi_init(void); +extern int cobalt_ruler_init(void); + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_cobalt; +EXPORT_SYMBOL(proc_cobalt); +#endif +spinlock_t cobalt_superio_lock = SPIN_LOCK_UNLOCKED; + +/* initialize all the cobalt specific stuff */ +int __init +cobalt_init(void) +{ + cobalt_proc_init(); + cobalt_systype_init(); +#ifdef CONFIG_COBALT_RAQ + /* we might keep the boardrev on an i2c chip */ + cobalt_i2c_init(); +#endif + cobalt_boardrev_init(); +#ifdef CONFIG_COBALT_ACPI + cobalt_acpi_init(); +#endif +#ifdef CONFIG_COBALT_LED + cobalt_net_init(); + cobalt_led_init(); +#endif +#ifdef CONFIG_COBALT_LCD + cobalt_lcd_init(); +#endif +#ifdef CONFIG_COBALT_RULER + cobalt_ruler_init(); +#endif +#ifdef CONFIG_COBALT_SERNUM + cobalt_serialnum_init(); +#endif +#ifdef CONFIG_COBALT_RAQ + /* some systems use WDT for reboot */ + cobalt_wdt_init(); +#endif +#ifdef CONFIG_COBALT_SENSORS + cobalt_sensors_init(); +#endif +#ifdef CONFIG_COBALT_FANS + cobalt_fan_init(); +#endif + + return 0; +} + +static int __init +cobalt_proc_init(void) +{ +#ifdef CONFIG_PROC_FS + proc_cobalt = proc_mkdir("cobalt", 0); + if (!proc_cobalt) { + EPRINTK("can't create /proc/cobalt\n"); + return -1; + } +#endif + + return 0; +} + +/* a function that handles the blah stuff in a simple proc read function */ +int +cobalt_gen_proc_read(char *buf, int plen, char **start, off_t pos, + int len, int *eof) +{ + /* trying to read a bad offset? */ + if (pos >= plen) { + *eof = 1; + return 0; + } + + /* did we write everything we wanted to? */ + if (len >= (plen-pos)) { + *eof = 1; + } + + *start = buf + pos; + plen -= pos; + + return (len > plen) ? plen : len; +} +EXPORT_SYMBOL(cobalt_gen_proc_read); diff -ruN linux-2.4.29/drivers/cobalt/lcd.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/lcd.c --- linux-2.4.29/drivers/cobalt/lcd.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/lcd.c 2005-03-21 17:27:16.648962116 -0700 @@ -0,0 +1,843 @@ +/* + * $Id: lcd.c,v 1.44 2002/05/10 18:44:45 duncan Exp $ + * lcd.c : driver for Cobalt LCD/Buttons + * + * Copyright 1996-2000 Cobalt Networks, Inc. + * Copyright 2001 Sun Microsystems, Inc. + * + * By: Andrew Bose + * Timothy Stonis + * Tim Hockin + * Adrian Sun + * Duncan Laurie + * + * This should be SMP safe. We're hardly performance critical, + * so we lock around lcd_ioctl() and just where needed by other external + * functions. There is a static global waiters variable that is atomic_t, and + * so should be safe. --TPH + */ + +#include + +#ifdef CONFIG_COBALT_LCD + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define TWIDDLE_HZ (HZ/10) + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define LCD_DRIVER "Cobalt Networks LCD driver" +#define LCD_DRIVER_VMAJ 4 +#define LCD_DRIVER_VMIN 0 + +/* this is the generic device minor assigned to /dev/lcd */ +#define COBALT_LCD_MINOR 156 +#define COBALT_LCD_OLD_MINOR 140 + +/* io registers */ +#define LPT 0x0378 +#define LCD_DATA_ADDRESS LPT+0 +#define LCD_CONTROL_ADDRESS LPT+2 + +/* LCD device info */ +#define LCD_Addr 0x80 +#define DD_R00 0x00 +#define DD_R01 0x27 +#define DD_R10 0x40 +#define DD_R11 0x67 + +/* driver functions */ +static int cobalt_lcd_open(struct inode *, struct file *); +static ssize_t cobalt_lcd_read(struct file *, char *, size_t, loff_t *); +static int cobalt_lcd_read_proc(char *, char **, off_t, int, int *, void *); +static char *cobalt_lcddev_read_line(int, char *); +static int cobalt_lcd_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); +static int cobalt_lcd_panic(struct notifier_block *self, unsigned long, void *); + +/* globals used throughout */ +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC +static struct proc_dir_entry *proc_lcd; +#endif +static struct proc_dir_entry *proc_clcd; +#endif +static int lcd_present; +static int has_i2c_lcd; +static spinlock_t lcd_lock = SPIN_LOCK_UNLOCKED; + +/* various file operations we support for this driver */ +static struct file_operations lcd_fops = { + owner: THIS_MODULE, + read: cobalt_lcd_read, + ioctl: cobalt_lcd_ioctl, + open: cobalt_lcd_open, +}; + +/* device structure */ +static struct miscdevice lcd_dev = { + COBALT_LCD_MINOR, + "lcd", + &lcd_fops +}; +#ifdef CONFIG_COBALT_LCD_DEV_COMPAT +/* device structure */ +static struct miscdevice lcd_compat_dev = { + COBALT_LCD_OLD_MINOR, + "lcd (compatible)", + &lcd_fops +}; +#endif + +static int disable_lcd; +static int __init +lcd_disable_setup(char *str) +{ + disable_lcd = 1; + return 0; +} +__setup("nolcd", lcd_disable_setup); + +/* Read a control instruction from the LCD */ +static inline int +lcddev_read_inst(void) +{ + int a = 0; + + if (cobt_is_5k() && has_i2c_lcd) { + a = cobalt_i2c_read_byte( + COBALT_I2C_DEV_LCD_INST | COBALT_I2C_READ, 0); + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x21, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */ + outb(0x20, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=1 */ + a = inb(LCD_DATA_ADDRESS); + outb(0x21, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */ + outb(0x01, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */ + } + + /* small delay */ + udelay(100); + + return a; +} + +#define LCD_MAX_POLL 10000 +static inline void +lcddev_poll_wait(void) +{ + int i=0; + + while (i++ < LCD_MAX_POLL) { + int r = lcddev_read_inst(); + if (r < 0 || !(r & 0x80)) + break; + } +} + +/* Write a control instruction to the LCD */ +static inline void +lcddev_write_inst(unsigned char data) +{ + lcddev_poll_wait(); + + if (cobt_is_5k() && has_i2c_lcd) { + cobalt_i2c_write_byte( + COBALT_I2C_DEV_LCD_INST | COBALT_I2C_WRITE, 0, data); + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x03, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=0 */ + outb(data, LCD_DATA_ADDRESS); + outb(0x02, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=1 */ + outb(0x03, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=0 */ + outb(0x01, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */ + } + + /* small delay */ + udelay(100); +} + +/* Write one byte of data to the LCD */ +static inline void +lcddev_write_data(unsigned char data) +{ + lcddev_poll_wait(); + + if (cobt_is_5k() && has_i2c_lcd) { + cobalt_i2c_write_byte( + COBALT_I2C_DEV_LCD_DATA | COBALT_I2C_WRITE, 0, data); + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x07, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=0 */ + outb(data, LCD_DATA_ADDRESS); + outb(0x06, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=1 */ + outb(0x07, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=0 */ + outb(0x05, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */ + } + /* small delay */ + udelay(100); +} + +/* Read one byte of data from the LCD */ +static inline unsigned char +lcddev_read_data(void) +{ + unsigned char a = 0; + + lcddev_poll_wait(); + + if (cobt_is_5k() && has_i2c_lcd) { + a = cobalt_i2c_read_byte( + COBALT_I2C_DEV_LCD_DATA | COBALT_I2C_READ, 0); + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x25, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */ + outb(0x24, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=1 */ + a = inb(LCD_DATA_ADDRESS); + outb(0x25, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */ + outb(0x01, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */ + } + + /* small delay */ + udelay(100); + + return a; +} + +static inline void +lcddev_init(void) +{ + lcddev_write_inst(0x38); + lcddev_write_inst(0x38); + lcddev_write_inst(0x38); + lcddev_write_inst(0x06); + lcddev_write_inst(0x0c); +} + +static inline char +read_buttons(void) +{ + char r = 0; + + if (cobt_is_5k() && has_i2c_lcd) { + unsigned char inst; + inst = cobalt_i2c_read_byte(COBALT_I2C_DEV_FP_BUTTONS, 0); + switch (inst) { + case 0x3e: r = BUTTON_Next_B; break; + case 0x3d: r = BUTTON_Enter_B; break; + case 0x1f: r = BUTTON_Left_B; break; + case 0x3b: r = BUTTON_Right_B; break; + case 0x2f: r = BUTTON_Up_B; break; + case 0x37: r = BUTTON_Down_B; break; + case 0x3f: + default: r = BUTTON_NONE_B; + } + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x29, LCD_CONTROL_ADDRESS); /* Sel=0, Bi=1 */ + r = inb(LCD_DATA_ADDRESS) & BUTTON_MASK; + } + + return r; +} + +static inline int +button_pressed(void) +{ + unsigned char b; + unsigned long flags; + + spin_lock_irqsave(&lcd_lock, flags); + b = read_buttons(); + spin_unlock_irqrestore(&lcd_lock, flags); + + switch (b) { + case BUTTON_Next: + case BUTTON_Next_B: + case BUTTON_Reset_B: + return b; + default: + } + + return 0; +} + +/* this could be protected by CAP_RAW_IO here, or by the FS permissions */ +static int +cobalt_lcd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct lcd_display button_display, display; + unsigned long address, a; + int index; + int dlen = sizeof(struct lcd_display); + int r = 0; + unsigned long flags; + +#ifdef CONFIG_COBALT_LCD_TWIDDLE + cobalt_lcd_stop_twiddle(); +#endif + switch (cmd) { + /* Turn the LCD on */ + case LCD_On: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x0F); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Turn the LCD off */ + case LCD_Off: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x08); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Reset the LCD */ + case LCD_Reset: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x3F); + lcddev_write_inst(0x3F); + lcddev_write_inst(0x3F); + lcddev_write_inst(0x3F); + lcddev_write_inst(0x01); + lcddev_write_inst(0x06); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Clear the LCD */ + case LCD_Clear: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x01); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Move the cursor one position to the left */ + case LCD_Cursor_Left: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x10); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Move the cursor one position to the right */ + case LCD_Cursor_Right: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x14); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Turn the cursor off */ + case LCD_Cursor_Off: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x0C); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Turn the cursor on */ + case LCD_Cursor_On: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x0F); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Turn blinking off? I don't know what this does - TJS */ + case LCD_Blink_Off: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x0E); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Get the current cursor position */ + case LCD_Get_Cursor_Pos: + spin_lock_irqsave(&lcd_lock, flags); + display.cursor_address = (unsigned char)lcddev_read_inst(); + display.cursor_address = display.cursor_address & 0x07F; + spin_unlock_irqrestore(&lcd_lock, flags); + if (copy_to_user((struct lcd_display *)arg, &display, dlen)) { + r = -EFAULT; + } + break; + + /* Set the cursor position */ + case LCD_Set_Cursor_Pos: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + a = display.cursor_address | LCD_Addr; + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(a); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Get the value at the current cursor position? - TJS */ + case LCD_Get_Cursor: + spin_lock_irqsave(&lcd_lock, flags); + display.character = lcddev_read_data(); + lcddev_write_inst(0x10); + spin_unlock_irqrestore(&lcd_lock, flags); + if (copy_to_user((struct lcd_display *)arg, &display, dlen)) { + r = -EFAULT; + } + break; + + /* Set the character at the cursor position? - TJS */ + case LCD_Set_Cursor: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_data(display.character); + lcddev_write_inst(0x10); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Dunno what this does - TJS */ + case LCD_Disp_Left: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x18); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Dunno what this does - TJS */ + case LCD_Disp_Right: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x1C); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Dunno what this does - TJS */ + case LCD_Home: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x02); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Write a string to the LCD */ + case LCD_Write: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + + spin_lock_irqsave(&lcd_lock, flags); + + display.size1 = display.size1 > 0 ? + min(display.size1, (int) sizeof(display.line1)) : 0; + display.size2 = display.size2 > 0 ? + min(display.size2, (int) sizeof(display.line2)) : 0; + + /* First line */ + lcddev_write_inst(0x80); + for (index = 0; index < display.size1; index++) + lcddev_write_data(display.line1[index]); + for (index = display.size1; index < sizeof(display.line1); index++) + lcddev_write_data(' '); + + /* Second line */ + lcddev_write_inst(0xC0); + for (index = 0; index < display.size2; index++) + lcddev_write_data(display.line2[index]); + for (index = display.size2; index < sizeof(display.line2); index++) + lcddev_write_data(' '); + + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Read what's on the LCD */ + case LCD_Read: + spin_lock_irqsave(&lcd_lock, flags); + + for (address = DD_R00; address <= DD_R01; address++) { + lcddev_write_inst(address | LCD_Addr); + display.line1[address] = lcddev_read_data(); + } + for (address = DD_R10; address <= DD_R11; address++) { + lcddev_write_inst(address | LCD_Addr); + display.line2[address - DD_R10] = lcddev_read_data(); + } + + spin_unlock_irqrestore(&lcd_lock, flags); + + display.line1[DD_R01] = '\0'; + display.line2[DD_R01] = '\0'; + + if (copy_to_user((struct lcd_display *)arg, &display, dlen)) { + r = -EFAULT; + } + break; + + case LCD_Raw_Inst: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(display.character); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + case LCD_Raw_Data: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_data(display.character); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + case LCD_Type: + if (cobt_is_5k() && has_i2c_lcd) { + if (put_user(LCD_TYPE_I2C, (int *)arg)) { + r = -EFAULT; + } + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + if (put_user(LCD_TYPE_PARALLEL_B, (int *)arg)) { + r = -EFAULT; + } + } + break; + + /* Read the buttons */ + case BUTTON_Read: + spin_lock_irqsave(&lcd_lock, flags); + button_display.buttons = read_buttons(); + spin_unlock_irqrestore(&lcd_lock, flags); + if (copy_to_user((struct lcd_display *)arg, + &button_display, dlen)) { + r = -EFAULT; + } + break; + +#ifdef CONFIG_COBALT_LED + /* a slightly different api that allows you to set 32 leds */ + case LED32_Set: + cobalt_led_set_lazy(arg); + break; + + case LED32_Bit_Set: + cobalt_led_set_bits_lazy(arg); + break; + + case LED32_Bit_Clear: + cobalt_led_clear_bits_lazy(arg); + break; + + case LED32_Get: + *(unsigned int *)arg = cobalt_led_get(); + break; + + /* set all the leds */ + case LED_Set: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + cobalt_led_set_lazy(display.leds); + break; + + /* set a single led */ + case LED_Bit_Set: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + cobalt_led_set_bits_lazy(display.leds); + break; + + /* clear an led */ + case LED_Bit_Clear: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + cobalt_led_clear_bits_lazy(display.leds); + break; +#endif + + default: + } + + return r; +} + +static int +cobalt_lcd_open(struct inode *inode, struct file *file) +{ + if (!lcd_present) { + return -ENXIO; + } else { + return 0; + } +} + +/* LCD daemon sits on this, we wake it up once a key is pressed */ +static ssize_t +cobalt_lcd_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + int bnow; + static unsigned long lcd_waiters; + + if (test_and_set_bit(0, &lcd_waiters)) { + return -EINVAL; + } + + while (((bnow = button_pressed()) == 0) && !(signal_pending(current))) { + if (file->f_flags & O_NONBLOCK) { + lcd_waiters = 0; + return -EAGAIN; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2 * HZ); + } + lcd_waiters = 0; + + if (signal_pending(current)) { + return -ERESTARTSYS; + } + + return bnow; +} + +/* read a single line from the LCD into a string */ +static char * +cobalt_lcddev_read_line(int lineno, char *line) +{ + unsigned long addr, min, max; + unsigned long flags; + + switch (lineno) { + case 0: + min = DD_R00; + max = DD_R01; + break; + case 1: + min = DD_R10; + max = DD_R11; + break; + default: + min = 1; + max = 0; + } + + spin_lock_irqsave(&lcd_lock, flags); + for (addr = min; addr <= max; addr++) { + lcddev_write_inst(addr | LCD_Addr); + udelay(150); + line[addr-min] = lcddev_read_data(); + udelay(150); + } + spin_unlock_irqrestore(&lcd_lock, flags); + line[addr-min] = '\0'; + + return line; +} + +#ifdef CONFIG_PROC_FS +static int +cobalt_lcd_read_proc(char *buf, char **start, off_t pos, + int len, int *eof, void *private) +{ + int plen = 0; + char line[COBALT_LCD_LINELEN+1]; + + /* first line */ + cobalt_lcddev_read_line(0, line); + plen += sprintf(buf+plen, "%s\n", line); + + /* second line */ + cobalt_lcddev_read_line(1, line); + plen += sprintf(buf+plen, "%s\n", line); + + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} +#endif + +static char *lcd_panic_str1 = "Kernel"; +static char *lcd_panic_str2 = "Panic!"; + +static int cobalt_lcd_panic(struct notifier_block *self, unsigned long a, void *b) +{ + int i; + int len; + + if( !lcd_present ) + return 0; + +#ifdef CONFIG_COBALT_LCD_TWIDDLE + cobalt_lcd_stop_twiddle(); +#endif + + lcddev_write_inst( (DD_R00) | LCD_Addr); + len = strlen( lcd_panic_str1 ); + for( i=0 ; i<16 ; i++ ) + lcddev_write_data( (i 11) { + state = -1; + pos = 10; + } + + lcddev_write_inst((DD_R10+4+pos) | LCD_Addr); + lcddev_write_data(0xff); + + spin_unlock_irqrestore(&lcd_lock, flags); + + mod_timer(&twiddle_timer, jiffies + TWIDDLE_HZ); +} + +void +cobalt_lcd_start_twiddle(void) +{ + init_timer(&twiddle_timer); + twiddle_timer.expires = jiffies + TWIDDLE_HZ; + twiddle_timer.data = 0; + twiddle_timer.function = &twiddle_timer_func; + add_timer(&twiddle_timer); + twiddling=1; +} + +void +cobalt_lcd_stop_twiddle(void) +{ + unsigned int flags; + + spin_lock_irqsave(&lcd_lock, flags); + if (twiddling) { + del_timer_sync(&twiddle_timer); + twiddling = 0; + } + spin_unlock_irqrestore(&lcd_lock, flags); +} +#endif /* CONFIG_COBALT_LCD_TWIDDLE */ + +/* stop the lcd */ +void cobalt_lcd_off(void) +{ + unsigned int flags; + + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x01); /* clear */ + lcddev_write_inst(0x08); /* off */ + spin_unlock_irqrestore(&lcd_lock, flags); +} + +static int initialized; +static struct notifier_block lcd_nb; + +int __init +cobalt_lcd_init(void) +{ + if (initialized) + return 0; + + initialized=1; + + if (disable_lcd) { + printk(KERN_INFO "%s DISABLED\n", LCD_DRIVER); + return 0; + } + + misc_register(&lcd_dev); +#ifdef CONFIG_COBALT_LCD_DEV_COMPAT + misc_register(&lcd_compat_dev); +#endif + + if (cobt_is_monterey() + && (cobalt_i2c_read_byte(COBALT_I2C_DEV_LCD_INST, 0) != 0xff)) { + has_i2c_lcd = 1; + } else { + has_i2c_lcd = 0; + } + + /* flag ourselves as present */ + lcd_present = 1; + + /* initialize the device */ + lcddev_init(); + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + /* create /proc/lcd */ + proc_lcd = create_proc_read_entry("lcd", S_IRUSR, NULL, + cobalt_lcd_read_proc, NULL); + if (!proc_lcd) { + EPRINTK("can't create /proc/lcd\n"); + } +#endif + proc_clcd = create_proc_read_entry("lcd", S_IRUSR, proc_cobalt, + cobalt_lcd_read_proc, NULL); + if (!proc_clcd) { + EPRINTK("can't create /proc/cobalt/lcd\n"); + } +#endif + +#ifdef CONFIG_COBALT_LCD_TWIDDLE + cobalt_lcd_start_twiddle(); +#endif + + /* register panic notifier */ + lcd_nb.notifier_call = cobalt_lcd_panic; + lcd_nb.next = NULL; + lcd_nb.priority = 0; + + notifier_chain_register( &panic_notifier_list, &lcd_nb ); + + return 0; +} + +#endif /* CONFIG_COBALT_LCD */ diff -ruN linux-2.4.29/drivers/cobalt/led.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/led.c --- linux-2.4.29/drivers/cobalt/led.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/led.c 2005-03-21 17:27:16.649961967 -0700 @@ -0,0 +1,502 @@ +/* + * $Id: led.c,v 1.36 2002/05/10 18:44:45 duncan Exp $ + * led.c : driver for Cobalt LEDs + * + * Copyright 1996-2000 Cobalt Networks, Inc. + * Copyright 2001 Sun Microsystems, Inc. + * + * By: Andrew Bose + * Timothy Stonis + * Tim Hockin + * Adrian Sun + * Duncan Laurie + * + * This should be SMP safe. There is one definite critical region: the + * handler list (led_handler_lock). The led_state is protected by led_lock, + * so should be safe against simultaneous writes. Bit banging of lights is + * currently also a protected region (led_lock, rather than add a new lock). + */ + +#include + +#ifdef CONFIG_COBALT_LED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include +#include +#include +#include +#include + +#define LED_DRIVER "Cobalt Networks LED driver" +#define LED_DRIVER_VMAJ 1 +#define LED_DRIVER_VMIN 0 + +/* the rate at which software controlled frontpanel LEDs blink */ +#define FPLED_DEFAULT_HZ (HZ/20) + +/* + * This is the abstracted state of active LEDs - see the defines for LED_* + * LED masks are always 'unsigned int'. You must hold led_lock to muck with + * these. + */ +static unsigned int led_state; +static unsigned int led_blips; + +/* leds are PCI on genIII */ +static struct pci_dev *led_dev; +/* on XTR the front panel LEDs are software controlled */ +struct led_handler { + unsigned int (*function)(void *); + void *data; + struct led_handler *next; + struct led_handler *prev; +}; +struct led_handler *led_handler_list; +static spinlock_t led_handler_lock = SPIN_LOCK_UNLOCKED; +static struct timer_list timer; + +static spinlock_t led_lock = SPIN_LOCK_UNLOCKED; + +/* + * RaQ 3 + * RaQ 4 + * Qube 3 + */ +#define RAQ3_SHUTLOGO_ADDR 0x7e +#define RAQ3_SHUTDOWN_OFF 0x40 /* reverse polarity */ +#define RAQ3_COBALTLOGO_ON 0x80 +#define QUBE3_LIGHTBAR_ON 0xc0 /* direct polarity */ +#define RAQ3_WEBLIGHT_ADDR 0xb8 +#define RAQ3_WEBLIGHT_ON 0x80 + +/* + * RaQ XTR + */ +#define MONTEREY_FPLED00 0x8000 +#define MONTEREY_FPLED01 0x4000 +#define MONTEREY_FPLED02 0x2000 +#define MONTEREY_FPLED03 0x0200 +#define MONTEREY_FPLED04 0x0080 +#define MONTEREY_FPLED05 0x0040 +#define MONTEREY_FPLED10 0x1000 +#define MONTEREY_FPLED11 0x0800 +#define MONTEREY_FPLED12 0x0400 +#define MONTEREY_FPLED13 0x0100 +#define MONTEREY_FPLED14 0x0020 +#define MONTEREY_FPLED15 0x0010 +#define MONTEREY_FPLED_ETH0_TXRX MONTEREY_FPLED00 +#define MONTEREY_FPLED_ETH0_LINK MONTEREY_FPLED10 +#define MONTEREY_FPLED_ETH1_TXRX MONTEREY_FPLED01 +#define MONTEREY_FPLED_ETH1_LINK MONTEREY_FPLED11 +#define MONTEREY_FPLED_DISK0 MONTEREY_FPLED02 +#define MONTEREY_FPLED_DISK1 MONTEREY_FPLED03 +#define MONTEREY_FPLED_DISK2 MONTEREY_FPLED04 +#define MONTEREY_FPLED_DISK3 MONTEREY_FPLED05 +#define MONTEREY_FPLED_WEB MONTEREY_FPLED12 +#define MONTEREY_LOGOLED_BIT 0x40 +#define MONTEREY_SYSFAULTLED_BIT 0x80 +#define MONTEREY_SLED0 (1<<3) +#define MONTEREY_SLED1 (1<<2) +#define MONTEREY_SLED2 (1<<1) +#define MONTEREY_SLED3 (1<<0) + +/* + * Alpine + */ +#define ALPINE_WEBLED_PORT 0x60e +#define ALPINE_WEBLED_BIT 0x20 +#define ALPINE_POWERLED_PORT 0x50b +#define ALPINE_POWERLED_CFG 0x23 +#define ALPINE_LOGOLED_BIT 0x02 +#define ALPINE_SYSFAULTLED_BIT 0x07 + +/* + * actually set the leds (icky details hidden within) + * this must be protected against itself with led_lock + * */ +static void +__set_led_hw(const unsigned int newstate) +{ + if (cobt_is_pacifica() && led_dev) { + unsigned char tmp; + /* RaQ 3, RaQ 4 + * - shutdown light + * - logo light + * - web light + */ + + /* read the current state of shutdown/logo lights */ + pci_read_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, &tmp); + + /* reverse polarity for shutdown light */ + if (newstate & LED_SHUTDOWN) + tmp &= ~RAQ3_SHUTDOWN_OFF; + else + tmp |= RAQ3_SHUTDOWN_OFF; + + /* logo light is straight forward */ + if (newstate & LED_COBALTLOGO) + tmp |= RAQ3_COBALTLOGO_ON; + else + tmp &= ~RAQ3_COBALTLOGO_ON; + + /* write new shutdown/logo light state */ + pci_write_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, tmp); + + /* read web light state */ + pci_read_config_byte(led_dev, RAQ3_WEBLIGHT_ADDR, &tmp); + if (newstate & LED_WEBLIGHT) { + tmp |= RAQ3_WEBLIGHT_ON; + } else { + tmp &= ~RAQ3_WEBLIGHT_ON; + } + + /* write new web light state */ + pci_write_config_byte(led_dev, RAQ3_WEBLIGHT_ADDR, tmp); + } else if (cobt_is_carmel() && led_dev) { + unsigned char tmp; + /* Qube 3 + * - no shutdown light + * - lightbar instead of logo + * - no web led (wired to 2nd IDE reset for staggered startup) + */ + + /* read the current state of lightbar */ + pci_read_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, &tmp); + if (newstate & LED_COBALTLOGO) { + tmp |= QUBE3_LIGHTBAR_ON; + } else { + tmp &= ~QUBE3_LIGHTBAR_ON; + } + + /* write new lightbar state */ + pci_write_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, tmp); + } else if (cobt_is_monterey()) { + unsigned int tmp = 0; + u8 val; + unsigned long flags; + + if (newstate & LED_WEBLIGHT) { + tmp |= MONTEREY_FPLED_WEB; + } + if (newstate & LED_ETH0_TXRX) { + tmp |= MONTEREY_FPLED_ETH0_TXRX; + } + if (newstate & LED_ETH0_LINK) { + tmp |= MONTEREY_FPLED_ETH0_LINK; + } + if (newstate & LED_ETH1_TXRX) { + tmp |= MONTEREY_FPLED_ETH1_TXRX; + } + if (newstate & LED_ETH1_LINK) { + tmp |= MONTEREY_FPLED_ETH1_LINK; + } + if (newstate & LED_DISK0) { + tmp |= MONTEREY_FPLED_DISK0; + } + if (newstate & LED_DISK1) { + tmp |= MONTEREY_FPLED_DISK1; + } + if (newstate & LED_DISK2) { + tmp |= MONTEREY_FPLED_DISK2; + } + if (newstate & LED_DISK3) { + tmp |= MONTEREY_FPLED_DISK3; + } + /* 3 LED's are unused on Monterey, but we support them */ + if (newstate & LED_MONTEREY_UNUSED0) { + tmp |= MONTEREY_FPLED13; + } + if (newstate & LED_MONTEREY_UNUSED1) { + tmp |= MONTEREY_FPLED14; + } + if (newstate & LED_MONTEREY_UNUSED2) { + tmp |= MONTEREY_FPLED15; + } + /* I2C controlled front-panel lights */ + cobalt_i2c_write_byte(COBALT_I2C_DEV_LED_I, 0, tmp & 0xff); + cobalt_i2c_write_byte(COBALT_I2C_DEV_LED_II, 0, tmp >> 8); + + /* drive sled LEDs are on a different i2c device */ + tmp = 0xf0; /* high nibble means something else */ + if (newstate * LED_SLED0) + tmp |= MONTEREY_SLED0; + if (newstate * LED_SLED1) + tmp |= MONTEREY_SLED1; + if (newstate * LED_SLED2) + tmp |= MONTEREY_SLED2; + if (newstate * LED_SLED3) + tmp |= MONTEREY_SLED3; + cobalt_i2c_write_byte(COBALT_I2C_DEV_RULER, 0, tmp); + +#if 0 + /* sysfault and logo are in APC page of nvram */ + spin_lock_irqsave(&rtc_lock, flags); + superio_set_rtc_bank(PC87317_RTC_BANK_APC); + val = CMOS_READ(PC87317_APCR4); + + /* reverse polarity */ + if (newstate & LED_COBALTLOGO) { + val &= ~MONTEREY_LOGOLED_BIT; /* logo is on */ + } else { + val |= MONTEREY_LOGOLED_BIT; /* logo is off */ + } + + if (newstate & LED_SYSFAULT) { + val |= MONTEREY_SYSFAULTLED_BIT; + } else { + val &= ~MONTEREY_SYSFAULTLED_BIT; + } + + CMOS_WRITE(val, PC87317_APCR4); + superio_set_rtc_bank(PC87317_RTC_BANK_MAIN); + spin_unlock_irqrestore(&rtc_lock, flags); +#endif + } else if (cobt_is_alpine()) { + unsigned char val; + + /* web LED is reverse polarity */ + val = inb(ALPINE_WEBLED_PORT); + if (newstate & LED_WEBLIGHT) { + val &= ~ALPINE_WEBLED_BIT; + } else { + val |= ALPINE_WEBLED_BIT; + } + outb(val, ALPINE_WEBLED_PORT); + + /* + * the power led is controled by switching the pin between + * a GPIO pin (on) and a LED pin (off) + */ + + outb( ALPINE_POWERLED_CFG, 0x2e ); + val = inb( 0x2f ); + if (newstate & LED_COBALTLOGO) { + val &= ~ALPINE_LOGOLED_BIT; + } else { + val |= ALPINE_LOGOLED_BIT; + } + outb( val, 0x2f ); + + if (newstate & LED_SYSFAULT) { + val = ALPINE_SYSFAULTLED_BIT; + } else { + val = 0; + } + + outb(val, ALPINE_POWERLED_PORT); + } +} + +/* blip the front panel leds */ +static void +led_timer_func(unsigned long data) +{ + unsigned int leds = 0; + struct led_handler *p; + unsigned long flags; + + /* call all registered callbacks */ + spin_lock_irqsave(&led_handler_lock, flags); + for (p = led_handler_list; p; p = p->next) { + leds |= p->function(p->data); + } + spin_unlock_irqrestore(&led_handler_lock, flags); + + /* set the led hardware */ + spin_lock_irqsave(&led_lock, flags); + __set_led_hw(led_state | leds | led_blips); + led_blips = 0; + spin_unlock_irqrestore(&led_lock, flags); + + /* re-arm ourself */ + mod_timer(&timer, jiffies + FPLED_DEFAULT_HZ); +} + +static void +__cobalt_led_set(const unsigned int leds) +{ + led_state = leds; + __set_led_hw(leds); +} + +void +cobalt_led_set(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set(leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +void +cobalt_led_set_bits(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set(led_state | leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +void +cobalt_led_clear_bits(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set(led_state & ~leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +static void +__cobalt_led_set_lazy(const unsigned int leds) +{ + /* the next led timer run will catch these changes */ + led_state = leds; + /* remember lights that were 'blipped' to force an edge */ + led_blips |= leds; +} + +void +cobalt_led_set_lazy(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set_lazy(leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +void +cobalt_led_set_bits_lazy(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set_lazy(led_state | leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +void +cobalt_led_clear_bits_lazy(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set_lazy(led_state & ~leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +unsigned int +cobalt_led_get(void) +{ + unsigned int r; + unsigned long flags; + + spin_lock_irqsave(&led_lock, flags); + r = led_state; + spin_unlock_irqrestore(&led_lock, flags); + + return r; +} + +int +cobalt_fpled_register(unsigned int (*function)(void *), void *data) +{ + struct led_handler *newh; + unsigned long flags; + + newh = kmalloc(sizeof(*newh), GFP_ATOMIC); + if (!newh) { + EPRINTK("can't allocate memory for handler %p(%p)\n", + function, data); + return -1; + } + + spin_lock_irqsave(&led_handler_lock, flags); + + /* head insert */ + newh->function = function; + newh->data = data; + newh->next = led_handler_list; + newh->prev = NULL; + if (led_handler_list) { + led_handler_list->prev = newh; + } + led_handler_list = newh; + + spin_unlock_irqrestore(&led_handler_lock, flags); + + return 0; +} + +int +cobalt_fpled_unregister(unsigned int (*function)(void *), void *data) +{ + int r = -1; + struct led_handler *p; + unsigned long flags; + + spin_lock_irqsave(&led_handler_lock, flags); + + for (p = led_handler_list; p; p = p->next) { + if (p->function == function && p->data == data) { + if (p->prev) { + p->prev->next = p->next; + } + if (p->next) { + p->next->prev = p->prev; + } + r = 0; + break; + } + } + + spin_unlock_irqrestore(&led_handler_lock, flags); + + return r; +} + +int __init +cobalt_led_init(void) +{ + unsigned int leds = LED_SHUTDOWN | LED_COBALTLOGO; + + if (cobt_is_3k()) { + /* LEDs for RaQ3/4 and Qube3 are on the PMU */ + led_dev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M7101, NULL); + if (!led_dev) { + EPRINTK("can't find PMU for LED control\n"); + return -1; + } + } + + /* setup up timer for fp leds */ + init_timer(&timer); + timer.expires = jiffies + FPLED_DEFAULT_HZ; + timer.data = 0; + timer.function = &led_timer_func; + add_timer(&timer); + + /* set the initial state */ + leds |= cobalt_cmos_read_flag(COBT_CMOS_SYSFAULT_FLAG) ? + LED_SYSFAULT : 0; + led_state = leds; + __set_led_hw(leds); + + return 0; +} + +#endif /* CONFIG_COBALT_LED */ diff -ruN linux-2.4.29/drivers/cobalt/net.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/net.c --- linux-2.4.29/drivers/cobalt/net.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/net.c 2005-03-21 17:27:16.649961967 -0700 @@ -0,0 +1,133 @@ +/* + * cobalt net wrappers + * Copyright (c) 2000, Cobalt Networks, Inc. + * Copyright (c) 2001, Sun Microsystems, Inc. + * $Id: net.c,v 1.11 2001/10/27 00:40:24 thockin Exp $ + * author: thockin@sun.com + * + * This should be SMP safe. The only critical data is the list of devices. + * The LED handler runs at timer-interrupt, so we must use the IRQ safe forms + * of the locks. --TPH + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_COBT_NETDEVS 2 +static struct net_device *netdevs[MAX_COBT_NETDEVS]; +static int n_netdevs; +static spinlock_t cobaltnet_lock = SPIN_LOCK_UNLOCKED; + +#if defined(CONFIG_COBALT_LED) +static unsigned int +net_led_handler(void *data) +{ + int i; + unsigned int leds = 0; + static int txrxmap[MAX_COBT_NETDEVS] = {LED_ETH0_TXRX, LED_ETH1_TXRX}; + static int linkmap[MAX_COBT_NETDEVS] = {LED_ETH0_LINK, LED_ETH1_LINK}; + unsigned long flags; + static unsigned long net_old[MAX_COBT_NETDEVS]; + + spin_lock_irqsave(&cobaltnet_lock, flags); + + for (i = 0; i < n_netdevs; i++) { + unsigned long txrxstate; + struct net_device *dev = netdevs[i]; + if (!dev) { + continue; + } + /* check for link */ + if (netif_running(dev) && netif_carrier_ok(dev)) { + leds |= linkmap[i]; + } + /* check for tx/rx */ + txrxstate = dev->trans_start ^ dev->last_rx; + if (txrxstate != net_old[i]) { + leds |= txrxmap[i]; + net_old[i] = txrxstate; + } + } + + spin_unlock_irqrestore(&cobaltnet_lock, flags); + + return leds; +} +#endif + +/* + * We try to be VERY explicit here. Fine for now, may eventually break down. + */ +void +cobalt_net_register(struct net_device *ndev) +{ + unsigned long flags; + int i; + + if (!ndev) { + return; + } + + /* we'll track the first MAX_COBT_NETDEVS NICs */ + if (n_netdevs >= MAX_COBT_NETDEVS) { + return; + } + + spin_lock_irqsave(&cobaltnet_lock, flags); + + /* find a free slot */ + for (i = 0; i < MAX_COBT_NETDEVS; i++) { + if (!netdevs[i]) { + netdevs[i] = ndev; + n_netdevs++; + break; + } + } + + spin_unlock_irqrestore(&cobaltnet_lock, flags); +} + +void +cobalt_net_unregister(struct net_device *ndev) +{ + int i; + unsigned long flags; + + if (!ndev) { + return; + } + + spin_lock_irqsave(&cobaltnet_lock, flags); + + /* try to remove it from the list */ + for (i = 0; i < MAX_COBT_NETDEVS; i++) { + if (netdevs[i] == ndev) { + netdevs[i] = NULL; + n_netdevs--; + break; + } + } + + spin_unlock_irqrestore(&cobaltnet_lock, flags); +} + +int __init +cobalt_net_init(void) +{ +#if defined(CONFIG_COBALT_LED) + /* register an LED handler */ + cobalt_fpled_register(net_led_handler, NULL); +#endif + + return 0; +} diff -ruN linux-2.4.29/drivers/cobalt/raminfo.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/raminfo.c --- linux-2.4.29/drivers/cobalt/raminfo.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/raminfo.c 2005-03-21 17:27:16.650961818 -0700 @@ -0,0 +1,312 @@ +/* $Id: raminfo.c,v 1.7 2001/10/29 22:21:36 thockin Exp $ + * + * Copyright (c) 2000-2001 Sun Microsystems, Inc. + * All Rights Reserved. + * + * This is SMP safe - the init runs once on load, and the rest is just + * printing information. --TPH + */ +#include + +#if defined(CONFIG_COBALT_RAMINFO) || defined(CONFIG_COBALT_RAMINFO_MODULE) + +#include +#include +#include +#include + +#include +#include + +#define MAX_DIMM_SLOTS 4 + +enum dimm_t { + DIMM_TYPE_FPM_DRAM, + DIMM_TYPE_EDO_DRAM, + DIMM_TYPE_REG_SDRAM, + DIMM_TYPE_SDRAM +}; + +static char *dimm_desc[] = { + "Fast-page Mode DRAM", + "EDO DRAM", + "Registered SDRAM", + "SDRAM", +}; + +struct dimm_slot { + int num; + enum dimm_t type; + uint16_t size; + int ecc; +}; + +struct raminfo { + int total; + int (*query)(struct dimm_slot *); + struct pci_dev *dev; + struct dimm_slot *dimm; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc; +#endif /* CONFIG_PROC_FS */ +}; + +/*########################################################################*/ + +static int serverworks_le_dimm_info(struct dimm_slot *); +static int ali_1541_dimm_info(struct dimm_slot *); +static int raminfo_read_proc(char*, char**, off_t, int, int*, void*); + +/* RaQ-3, RaQ-4, Qube-3 + * - uses ALI M1541 for memory controller + * - has 2 dimm slots */ +static struct raminfo gen3_raminfo = { + total: 2, + query: ali_1541_dimm_info +}; +/* RaQ-XTR (Monterey) + * - uses ServerWorks CNB30LE for Memory Controller + * - has 4 dimm slots */ +static struct raminfo gen5_monterey_raminfo = { + total: 4, + query: serverworks_le_dimm_info +}; +/* RaQ (Alpine) + * - uses ServerWorks CNB30LE for Memory Controller + * - has 2 dimm slots */ +static struct raminfo gen5_alpine_raminfo = { + total: 2, + query: serverworks_le_dimm_info +}; + +static struct raminfo *sys_raminfo; + +/*########################################################################*/ + +#define SERVERWORKS_DRAM_MRPR (0x90) +#define SERVERWORKS_DRAM_MRAR(slot) (0x7c + (slot)) +#define SERVERWORKS_DRAM_ECCR (0xe0) + +static int +serverworks_le_dimm_info(struct dimm_slot *dimm) +{ + int row; + uint8_t rar, active, eccr; + uint16_t ma_map[] = { + 32, 16, 32, 256, 512, 128, 128, 64, 256, 128, 64, 64, 128, + }; + + if (!sys_raminfo || !sys_raminfo->dev || !dimm) + return -ENOSYS; + + pci_read_config_byte(sys_raminfo->dev, + SERVERWORKS_DRAM_MRPR, &active); + pci_read_config_byte(sys_raminfo->dev, + SERVERWORKS_DRAM_MRAR(dimm->num), &rar); + + /* serverworks uses only registered sdram */ + dimm->type = DIMM_TYPE_REG_SDRAM; + dimm->size = 0; + + /* check to see if ECC is enabled (bit 4 of reg 0xE0) */ + pci_read_config_byte(sys_raminfo->dev, + SERVERWORKS_DRAM_ECCR, &eccr); + dimm->ecc = (eccr & (1<<2)) ? 1 : 0; + + /* two rows for each dimm slot */ + for (row=2*dimm->num; row<=(2*dimm->num+1); row++) { + /* each active row will have corresponding bit + * set in the Memory Row Presence Register */ + if (active & (1 << row)) { + /* lookup size ma_map table */ + dimm->size += ma_map[ rar & 0xf ]; + } + /* two rows per RAR register, bits 7-4 and bits 3-0 */ + rar >>= 4; + } + + return 0; +} + +#define ALI_DRAM_CONF_1(row) (0x60 + ((row) * 2)) +#define ALI_DRAM_CONF_2(row) (0x61 + ((row) * 2)) +#define ALI_DIMM_TYPE(d2) (((d2) >> 4) & 0x3) +#define ALI_DIMM_MMAP(d2) (((d2) >> 6) & 0x3) +#define ALI_DIMM_SIZE(d1, d2) (((((d2) & 0xf) << 8) | (d1)) + 1) + +static int +ali_1541_dimm_info(struct dimm_slot *dimm) +{ + int row; + uint8_t dbc1, dbc2; + + if (!sys_raminfo || !sys_raminfo->dev || !dimm) + return -ENOSYS; + + dimm->size = 0; + dimm->ecc = 0; + + /* read two rows per dimm (for double-side) */ + for (row=2*dimm->num; row<=(2*dimm->num + 1); row++) { + pci_read_config_byte(sys_raminfo->dev, + ALI_DRAM_CONF_2(row), &dbc2); + + /* row is empty iff dimm type and ma_map are both 0 */ + if (!ALI_DIMM_TYPE(dbc2) && !ALI_DIMM_MMAP(dbc2)) + continue; + + pci_read_config_byte(sys_raminfo->dev, + ALI_DRAM_CONF_1(row), &dbc1); + + /* type is bits 4-5 of dimm conf reg 2 */ + dimm->type = ALI_DIMM_TYPE(dbc2); + + /* A27-A20 address lines are bits 7-0 of dimm conf reg 1 + * A31-A28 address lines are bits 3-0 of dimm conf reg 2 */ + dimm->size = ALI_DIMM_SIZE(dbc1, dbc2); + } + + /* the M1541 uses "not less than" policy to determine which row a + * memory address resides in. the top address boundary for each + * row is the maximum memory value minus 1. so to determine the + * size of a row you must subtract the size of the previous row. + * (unless this is slot 0 or the first populated slot) */ + if (dimm->num > 0 && dimm->size > 0) { + uint16_t sz; + pci_read_config_byte(sys_raminfo->dev, + ALI_DRAM_CONF_1(2*dimm->num - 1), &dbc1); + pci_read_config_byte(sys_raminfo->dev, + ALI_DRAM_CONF_2(2*dimm->num - 1), &dbc2); + sz = ALI_DIMM_SIZE(dbc1, dbc2); + dimm->size -= (sz > 1) ? sz : 0; + } + + return 0; +} + +int __init +cobalt_raminfo_init(void) +{ + int j; + + /* determine system type and find memory controller pci dev + * so we don't have to do pci lookup for each proc read */ + if (cobt_is_3k()) { + sys_raminfo = &gen3_raminfo; + sys_raminfo->dev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M1541, NULL); + } else if (cobt_is_5k()) { + if (cobt_is_monterey()) { + sys_raminfo = &gen5_monterey_raminfo; + } else if (cobt_is_alpine()) { + sys_raminfo = &gen5_alpine_raminfo; + } else { + EPRINTK("unable to identify gen5 board\n"); + return -ENOSYS; + } + sys_raminfo->dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_LE, NULL); + } + + if (!sys_raminfo || !sys_raminfo->dev) { + EPRINTK("unable to identify system type\n"); + return -ENOSYS; + } + +#ifdef CONFIG_PROC_FS + /* add entry to /proc filesytem */ + sys_raminfo->proc = create_proc_entry("raminfo", + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, proc_cobalt); + if (!sys_raminfo->proc) { + EPRINTK("can't create /proc/cobalt/raminfo\n"); + return -ENOENT; + } + sys_raminfo->proc->owner = THIS_MODULE; + sys_raminfo->proc->write_proc = NULL; + sys_raminfo->proc->read_proc = raminfo_read_proc; +#endif /* CONFIG_PROC_FS */ + + /* create arrary of dimm slots to store info */ + sys_raminfo->dimm = kmalloc( + sys_raminfo->total * sizeof(struct dimm_slot), GFP_ATOMIC); + if (!sys_raminfo->dimm) { + EPRINTK("unable to allocate memory\n"); +#ifdef CONFIG_PROC_FS + if (sys_raminfo->proc) { + remove_proc_entry("raminfo", proc_cobalt); + sys_raminfo->proc = NULL; + } +#endif /* CONFIG_PROC_FS */ + return -ENOMEM; + } + + { + struct dimm_slot *ds = sys_raminfo->dimm; + for (j=0; jtotal; j++, ds++) { + if (!ds) continue; + ds->num = j; + if (sys_raminfo->query(ds) < 0) { + EPRINTK("unable to read dimm %d\n", j); + ds->num = -1; + } + } + } + + return 0; +} + +static void __exit +cobalt_raminfo_exit(void) +{ +#ifdef CONFIG_PROC_FS + if (sys_raminfo->proc) { + remove_proc_entry("raminfo", proc_cobalt); + sys_raminfo->proc = NULL; + } +#endif /* CONFIG_PROC_FS */ + + if (sys_raminfo->dimm) { + kfree(sys_raminfo->dimm); + sys_raminfo->dimm = NULL; + } + + sys_raminfo->dev = NULL; + sys_raminfo = NULL; +} + +#ifdef CONFIG_PROC_FS +static int +raminfo_read_proc(char *buf, char **st, off_t off, int len, int *eof, void *x) +{ + int rlen, i; + struct dimm_slot *ds; + + if (!sys_raminfo) + return -ENOSYS; + + MOD_INC_USE_COUNT; + + ds = sys_raminfo->dimm; + for (rlen=i=0; itotal; i++, ds++) { + if (!ds || ds->num < 0) + continue; + rlen += sprintf(buf+rlen, "%d [%s%s]: %u MB\n", i, + ds->size ? dimm_desc[ds->type] : "Empty", + ds->size ? ds->ecc ? "+ECC" : "" : "", + ds->size); + } + + MOD_DEC_USE_COUNT; + + return cobalt_gen_proc_read(buf, rlen, st, off, len, eof); +} +#endif /* CONFIG_PROC_FS */ + +module_init(cobalt_raminfo_init); +module_exit(cobalt_raminfo_exit); + +MODULE_AUTHOR("Sun Cobalt"); +MODULE_DESCRIPTION("DIMM Information"); +MODULE_LICENSE("GPL"); + +#endif /* CONFIG_COBALT_RAMINFO || CONFIG_COBALT_RAMINFO_MODULE */ diff -ruN linux-2.4.29/drivers/cobalt/ruler.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/ruler.c --- linux-2.4.29/drivers/cobalt/ruler.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/ruler.c 2005-03-21 17:27:16.651961670 -0700 @@ -0,0 +1,407 @@ +/* + * cobalt ruler driver + * Copyright (c) 2000, Cobalt Networks, Inc. + * Copyright (c) 2001, Sun Microsystems, Inc. + * $Id: ruler.c,v 1.23 2002/08/29 00:33:01 uzi Exp $ + * + * author: asun@cobalt.com, thockin@sun.com + * + * This should be SMP safe. There is one critical piece of data, and thus + * one lock. The ruler_lock protects the arrays of channels(hwifs) and + * busproc function pointers. These are only ever written in the + * register/unregister functions but read in several other places. A + * read/write lock is appropriate. The global switches and sled_leds are + * atomic_t. --TPH + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#define RULER_TIMEOUT (HZ >> 1) /* .5s */ +#define MAX_COBT_DRIVES 4 + +/* all of this is for gen V */ +static struct timer_list cobalt_ruler_timer; +static rwlock_t ruler_lock = RW_LOCK_UNLOCKED; +static ide_hwif_t *channels[MAX_COBT_DRIVES]; +static ide_busproc_t *busprocs[MAX_COBT_DRIVES]; +/* NOTE: switches is a bitmask of DETACHED sleds */ +static atomic_t switches = ATOMIC_INIT(0); +static atomic_t sled_leds = ATOMIC_INIT(0); +static int sled_led_map[] = {LED_SLED0, LED_SLED1, LED_SLED2, LED_SLED3}; +static int ruler_detect; +static int initialized; + +static void ruler_hwif_added(ide_hwif_t *hwif, int idx); + +static inline u8 +read_switches(void) +{ + u8 state = 0; + if (cobt_is_monterey()) { + int tries = 3; + + /* i2c can be busy, and this can read wrong - try a few times */ + while (tries--) { + state = cobalt_i2c_read_byte(COBALT_I2C_DEV_DRV_SWITCH, + 0); + if ((state & 0xf0) != 0xf0) { + break; + } + } + } + + return state; +} + +static inline unsigned int +get_sled_leds(void) +{ + return atomic_read(&sled_leds); +} + +/* + * deal with sled leds: LED on means OK to remove + * NOTE: all the reset lines are kept high. + * NOTE: the reset lines are in the reverse order of the switches. + */ +static void +set_sled_leds(unsigned int leds) +{ + if (cobt_is_monterey()) { + unsigned int offed = get_sled_leds(); + + offed &= ~leds; + atomic_set(&sled_leds, leds); +#ifdef CONFIG_COBALT_LED + cobalt_led_clear_bits_lazy(offed); + cobalt_led_set_bits_lazy(leds); +#endif + } +} + +/* this must be called with the ruler_lock held for read */ +static int +do_busproc(int idx, ide_hwif_t *hwif, int arg) +{ + if (cobt_is_monterey()) { + /* sed sled LEDs */ + switch (arg) { + case BUSSTATE_ON: + set_sled_leds(get_sled_leds() & + ~sled_led_map[idx]); + break; + case BUSSTATE_OFF: + case BUSSTATE_TRISTATE: + set_sled_leds(get_sled_leds() | + sled_led_map[idx]); + break; + default: + WPRINTK("unknown busproc argument (%d)\n", arg); + } + } + + /* do the real work */ + return busprocs[idx](hwif, arg); +} + +static void +ruler_timer_fn(unsigned long data) +{ + if (cobt_is_monterey()) { + u8 state; + int i; + unsigned int now, expected, bit, swcur; + + state = read_switches(); + if ((state & 0xf0) == 0xf0) { + return; + } + swcur = atomic_read(&switches); + + state &= 0xf; + read_lock(&ruler_lock); + for (i = 0; i < MAX_COBT_DRIVES; i++) { + bit = 1 << i; + now = state & bit; + expected = swcur & bit; + if (now == expected) { + /* no changes to worry about */ + continue; + } + + if (now) { + /* a freshly detached drive */ + atomic_set(&switches, swcur | bit); + if (channels[i]) { + printk("disabling ide ruler " + "channel %d\n", i); + do_busproc(i, channels[i], + BUSSTATE_TRISTATE); + } else { + WPRINTK("drive detach on bad " + "channel (%d)\n", i); + } + set_sled_leds(get_sled_leds() | + sled_led_map[i]); + } else { + /* + * do we want to do anything when a re-attach + * is detected? + */ + } + } + read_unlock(&ruler_lock); + } +} + +#ifdef CONFIG_COBALT_ACPI +static int +ruler_interrupt(cobalt_acpi_evt *evt, void * data) +{ + if (cobt_is_monterey() && ruler_detect) { + u8 state; + + state = read_switches(); + if ((state & 0xf0) != 0xf0) { + /* this is protected inside mod_timer */ + mod_timer(&cobalt_ruler_timer, jiffies + RULER_TIMEOUT); + } + + evt->ev_data = state; + /* empirical: delay enough to debounce */ + udelay(10); + } + return 0; +} +#endif /* CONFIG_COBALT_ACPI */ + +#if defined(CONFIG_COBALT_LED) +/* figure which LEDs to blink */ +static unsigned int +ide_led_handler(void *data) +{ + unsigned int leds = 0; + + if (cobt_is_monterey()) { + int i; + static int ledmap[MAX_COBT_DRIVES] = { + LED_DISK0, LED_DISK1, LED_DISK2, LED_DISK3 + }; + static unsigned long old[MAX_COBT_DRIVES]; + + read_lock(&ruler_lock); + + for (i = 0; i < MAX_COBT_DRIVES; i++) { + if (channels[i] && channels[i]->drives[0].present + && channels[i]->drives[0].service_start != old[i]) { + leds |= ledmap[i]; + old[i] = channels[i]->drives[0].service_start; + } + } + + read_unlock(&ruler_lock); + } + + return leds; +} +#endif + +/* this is essentially an exported function - it is in the hwif structs */ +static int +ruler_busproc_fn(ide_hwif_t *hwif, int arg) +{ + int r = 0; + + if (cobt_is_monterey()) { + int idx; + + read_lock(&ruler_lock); + + for (idx = 0; idx < MAX_COBT_DRIVES; idx++) { + if (channels[idx] == hwif) { + break; + } + } + + if (idx >= MAX_COBT_DRIVES) { + /* not a hwif we manage? */ + return 0; + } + + r = do_busproc(idx, hwif, arg); + + read_unlock(&ruler_lock); + + } + + return r; +} + +/* + * We try to be VERY explicit here. Fine for now, may eventually break down. + */ +void +cobalt_ruler_register(ide_hwif_t *hwif) +{ + if (cobt_is_monterey()) { + struct pci_dev *dev; + int idx; + unsigned long flags; + + if (!hwif) { + return; + } + + /* Cobalt rulers only have HPT370 controllers on bus 1 */ + dev = hwif->pci_dev; + if (!dev) + return; + + if (dev->vendor != PCI_VENDOR_ID_TTI + || dev->device != PCI_DEVICE_ID_TTI_HPT366 + || dev->bus->number != 1) { + /* ignore it */ + return; + } + + /* IDE ruler has controllers at dev 3 and 4, ONLY */ + if (dev->devfn == PCI_DEVFN(3,0)) { + idx = hwif->channel; + } else if (dev->devfn == PCI_DEVFN(4,0)) { + idx = 2 + hwif->channel; + } else { + return; + } + + if (idx >= MAX_COBT_DRIVES) { + return; + } + + write_lock_irqsave(&ruler_lock, flags); + + /* save a pointer to the hwif, and trap it's busproc() */ + channels[idx] = hwif; + if (hwif->busproc) { + busprocs[idx] = hwif->busproc; + hwif->busproc = ruler_busproc_fn; + } + + write_unlock_irqrestore(&ruler_lock, flags); + + /* now that we have trapped it, do what we need to initialize + * the drive - if we haven't been initialized, we'll call this + * later. + */ + if (initialized) { + ruler_hwif_added(hwif, idx); + } + } +} + +static void +ruler_hwif_added(ide_hwif_t *hwif, int idx) +{ + /* the associated switch should be closed */ + if (hwif->drives[0].present) { + /* set the sled LED off - not safe to remove */ + set_sled_leds(get_sled_leds() & ~sled_led_map[idx]); + } +} + +void +cobalt_ruler_unregister(ide_hwif_t *hwif) +{ + if (cobt_is_monterey()) { + int i; + unsigned long flags; + + write_lock_irqsave(&ruler_lock, flags); + + for (i = 0; i < MAX_COBT_DRIVES; i++) { + if (channels[i] == hwif) { + channels[i] = NULL; + hwif->busproc = busprocs[i]; + busprocs[i] = NULL; + } + } + + write_unlock_irqrestore(&ruler_lock, flags); + } +} + +int __init +cobalt_ruler_init(void) +{ + if (cobt_is_monterey()) { + int err; + u8 tmp; + int i; + + /* initialize switches */ + tmp = read_switches(); + ruler_detect = ((tmp & 0xf0) == 0xf0) ? 0 : 1; + tmp &= 0xf; + atomic_set(&switches, tmp); + + /* initialize our timer */ + init_timer(&cobalt_ruler_timer); + cobalt_ruler_timer.function = ruler_timer_fn; + +#ifdef CONFIG_COBALT_ACPI + err = cobalt_acpi_register_evt_handler(ruler_interrupt, + COBALT_ACPI_EVT_SLED, NULL ); + + if (err) { + EPRINTK("can't register interrupt handler %p\n", + ruler_interrupt); + } +#endif + + /* set initial sled LED state */ + set_sled_leds(LED_SLED0 | LED_SLED1 | LED_SLED2 | LED_SLED3); + + /* run through any devices that were registered before */ + for (i = 0; i < MAX_COBT_DRIVES; i++) { + if (channels[i]) { + ruler_hwif_added(channels[i], i); + } + } + +#if defined(CONFIG_COBALT_LED) + /* register for a blinky LEDs callback */ + err = cobalt_fpled_register(ide_led_handler, NULL); + if (err) { + EPRINTK("can't register LED handler %p\n", + ide_led_handler); + } +#endif + } + + initialized = 1; + + return 0; +} diff -ruN linux-2.4.29/drivers/cobalt/sensors.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/sensors.c --- linux-2.4.29/drivers/cobalt/sensors.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/sensors.c 2005-03-21 17:27:16.652961521 -0700 @@ -0,0 +1,519 @@ +/* $Id: sensors.c,v 1.31 2002/08/29 00:33:01 uzi Exp $ + * Copyright (c) 2000-2001 Sun Microsystems, Inc + * + * This should be SMP safe. There is just one race - the read in /proc. + * It now guards against itself with a semaphore. Note that we don't use a + * spinlock because any of the methods may (and do!) block. + */ +#include +#ifdef CONFIG_COBALT_SENSORS + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +/* externals */ +unsigned int cobalt_nthermals; +unsigned int cobalt_nvoltages; + +/* data about a sensor for generic handling */ +/* we could add data about a low/high range, if needed */ +struct sensor { + int sensor; /* sensor #, so maps can be logically ordered */ + char *desc; + int last_val; + unsigned long cache; + unsigned long cache_timeout; + /* pre/post hook - 1 for pre, 0 for post */ + void (*setup)(struct sensor *s, int pre); + /* read as an int, to be passed to format() */ + int (*read)(struct sensor *s); + /* hook for scaling values */ + int (*scale)(struct sensor *s, int val); + /* format the value as a string */ + char *(*format)(struct sensor *s, int val, char *buf, int len); +}; + +/* some stuff for generic formatting */ +#define DEC_SCALAR 100 +static char *decimal_format(struct sensor *s, int val, char *buf, int len); + +static DECLARE_MUTEX(sensor_sem); +static struct sensor *therm_map; +static struct sensor *volt_map; + +#define CACHE_DEF 30 + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_csensors; +static struct proc_dir_entry *proc_therm; +static struct proc_dir_entry *proc_volt; +static int therm_read_proc(char *buf, char **start, off_t pos, int len, + int *eof, void *x); +static int therm_write_proc(struct file *file, const char *buf, + unsigned long len, void *x); +static int volt_read_proc(char *buf, char **start, off_t pos, int len, + int *eof, void *x); +static int volt_write_proc(struct file *file, const char *buf, + unsigned long len, void *x); +#endif + +static int lm77_therm_read(struct sensor *s); +static int adm1029_init(void); +static int adm1029_therm_read(struct sensor *s); +static int adm1029_volt_read(struct sensor *s); +static int alpine_vcore_scale(struct sensor *s, int val); +static void alpine_vbat_switch(struct sensor *s, int pre); +static int alpine_vbat_scale(struct sensor *s, int val); + +/* sensor name mappings */ +static struct sensor gen3_therm_map[] = { + {0, "CPU", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, +}; +static struct sensor monterey_therm_map[] = { + {0, "CPU0", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, + {1, "CPU1", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, + {2, "Case0", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, + {3, "Case1", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, +}; +static struct sensor alpine_therm_map[] = { + {1, "CPU", 0, 0, CACHE_DEF, NULL, adm1029_therm_read, NULL, decimal_format}, + {0, "Case", 0, 0, CACHE_DEF, NULL, adm1029_therm_read, NULL, decimal_format}, +}; +static struct sensor alpine_volt_map[] = { + {0, "Vcore", 0, 0, CACHE_DEF, NULL, adm1029_volt_read, + alpine_vcore_scale, decimal_format}, + {1, "Vtt", 0, 0, CACHE_DEF, NULL, adm1029_volt_read, NULL, decimal_format}, + {0, "Vbat", 0, 0, CACHE_DEF<<10, alpine_vbat_switch, adm1029_volt_read, + alpine_vbat_scale, decimal_format}, +}; + +int __init +cobalt_sensors_init(void) +{ + if (cobt_is_3k()) { + cobalt_nthermals = 1; + cobalt_nvoltages = 0; + therm_map = gen3_therm_map; + } else if (cobt_is_monterey()) { + cobalt_nthermals = 4; + cobalt_nvoltages = 0; + therm_map = monterey_therm_map; + } else if (cobt_is_alpine()) { + cobalt_nthermals = 2; + cobalt_nvoltages = 3; + therm_map = alpine_therm_map; + volt_map = alpine_volt_map; + adm1029_init(); + } else { + return -1; + } + +#ifdef CONFIG_PROC_FS + /* make files in /proc */ + proc_csensors = proc_mkdir("sensors", proc_cobalt); + if (!proc_csensors) { + EPRINTK("can't create /proc/cobalt/sensors\n"); + return -1; + } + if (cobalt_nthermals) { + proc_therm = create_proc_entry("thermal", + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, + proc_csensors); + if (!proc_therm) { + EPRINTK("can't create /proc/cobalt/sensors/thermal\n"); + } + proc_therm->read_proc = therm_read_proc; + proc_therm->write_proc = therm_write_proc; + } + if (cobalt_nvoltages) { + proc_volt = create_proc_entry("voltage", + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, + proc_csensors); + if (!proc_volt) { + EPRINTK("can't create /proc/cobalt/sensors/voltage\n"); + } + proc_volt->read_proc = volt_read_proc; + proc_volt->write_proc = volt_write_proc; + + } +#endif + + return 0; +} + +static char * +sensor_read(struct sensor *s, char *buf, int len) +{ + int val; + + if (s->cache && time_after(s->cache_timeout*HZ + s->cache, jiffies)) + val = s->last_val; + else { + if (s->setup) s->setup(s, 1); + val = s->read(s); + s->last_val = val; + s->cache = jiffies; + if (s->setup) s->setup(s, 0); + } + + if (s->scale) val = s->scale(s, val); + return s->format(s, val, buf, len); +} + +/* exported - nicer inline functions in header */ +char * +__cobalt_thermal_read(unsigned int idx, char *buf, int len) +{ + if (idx >= cobalt_nthermals || !buf) { + return NULL; + } + + return sensor_read(&therm_map[idx], buf, len); +} + +/* exported - nicer inline functions in header */ +char * +__cobalt_voltage_read(unsigned int idx, char *buf, int len) +{ + if (idx >= cobalt_nvoltages || !buf) { + return NULL; + } + + return sensor_read(&volt_map[idx], buf, len); +} + +/* generic function for formatting decimal scaled data */ +static char * +decimal_format(struct sensor *s, int val, char *buf, int len) +{ + int plen; + + if (!buf || len <= 0) { + return NULL; + } + + plen = snprintf(buf, len, "%d", val/DEC_SCALAR); + len -= plen; + + if (val % DEC_SCALAR && len > 0) { + snprintf(buf+plen, len, ".%02d", val%DEC_SCALAR); + } + + return buf; +} + +#define LM77_TEMP 0x0 +static int +lm77_therm_read(struct sensor *s) +{ + int sensor = s->sensor; + int tmp; + int val = 0; + int tries = 2; + + /* sometimes it reads as zero... try again */ + while (tries--) { + /* LM77 returns the bytes backwards - */ + /* address = base + deviceid + 1 for read */ + val = cobalt_i2c_read_word(COBALT_I2C_DEV_LM77 + + (sensor<<1) + 1, LM77_TEMP); + if (val < 0) { + /* read failed, return the last known value */ + return s->last_val; + } + + tmp = (val<<8 & 0xff00) + (val>>8 & 0x00ff); + if (tmp) { + val = tmp >> 4; + val *= DEC_SCALAR; + if (tmp & 0x8) { + val += DEC_SCALAR/2; + } + break; + } + } + return val; +} + +#define ADM1029_CTL_CFAULT_OVER 0x01 +#define ADM1029_CTL_ALARM_OVER 0x02 +#define ADM1029_CTL_INT_OVER 0x04 +#define ADM1029_CTL_ALARM_LOW 0x08 +#define ADM1029_CTL_CFAULT_UNDER 0x10 +#define ADM1029_CTL_ALARM_UNDER 0x20 +#define ADM1029_CTL_INT_UNDER 0x40 +#define ADM1029_CTL_LATCH 0x80 + +#define ADM1029_FAN_CTL(i) (0x18 + i) +#define ADM1029_TEMP_CTL(i) (0x40 + i) +#define ADM1029_AIN_CTL(i) (0x50 + i) + +#define ADM1029_TEMP_HIGH(i) (0x90 + i) +#define ADM1029_TEMP_LOW(i) (0x98 + i) +#define ADM1029_AIN_HIGH(i) (0xa8 + i) +#define ADM1029_AIN_LOW(i) (0xb0 + i) + +#define ADM1029_TEMP_VALUE(i) (0xa0 + i) +#define ADM1029_AIN_VALUE(i) (0xb8 + i) + +#ifdef CONFIG_COBALT_ACPI +static int +adm1029_handler(cobalt_acpi_evt *evt, void * data) +{ + int j, k; + + switch (evt->ev_type) { + case COBALT_ACPI_EVT_SM_INT: + evt->ev_data = 0; + evt->ev_type = COBALT_ACPI_EVT_VOLT; + for (j=0; jev_data |= (1 << j); + volt_map[j].cache = 0; + } + } + break; + + case COBALT_ACPI_EVT_THERM: + evt->ev_data = 0; + for (j=0; jev_data |= (1 << j); + therm_map[j].cache = 0; + } + } + break; + + default: + return -1; + } + return 0; +} +#endif /* CONFIG_COBALT_ACPI */ + +static int +adm1029_init(void) +{ + +#ifdef CONFIG_COBALT_ACPI + cobalt_acpi_register_evt_handler(adm1029_handler, + COBALT_ACPI_EVT_THERM, NULL); + cobalt_acpi_register_evt_handler(adm1029_handler, + COBALT_ACPI_EVT_SM_INT, NULL); +#endif + + return 0; +} + +static int +adm1029_therm_read(struct sensor *s) +{ + int sensor = s->sensor; + int val; + + val = cobalt_i2c_read_byte(COBALT_I2C_DEV_ADM1029, + ADM1029_TEMP_VALUE(sensor)); + if (val < 0) { + /* read failed, return the last known value */ + return s->last_val; + } + if (val & 0x80) { + val -= 256; + } + val *= DEC_SCALAR; + + return val; +} + +static int +adm1029_volt_read(struct sensor *s) +{ + int sensor = s->sensor; + int val; + + val = cobalt_i2c_read_byte(COBALT_I2C_DEV_ADM1029, + ADM1029_AIN_VALUE(sensor)); + if (val < 0) { + /* read failed, return the last known value */ + return s->last_val; + } + + /* already scaled by 100 */ + val *= DEC_SCALAR/100; + + return val; +} + +static int +alpine_vcore_scale(struct sensor *s, int val) +{ + /* the measured Vbat switch cost is negligable + * due to very low current through the diode */ + return val; +} + +#define VBAT_REG 0x608 +#define VBAT_BIT 0x1 +static void +alpine_vbat_switch(struct sensor *s, int pre) +{ + unsigned char v = inb(VBAT_REG); + unsigned long j = jiffies; + + if (pre) { + v |= VBAT_BIT; + /* + * disable AIN0 INT# assertion before switching to + * Vbat because the input is shared with Vcore and + * their acceptable ranges are very different. + */ + cobalt_i2c_write_byte(COBALT_I2C_DEV_ADM1029, + ADM1029_AIN_CTL(s->sensor), 0x0); + } else { + v &= ~VBAT_BIT; + } + + outb(v, VBAT_REG); + + /* + * wait for the round-robin monitor to complete a cycle + * before _and_ after toggling Vbat switch, otherwise + * stale data in AIN0 will trigger INT# assertion. + */ + while ((jiffies - j) < HZ) { + /* block for ~ 1sec */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + } + + if (!pre) { + /* + * now re-enable INT# assertion capability for AIN0 + * (this also clears the AIN0 fault latch at bit 7) + */ + cobalt_i2c_write_byte(COBALT_I2C_DEV_ADM1029, + ADM1029_AIN_CTL(s->sensor), + ADM1029_CTL_INT_OVER | ADM1029_CTL_INT_UNDER); + } +} + +static int +alpine_vbat_scale(struct sensor *s, int val) +{ + /* + * The spec says 2.5V max - but empirically, 3.3V works :) + * The Vbat switch costs 0.3 volts + */ + if (val) val += (3 * DEC_SCALAR)/10; + + return val; +} + +#ifdef CONFIG_PROC_FS +static int +sensor_write_proc(int nsensors, struct sensor *map, + struct file *file, const char *buf, unsigned long len, void *x) +{ + char *pg; + + if (len > PAGE_SIZE) { + return -EOVERFLOW; + } + + pg = (char *)__get_free_page(GFP_KERNEL); + if (!pg) { + return -ENOMEM; + } + + if (copy_from_user(pg, buf, len)) { + free_page((unsigned long)pg); + return -EFAULT; + } + pg[len] = '\0'; + + /* format: `cache_timeout #' in seconds */ + if (len>15 && !strncmp("cache_timeout ", pg, 14) && isdigit(*(pg+14))) { + unsigned long i, sec = simple_strtoul(pg+14, NULL, 0); + for (i=0; i= plen) { + *eof = 1; + up(&sensor_sem); + return 0; + } + + plen = 0; + for (i = 0; i < nsensors; i++) { + char sbuf[32]; + if (sensor_read(&map[i], sbuf, sizeof(sbuf))) + plen += sprintf(buf+plen, "%d [%s]: %s\n", i, map[i].desc, sbuf); + } + + up(&sensor_sem); + + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} + +static int +therm_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + return sensor_read_proc(cobalt_nthermals, therm_map, + buf, start, pos, len, eof, x); +} +static int +therm_write_proc(struct file *file, const char *buf, unsigned long len, void *x) +{ + return sensor_write_proc(cobalt_nthermals, therm_map, file, buf, len, x); +} + +static int +volt_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + return sensor_read_proc(cobalt_nvoltages, volt_map, + buf, start, pos, len, eof, x); +} +static int +volt_write_proc(struct file *file, const char *buf, unsigned long len, void *x) +{ + return sensor_write_proc(cobalt_nvoltages, volt_map, file, buf, len, x); +} +#endif /* CONFIG_PROC_FS */ + +#endif /* CONFIG_COBALT_SENSORS */ diff -ruN linux-2.4.29/drivers/cobalt/serialnum.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/serialnum.c --- linux-2.4.29/drivers/cobalt/serialnum.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/serialnum.c 2005-03-21 17:27:16.653961372 -0700 @@ -0,0 +1,448 @@ +/* $Id: serialnum.c,v 1.15 2001/10/23 20:15:27 thockin Exp $ */ +/* + * + * Author: Philip Gladstone, Axent Technologies + * modified for Nat Semi PC[89]7317 by asun@cobalt.com + * ported to 2.4.x by thockin@sun.com + * alpine serial eeprom by erik.glling@sun.com + * Copyright (c) 2000 Axent Technologies, Cobalt Networks + * Copyright (c) 2001 Axent Technologies, Sun Microsystems + * + * This module interrogates the DS2401 Silicon Serial Number chip + * that is attached to all x86 Cobalt systems. + * + * It exports /proc/cobalt/hostid which is four bytes generated from of + * the id. It can be linked to /var/adm/hostid or /etc/hostid for the + * hostid command to use. + * + * It exports /proc/cobalt/serialnumber which is the entire 64 bit value + * read back (in ascii). + * + * For the guts of the 1 wire protocol used herein, please see the DS2401 + * specification. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is SMP safe by nature. --TPH + */ +#include +#if defined (CONFIG_COBALT_SERNUM) || defined(CONFIG_COBALT_SERNUM_MODULE) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define SERNUM_VER "1.6" + +/* dependent on systype */ +static unsigned int sn_direction; +static unsigned int sn_output; +static unsigned int sn_input; +static unsigned int sn_mask; + +/* 3k style systems */ +#define III_SN_DIRECTION 0x7d +#define III_SN_OUTPUT 0x7e +#define III_SN_INPUT 0x7f +#define III_SN_MASK 0x08 +static struct pci_dev *id_dev; + +/* 5k style systems */ +#define V_SN_DIRECTION (sn_io_base + 0x01) +#define V_SN_OUTPUT (sn_io_base + 0x00) +#define V_SN_INPUT (sn_io_base + 0x00) +#define V_SN_MASK (sn_io_base + 0x01) +static unsigned int sn_io_base; + +#define SSN_SIZE 8 /* bytes */ +static char ssn_string[SSN_SIZE * 2 + 1]; +static unsigned long hostid; +static int debug; +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC +static struct proc_dir_entry *proc_hostid; +static struct proc_dir_entry *proc_serialnum; +#endif +static struct proc_dir_entry *proc_chostid; +static struct proc_dir_entry *proc_cserialnum; +#endif + +static int +hostid_read(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + int plen = sizeof(hostid); + memcpy(buf, &hostid, sizeof(hostid)); + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} + +static int +serialnum_read(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + int plen = sizeof(ssn_string); + sprintf(buf, "%s\n", ssn_string); + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} + +/* set up the requisite IO bits */ +static int __init +io_init(void) +{ + unsigned char data; + + if (cobt_is_3k()) { + /* The GPIO tied to the ID chip is on the PMU */ + id_dev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M7101, NULL); + if (!id_dev) { + EPRINTK("can't find PMU for serialnumber access\n"); + return -ENXIO; + } + + /* Set input mode on GPIO3 */ + pci_read_config_byte(id_dev, sn_direction, &data); + if (debug > 1) { + WPRINTK("read of register 0x%x = 0x%x\n", + sn_direction, data); + } + if (data & sn_mask) { + pci_write_config_byte(id_dev, sn_direction, + data & ~sn_mask); + } + + /* Set the output value to be 0 */ + pci_read_config_byte(id_dev, sn_output, &data); + if (debug > 1) { + WPRINTK("read of register 0x%x = 0x%x\n", + sn_output, data); + } + if (data & sn_mask) { + pci_write_config_byte(id_dev, sn_output, + data & ~sn_mask); + } + } else if (cobt_is_5k()) { + u16 addr; + + addr = superio_ldev_base(PC87317_DEV_GPIO); + if (addr) { + u8 val; + + sn_io_base = addr; + + /* set output value to 0 */ + val = inb(sn_direction); + outb(val | sn_mask, sn_direction); + data = inb(sn_output); + if (data & sn_mask) { + outb(data & ~sn_mask, sn_output); + } + /* set to input */ + outb(val & ~sn_mask, sn_direction); + } + } else { + return -ENXIO; + } + + /* pick proper variables */ + if (cobt_is_3k()) { + sn_direction = III_SN_DIRECTION; + sn_output = III_SN_OUTPUT; + sn_input = III_SN_INPUT; + sn_mask = III_SN_MASK; + } else if (cobt_is_5k()) { + sn_direction = V_SN_DIRECTION; + sn_output = V_SN_OUTPUT; + sn_input = V_SN_INPUT; + sn_mask = V_SN_MASK; + } else { + return -1; + } + + /* Let things calm down */ + udelay(500); + return 0; +} + +/* write out a bit */ +static void __init +io_write(int delay) +{ + if (cobt_is_3k()) { + unsigned char data; + /* Set output mode on GPIO3 */ + pci_read_config_byte(id_dev, sn_direction, &data); + pci_write_config_byte(id_dev, sn_direction, data | sn_mask); + udelay(delay); + + /* Set input mode */ + pci_write_config_byte(id_dev, sn_direction, data & ~sn_mask); + } else if (cobt_is_5k()) { + unsigned char direction; + + /* change to output and back */ + direction = inb(sn_direction); + outb(direction | sn_mask, sn_direction); + udelay(delay); + outb(direction & ~sn_mask, sn_direction); + } +} + +/* read in a bit */ +static int __init +io_read(void) +{ + unsigned char data = 0; + + /* Get the input value */ + if (cobt_is_3k()) { + pci_read_config_byte(id_dev, sn_input, &data); + } else if (cobt_is_5k()) { + data = inb(sn_input); + } + + return (data & sn_mask) ? 1 : 0; +} + +static void __init +io_write_byte(unsigned char c) +{ + int i; + unsigned long flags; + + save_flags(flags); + + for (i = 0; i < 8; i++, c >>= 1) { + cli(); + if (c & 1) { + /* Transmit a 1 */ + io_write(5); + udelay(80); + } else { + /* Transmit a 0 */ + io_write(80); + udelay(10); + } + restore_flags(flags); + } +} + +static int __init +io_read_byte(void) +{ + int i; + int c = 0; + unsigned long flags; + + save_flags(flags); + + for (i = 0; i < 8; i++) { + cli(); + io_write(1); /* Start the read */ + udelay(2); + if (io_read()) { + c |= 1 << i; + } + udelay(60); + restore_flags(flags); + } + + return c; +} + +static int __init +get_ssn(unsigned char *buf) +{ + int i; + unsigned long flags; + + /* + * Alpine does not have a dallas chip. Instead + * we read from an eprom. + */ + if (cobt_is_alpine()) { + for (i = 0; i < 8; i++) { + buf[i] = cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, + 12 + i); + } + return 0; + } + + /* + * bit-bang the Dallas 2401 + */ + + save_flags(flags); + cli(); + + /* Master Reset Pulse */ + for (i = 0; i < 600; i += 30) { + if (io_read()) { + break; + } + } + + if (i >= 600) { + if (debug) { + EPRINTK("the data line seems to be held low\n"); + } + restore_flags(flags); + return -ENXIO; + } + + io_write(600); + + for (i = 0; i < 300; i += 15) { + udelay(15); + if (io_read() == 0) { + /* We got a presence pulse */ + udelay(600); /* Wait for things to quiet down */ + break; + } + } + restore_flags(flags); + + if (i >= 300) { + if (debug) + EPRINTK("no presence pulse detected\n"); + return -ENXIO; + } + + io_write_byte(0x33); + + for (i = 0; i < 8; i++) { + int rc; + + rc = io_read_byte(); + if (rc < 0) { + return rc; + } + + *buf++ = rc; + } + + return 0; +} + +int __init +cobalt_serialnum_init(void) +{ + unsigned char ssn[SSN_SIZE]; + int rc; + int i; + + /* set up for proper IO */ + rc = io_init(); + if (rc) { + return rc; + } + + /* + * NOTE: the below algorithm CAN NOT be changed. We have many systems + * out there registered with the serial number AS DERIVED by this + * algorithm. + */ + + rc = get_ssn(ssn); + if (rc) { + return rc; + } + + /* Convert to ssn_string */ + for (i = 7; i >= 0; i--) { + sprintf(ssn_string + (7 - i) * 2, "%02x", ssn[i]); + } + + /* get four bytes for a pretty unique (not guaranteed) hostid */ + hostid = *(unsigned long *)ssn ^ *(unsigned long *)(ssn+4); + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + proc_hostid = create_proc_read_entry("hostid", 0, NULL, + hostid_read, NULL); + if (!proc_hostid) { + EPRINTK("can't create /proc/hostid\n"); + } + proc_serialnum = create_proc_read_entry("serialnumber", 0, NULL, + serialnum_read, NULL); + if (!proc_serialnum) { + EPRINTK("can't create /proc/serialnumber\n"); + } +#endif + proc_chostid = create_proc_read_entry("hostid", 0, proc_cobalt, + hostid_read, NULL); + if (!proc_chostid) { + EPRINTK("can't create /proc/cobalt/hostid\n"); + } + proc_cserialnum = create_proc_read_entry("serialnumber", 0, + proc_cobalt, serialnum_read, NULL); + if (!proc_cserialnum) { + EPRINTK("can't create /proc/cobalt/serialnumber\n"); + } +#endif + + return 0; +} + +char * +cobalt_serialnum_get(void) +{ + return ssn_string; +} + +unsigned long +cobalt_hostid_get(void) +{ + return hostid; +} + +#if defined(CONFIG_COBALT_SERNUM_MODULE) +MODULE_PARM(debug, "i"); + +int +init_module(void) +{ + return cobalt_serialnum_init(); +} + +void +cleanup_module(void) +{ +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + remove_proc_entry("hostid", NULL); + remove_proc_entry("serialnumber", NULL); +#endif + remove_proc_entry("hostid", proc_cobalt); + remove_proc_entry("serialnumber", proc_cobalt); +#endif +} + +module_init(init_module); +module_exit(cleanup_module); +#endif /* MODULE */ + +#endif /* CONFIG_COBALT_SERNUM */ diff -ruN linux-2.4.29/drivers/cobalt/systype.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/systype.c --- linux-2.4.29/drivers/cobalt/systype.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/systype.c 2005-03-21 17:27:16.654961223 -0700 @@ -0,0 +1,274 @@ +/* + * $Id: systype.c,v 1.33 2002/11/04 17:54:15 thockin Exp $ + * systype.c : routines for figuring out which Cobalt system this is + * + * Copyright 2001-2002 Sun Microsystems, Inc. + * + * By: Tim Hockin + * Adrian Sun + * Duncan Laurie + * + * This driver is SMP safe by nature. --TPH + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +/* for easy first-pass analysis */ +#if defined(CONFIG_COBALT_GEN_III) +int COBALT_GENERATION_III_DEFINED; +#endif +#if defined(CONFIG_COBALT_GEN_V) +int COBALT_GENERATION_V_DEFINED; +#endif + +cobt_sys_t cobt_type = COBT_UNINITIALIZED; +EXPORT_SYMBOL(cobt_type); +unsigned long cobt_rev; +EXPORT_SYMBOL(cobt_rev); + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_systype; +#endif +static int systype_read_proc(char *buf, char **start, off_t pos, int len, + int *eof, void *x); +static char *systype_str(cobt_sys_t type); +static unsigned long boardrev_read(void); + +void __init +cobalt_boardrev_init(void) +{ + cobt_rev = boardrev_read(); +} + +int __init +cobalt_systype_init(void) +{ + cobalt_systype_probe(); + +#ifdef CONFIG_PROC_FS + proc_systype = create_proc_read_entry("systype", 0, + proc_cobalt, systype_read_proc, NULL); + if (!proc_systype) { + EPRINTK("can't create /proc/cobalt/systype\n"); + } +#endif + + if (cobt_type == COBT_UNKNOWN) { + printk("Cobalt system type is unknown (trouble will ensue)\n"); + return -1; + } + + return 0; +} + +#if defined(CONFIG_COBALT_GEN_III) +static cobt_sys_t +systype_probe_3k(void) +{ + struct pci_dev *pdev; + cobt_sys_t retval = COBT_UNKNOWN; + + /* board identifier for RaQ3/4 vs Qube3 is on the PMU @ 0x7f */ + pdev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL); + if (pdev) { + /* + * check to see what board we are on + * ( RaQ 3, RaQ 4, Qube 3 ) + */ + unsigned char val; + + /* momentarily set DOGB# to input */ + pci_read_config_byte(pdev, 0x7d, &val); + pci_write_config_byte(pdev, 0x7d, val & ~0x20); + + /* read the GPIO register */ + pci_read_config_byte(pdev, 0x7f, &val); + /* RaQ3/4 boards have DOGB (0x20) high, + * Qube3 has DOGB low */ + retval = (val & 0x20) ? COBT_PACIFICA : COBT_CARMEL; + + /* change DOGB back to output */ + pci_read_config_byte(pdev, 0x7d, &val); + pci_write_config_byte(pdev, 0x7d, val | 0x20); + } + + /* assign to this, so the compiler shuts up */ + COBALT_GENERATION_III_DEFINED = 1; + + return retval; +} +#else +#define systype_probe_3k() (COBT_UNKNOWN) +#endif + +#if defined(CONFIG_COBALT_GEN_V) +static cobt_sys_t +systype_probe_5k(void) +{ + struct pci_dev *pdev; + cobt_sys_t retval = COBT_UNKNOWN; + + /* is it a gen V ? */ + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); + if (pdev) { + retval = COBT_MONTEREY; + goto out; + } + + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); + if (pdev) { + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_LE, NULL); + if (pdev) { + retval = COBT_ALPINE; + goto out; + } + } + +out: + /* assign to this, so the compiler shuts up */ + COBALT_GENERATION_V_DEFINED = 1; + + return retval; +} +#else +#define systype_probe_5k() (COBT_UNKNOWN) +#endif + +static cobt_sys_t +systype_probe_gp(void) +{ + struct pci_dev *pdev; + cobt_sys_t retval = COBT_UNKNOWN; + + /* is it a GP system? */ + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); + if (pdev) { + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_HE, NULL); + if (pdev) { + retval = COBT_BIGBEAR; + } + } + + return retval; +} + +cobt_sys_t +cobalt_systype_probe(void) +{ + static int init_done = 0; + + if (init_done) { + return cobt_type; + } + + /* check for 3k family systems */ + cobt_type = systype_probe_3k(); + if (cobt_type != COBT_UNKNOWN) + goto out; + + /* check for 5k family systems */ + cobt_type = systype_probe_5k(); + if (cobt_type != COBT_UNKNOWN) + goto out; + + /* it's a GP system or unknown */ + cobt_type = systype_probe_gp(); + +out: + if (cobt_type != COBT_UNKNOWN) { + init_done = 1; + } + + return cobt_type; +} +EXPORT_SYMBOL(cobalt_systype_probe); + +#ifdef CONFIG_PROC_FS +static int +systype_read_proc(char *buf, char **start, off_t pos, int len, + int *eof, void *x) +{ + int plen = sprintf(buf, "%s\n", systype_str(cobt_type)); + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} +#endif + +static char * +systype_str(cobt_sys_t type) +{ + switch (type) { + case COBT_PACIFICA: + return "Pacifica"; + break; + case COBT_CARMEL: + return "Carmel"; + break; + case COBT_MONTEREY: + return "Monterey"; + break; + case COBT_ALPINE: + return "Alpine"; + break; + case COBT_BIGBEAR: + return "BigBear"; + break; + case COBT_UNKNOWN: + default: + return "unknown"; + break; + } +} + +static unsigned long +boardrev_read(void) +{ + unsigned long rev; + + switch (cobt_type) { +#ifdef CONFIG_COBALT_RAQ + case COBT_PACIFICA: + case COBT_CARMEL: + /* No usable board rev on these systems */ + return 0; + case COBT_MONTEREY: + /* + * the boardrev on monterey is strapped off of GPM[3:0] + * and is read from port 0xc52 + */ + return inb(0xc52); + case COBT_ALPINE: + /* + * the boardrev on alpine in stored in the i2c eeprom + * location 4 + */ + rev = cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x04); + rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x05) << 8; + rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x06) << 16; + rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x07) << 24; + if (rev == 0xffffffff) + rev = 0; + return rev; +#endif + case COBT_BIGBEAR: + /* No board revs at this time */ + return 0; + case COBT_UNKNOWN: + case COBT_UNINITIALIZED: + return 0; + } + return 0; +} diff -ruN linux-2.4.29/drivers/cobalt/wdt.c linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/wdt.c --- linux-2.4.29/drivers/cobalt/wdt.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/cobalt/wdt.c 2005-03-21 17:27:16.655961075 -0700 @@ -0,0 +1,419 @@ +/* $Id: wdt.c,v 1.21 2002/07/02 00:38:17 asun Exp $ */ +/* + * Cobalt kernel WDT timer driver + * Tim Hockin + * Adrian Sun + * Chris Johnson + * Copyright (c)1999-2000, Cobalt Networks + * Copyright (c)2001, Sun Microsystems + * + * This should be SMP safe. Every external function (except trigger_reboot) + * grabs the wdt lock. No function in this file may call any exported + * function (excepting trigger_reboot). The disable counter is an atomic, so + * there should be no issues there. --TPH + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DOGB 0x20 +#define ALI_7101_WDT 0x92 +#define ALI_WDT_ARM 0x01 +#define WDT_3K_TIMEOUT (HZ >> 4) /* 1/16 second */ + +#define WDT_SUPERIO_TIMEOUT (0x01) /* 1 minute */ +#define WDT_5K_TIMEOUT (HZ << 3) /* 8 seconds */ + +static unsigned long wdt_timeout; +static unsigned long long tsc_per_wdt; +static int initialized; + +#ifdef CONFIG_COBALT_WDT +struct timer_list cobalt_wdt_timer; +static atomic_t cobalt_wdt_disable_count = ATOMIC_INIT(0); +static spinlock_t wdt_lock = SPIN_LOCK_UNLOCKED; +#endif + +/* gen III */ +static struct pci_dev *cobalt_pmu; +static int use_pic; +/* gen V */ +static u16 superio_pm_port; + +#ifdef CONFIG_COBALT_WDT +static void do_refresh(void); +static void do_cleardog(void); +static void do_disable(void); +static void do_reenable(void); +#endif + +static unsigned long __init +chipset_setup(void) +{ + if (cobt_is_3k()) { + /* + * Set up the PMU for 3k boards. It has a max + * of a 1 second timeout. + */ + struct pci_dev *south; + char tmp; + + /* PMU (1543 ver A1-E) has a built-in WDT. Set it to 1 sec */ + cobalt_pmu = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M7101, NULL); + if (!cobalt_pmu) { + EPRINTK("can't find south bridge for WDT\n"); + return 0; + } + pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, 0x02); + + /* why it is called 1543, but DevId is 1533 I'll never know */ + south = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M1533, NULL); + if (!south) { + EPRINTK("can't find south bridge for WDT\n"); + use_pic = 1; + } else { + /* reversion # is here - must match ???1001?(b) + * else use PIC for WDT */ + pci_read_config_byte(south, 0x5e, &tmp); + use_pic = ((tmp & 0x1e) != 0x12); + } + + if (!use_pic) { + /* set DOGB GPIO pin to OUTPUT - JIC */ + pci_read_config_byte(cobalt_pmu, 0x7d, &tmp); + pci_write_config_byte(cobalt_pmu, 0x7d, tmp | DOGB); + } + return WDT_3K_TIMEOUT; + } else if (cobt_is_monterey()) { + /* + * Set up the Nat. Semi SuperI/O for XTR. It has a + * minimum of a 1 minute timeout. + */ + + /* superi/o -- select pm logical device and get base address */ + superio_pm_port = superio_ldev_base(PC87317_DEV_PM); +#ifdef CONFIG_COBALT_WDT + if (!superio_pm_port) { + return 0; + } + outb(PC87317_PMDEV_WDTO, superio_pm_port); + outb(WDT_SUPERIO_TIMEOUT, superio_pm_port + 1); +#endif + return WDT_5K_TIMEOUT; + } else if (cobt_is_alpine()) { + /* + * Set up the Nat. Semi SuperI/O for Alpine. It has a + * minimum of a 1 minute timeout. + */ + unsigned char tmp; + + /* superi/o -- select pm logical device and get base address */ + superio_pm_port = superio_ldev_base(PC87417_DEV_SWC); +#ifdef CONFIG_COBALT_WDT + if (!superio_pm_port) { + return 0; + } + /* select the WDT bank of SWC */ + outb(PC87417_SWCBANK_WDT, superio_pm_port+PC87417_SWC_BANK); + /* clear event config... */ + tmp = inb(superio_pm_port+PC87417_WDT_CONFIG); + outb(0, superio_pm_port+PC87417_WDT_CONFIG); + /* ...before mucking with timeout */ + outb(WDT_SUPERIO_TIMEOUT, + superio_pm_port+PC87417_WDT_TIMEOUT); + /* restore the event config */ + outb(tmp, superio_pm_port+PC87417_WDT_CONFIG); + /* enable the counter */ + outb(1, superio_pm_port+PC87417_WDT_CONTROL); +#endif + return WDT_5K_TIMEOUT; + } + + return 0; +} + +void __init +cobalt_wdt_init(void) +{ + unsigned long long start, stop; + + wdt_timeout = chipset_setup(); + + /* figure out time */ + rdtscll(start); + udelay(100); + rdtscll(stop); + + /* + * (int) (stop - start) * 10 == tsc per msec + * 1000 / HZ == msec per tick + * wdt_timeout == ticks per watchdog rearm + */ + tsc_per_wdt = (int) (stop - start) * 10 * (1000 * wdt_timeout / HZ); + +#ifdef CONFIG_COBALT_WDT + /* set the timer going */ + init_timer(&cobalt_wdt_timer); + cobalt_wdt_timer.function = cobalt_wdt_refresh; + cobalt_wdt_timer.data = 1; + cobalt_wdt_timer.expires = jiffies + wdt_timeout; + add_timer(&cobalt_wdt_timer); + + /* the first timer tick will set it going */ + + if (cobt_is_3k() && use_pic) { + WPRINTK("Cobalt WDT - old board, using PIC controller\n"); + } +#endif /* CONFIG_COBALT_WDT */ + + initialized = 1; +} + +static inline void +hw_disable(void) +{ + if (cobt_is_3k()) { + char tmp; + /* read the value, disable (reset) WDT */ + pci_read_config_byte(cobalt_pmu, ALI_7101_WDT, &tmp); + pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, + (tmp & ~ALI_WDT_ARM)); + } else if (cobt_is_monterey()) { + outb(PC87317_PMDEV_WDTO, superio_pm_port); + outb(0, superio_pm_port + 1); + } else if (cobt_is_alpine()) { + unsigned char tmp; + /* select the WDT bank of SWC */ + outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK); + /* clear event config before mucking with timeout */ + tmp = inb(superio_pm_port + PC87417_WDT_CONFIG); + outb(0, superio_pm_port + PC87417_WDT_CONFIG); + /* + * Disable it by setting a 0 time-out. + * The spec says 00h is reserved, but NSC confirms this is the + * way to disable the device. + */ + outb(0, superio_pm_port + PC87417_WDT_TIMEOUT); + /* restore the event config */ + outb(tmp, superio_pm_port + PC87417_WDT_CONFIG); + } +} + +static inline void +hw_enable(void) +{ + if (cobt_is_3k()) { + unsigned char tmp; + /* read the value, disable (reset) WDT, enable WDT */ + pci_read_config_byte(cobalt_pmu, ALI_7101_WDT, &tmp); + pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, + (tmp | ALI_WDT_ARM)); + if (use_pic) { + /* transition GPIO 5 (DOGB) to arm/clear timer */ + pci_read_config_byte(cobalt_pmu, 0x7e, &tmp); + pci_write_config_byte(cobalt_pmu, 0x7e, tmp ^ DOGB); + } + } else if (cobt_is_monterey()) { + outb(PC87317_PMDEV_WDTO, superio_pm_port); + outb(WDT_SUPERIO_TIMEOUT, superio_pm_port + 1); + } else if (cobt_is_alpine()) { + unsigned char tmp; + /* select the WDT bank of SWC */ + outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK); + /* clear event config before mucking with timeout */ + tmp = inb(superio_pm_port + PC87417_WDT_CONFIG); + outb(0, superio_pm_port + PC87417_WDT_CONFIG); + /* enable and refresh the timer */ + outb(WDT_SUPERIO_TIMEOUT, + superio_pm_port + PC87417_WDT_TIMEOUT); + outb(0x80, superio_pm_port + PC87417_WDT_CONTROL); + /* restore event config */ + outb(tmp, superio_pm_port + PC87417_WDT_CONFIG); + } +} + +#ifdef CONFIG_COBALT_WDT +static void +do_refresh(void) +{ + if (!initialized) { + return; + } + + do_cleardog(); + + /* re-arm the timer - this is locked in mod_timer() */ + mod_timer(&cobalt_wdt_timer, jiffies + wdt_timeout); +} +#endif + +EXPORT_SYMBOL(cobalt_wdt_refresh); +void +cobalt_wdt_refresh(unsigned long refresh_timer) +{ +#ifdef CONFIG_COBALT_WDT + unsigned long flags; + spin_lock_irqsave(&wdt_lock, flags); + do_refresh(); + spin_unlock_irqrestore(&wdt_lock, flags); +#endif +} + +#ifdef CONFIG_COBALT_WDT +static void +do_cleardog(void) +{ + static unsigned long long last_tsc = 0; + unsigned long long tmp; + + if (!initialized || (atomic_read(&cobalt_wdt_disable_count) > 0)) { + return; + } + + /* only bother if we're due */ + rdtscll(tmp); + if ((int)(tmp - last_tsc) < tsc_per_wdt) { + return; + } + + if (cobt_is_3k() || cobt_is_monterey()) { + /* this is how we re-start the clock */ + hw_disable(); + hw_enable(); + } else if (cobt_is_alpine()) { + /* select the WDT bank of SWC */ + outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK); + /* refresh the timer */ + outb(0x80, superio_pm_port + PC87417_WDT_CONTROL); + } + + rdtscll(last_tsc); +} +#endif + +EXPORT_SYMBOL(cobalt_wdt_cleardog); +void +cobalt_wdt_cleardog(void) +{ +#ifdef CONFIG_COBALT_WDT + unsigned long flags; + + spin_lock_irqsave(&wdt_lock, flags); + do_cleardog(); + spin_unlock_irqrestore(&wdt_lock, flags); +#endif +} + +/* + * this is called from machine_restart. it should not be used on + * 5k machines. + */ +EXPORT_SYMBOL(cobalt_wdt_trigger_reboot); +void +cobalt_wdt_trigger_reboot(void) +{ + if (cobt_is_3k()) { + if (!cobalt_pmu) { + WPRINTK("no PMU found!\n"); + WPRINTK("reboot not possible!\n"); + return; + } + +#ifdef CONFIG_COBALT_WDT + /* stop feeding it */ + del_timer_sync(&cobalt_wdt_timer); +#endif + + /* kiss your rear goodbye... */ + initialized = 0; + hw_disable(); + hw_enable(); + } +} + +#ifdef CONFIG_COBALT_WDT +static void +do_disable(void) +{ + if (!initialized) { + return; + } + + if (atomic_read(&cobalt_wdt_disable_count) == 0) { + atomic_inc(&cobalt_wdt_disable_count); + del_timer_sync(&cobalt_wdt_timer); + hw_disable(); + } +} +#endif + +EXPORT_SYMBOL(cobalt_wdt_disable); +void +cobalt_wdt_disable(void) +{ +#ifdef CONFIG_COBALT_WDT + unsigned long flags; + + if (cobt_is_3k() && use_pic) { + WPRINTK("in PIC mode - cannot disable\n"); + return; + } + + spin_lock_irqsave(&wdt_lock, flags); + do_disable(); + spin_unlock_irqrestore(&wdt_lock, flags); +#endif +} + +#ifdef CONFIG_COBALT_WDT +static void +do_reenable(void) +{ + int dcnt; + + if (!initialized) { + return; + } + + atomic_dec(&cobalt_wdt_disable_count); + dcnt = atomic_read(&cobalt_wdt_disable_count); + + if (dcnt == 0) { + do_refresh(); + } else if (dcnt < 0) { + WPRINTK("too many enables\n"); + atomic_set(&cobalt_wdt_disable_count, 0); + } +} +#endif + + +EXPORT_SYMBOL(cobalt_wdt_reenable); +void +cobalt_wdt_reenable(void) +{ +#ifdef CONFIG_COBALT_WDT + unsigned long flags; + + spin_lock_irqsave(&wdt_lock, flags); + do_reenable(); + spin_unlock_irqrestore(&wdt_lock, flags); +#endif +} diff -ruN linux-2.4.29/drivers/net/wan/sdla_ppp.c linux-2.4.29-BF6-C7_III-grsec/drivers/net/wan/sdla_ppp.c --- linux-2.4.29/drivers/net/wan/sdla_ppp.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/net/wan/sdla_ppp.c 2005-03-21 17:27:01.122270952 -0700 @@ -467,7 +467,7 @@ sdla_t* card = wandev->private; netdevice_t* dev; volatile ppp_private_area_t *ppp_priv_area; - ppp_flags_t *flags = card->flags; + ppp_flags_t *flags; unsigned long timeout; /* sanity checks */ @@ -491,6 +491,7 @@ ppp_priv_area->update_comms_stats = 2; ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; + flags = card->flags; flags->imask |= PPP_INTR_TIMER; /* wait a maximum of 1 second for the statistics to be updated */ diff -ruN linux-2.4.29/drivers/pci/proc.c linux-2.4.29-BF6-C7_III-grsec/drivers/pci/proc.c --- linux-2.4.29/drivers/pci/proc.c 2004-08-07 17:26:05.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/pci/proc.c 2005-03-21 17:27:01.123270804 -0700 @@ -564,7 +564,15 @@ pci_for_each_dev(dev) { pci_proc_attach_device(dev); } +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + entry = create_proc_entry("pci", S_IRUSR, NULL); +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + entry = create_proc_entry("pci", S_IRUSR | S_IRGRP, NULL); +#endif +#else entry = create_proc_entry("pci", 0, NULL); +#endif if (entry) entry->proc_fops = &proc_pci_operations; } diff -ruN linux-2.4.29/drivers/video/vesafb.c linux-2.4.29-BF6-C7_III-grsec/drivers/video/vesafb.c --- linux-2.4.29/drivers/video/vesafb.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/drivers/video/vesafb.c 2005-03-21 17:27:01.124270655 -0700 @@ -546,7 +546,7 @@ video_visual = (video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; -#ifndef __i386__ +#if !defined(__i386__) || defined(CONFIG_GRKERNSEC_PAX_KERNEXEC) screen_info.vesapm_seg = 0; #endif diff -ruN linux-2.4.29/fs/Makefile linux-2.4.29-BF6-C7_III-grsec/fs/Makefile --- linux-2.4.29/fs/Makefile 2004-02-18 06:36:31.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/Makefile 2005-03-21 17:27:01.124270655 -0700 @@ -7,7 +7,7 @@ O_TARGET := fs.o -export-objs := filesystems.o open.o dcache.o buffer.o dquot.o +export-objs := filesystems.o open.o dcache.o buffer.o dquot.o exec.o mod-subdirs := nls obj-y := open.o read_write.o devices.o file_table.o buffer.o \ diff -ruN linux-2.4.29/fs/binfmt_aout.c linux-2.4.29-BF6-C7_III-grsec/fs/binfmt_aout.c --- linux-2.4.29/fs/binfmt_aout.c 2005-01-19 07:10:10.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/binfmt_aout.c 2005-03-21 17:27:01.125270506 -0700 @@ -121,10 +121,12 @@ /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ #ifdef __sparc__ + gr_learn_resource(current, RLIMIT_CORE, dump.u_dsize+dump.u_ssize, 1); if ((dump.u_dsize+dump.u_ssize) > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; #else + gr_learn_resource(current, RLIMIT_CORE, (dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE, 1); if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; @@ -132,10 +134,12 @@ /* Make sure we have enough room to write the stack and data areas. */ #ifdef __sparc__ + gr_learn_resource(current, RLIMIT_CORE, dump.u_ssize, 1); if ((dump.u_ssize) > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; #else + gr_learn_resource(current, RLIMIT_CORE, (dump.u_ssize+1) * PAGE_SIZE, 1); if ((dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; @@ -284,6 +288,8 @@ rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; + + gr_learn_resource(current, RLIMIT_DATA, ex.a_data + ex.a_bss, 1); if (ex.a_data + ex.a_bss > rlim) return -ENOMEM; @@ -315,6 +321,24 @@ current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (!(N_FLAGS(ex) & F_PAX_PAGEEXEC)) { + current->flags |= PF_PAX_PAGEEXEC; + +#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 + + } +#endif + #ifdef __sparc__ if (N_MAGIC(ex) == NMAGIC) { loff_t pos = fd_offset; @@ -408,7 +432,7 @@ down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); up_write(¤t->mm->mmap_sem); diff -ruN linux-2.4.29/fs/binfmt_elf.c linux-2.4.29-BF6-C7_III-grsec/fs/binfmt_elf.c --- linux-2.4.29/fs/binfmt_elf.c 2005-01-19 07:10:10.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/binfmt_elf.c 2005-03-21 17:27:01.127270209 -0700 @@ -33,10 +33,13 @@ #include #include #include +#include +#include #include #include #include +#include #define DLINFO_ITEMS 13 @@ -81,18 +84,30 @@ static int set_brk(unsigned long start, unsigned long end) { + unsigned long e = end, retval; + start = ELF_PAGEALIGN(start); end = ELF_PAGEALIGN(end); + + down_write(¤t->mm->mmap_sem); if (end > start) { - unsigned long addr; - down_write(¤t->mm->mmap_sem); - addr = do_brk(start, end - start); - up_write(¤t->mm->mmap_sem); - if (BAD_ADDR(addr)) - return addr; - } - current->mm->start_brk = current->mm->brk = end; - return 0; + retval = do_brk(start, end - start); + if (BAD_ADDR(retval)) + goto out; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if (current->flags & PF_PAX_RANDEXEC) + retval = __do_mmap_pgoff(NULL, ELF_PAGEALIGN(start + current->mm->delta_exec), 0UL, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_MIRROR, start); + if (BAD_ADDR(retval)) + goto out; +#endif + + } + current->mm->start_brk = current->mm->brk = e; + retval = 0UL; +out: + up_write(¤t->mm->mmap_sem); + return retval; } @@ -452,6 +467,203 @@ return elf_entry; } +#if (defined(CONFIG_GRKERNSEC_PAX_EI_PAX) || defined(CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS)) && defined(CONFIG_GRKERNSEC_PAX_SOFTMODE) +static unsigned long pax_parse_softmode(const struct elf_phdr * const elf_phdata) +{ + unsigned long pax_flags = 0UL; + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (elf_phdata->p_flags & PF_PAGEEXEC) + pax_flags |= PF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (elf_phdata->p_flags & PF_SEGMEXEC) { + pax_flags &= ~PF_PAX_PAGEEXEC; + pax_flags |= PF_PAX_SEGMEXEC; + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + if (elf_phdata->p_flags & PF_EMUTRAMP) + pax_flags |= PF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_MPROTECT + if (elf_phdata->p_flags & PF_MPROTECT) + pax_flags |= PF_PAX_MPROTECT; +#endif + +#if defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) || defined(CONFIG_GRKERNSEC_PAX_RANDUSTACK) + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_aslr) +#endif + + if (elf_phdata->p_flags & PF_RANDMMAP) + pax_flags |= PF_PAX_RANDMMAP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_aslr) +#endif + + if (elf_phdata->p_flags & PF_RANDEXEC) + pax_flags |= PF_PAX_RANDEXEC; +#endif + + return pax_flags; +} +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS +static unsigned long pax_parse_hardmode(const struct elf_phdr * const elf_phdata) +{ + unsigned long pax_flags = 0UL; + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (!(elf_phdata->p_flags & PF_NOPAGEEXEC)) + pax_flags |= PF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (!(elf_phdata->p_flags & PF_NOSEGMEXEC)) { + pax_flags &= ~PF_PAX_PAGEEXEC; + pax_flags |= PF_PAX_SEGMEXEC; + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + if (!(elf_phdata->p_flags & PF_NOEMUTRAMP)) + pax_flags |= PF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_MPROTECT + if (!(elf_phdata->p_flags & PF_NOMPROTECT)) + pax_flags |= PF_PAX_MPROTECT; +#endif + +#if defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) || defined(CONFIG_GRKERNSEC_PAX_RANDUSTACK) + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_aslr) +#endif + + if (!(elf_phdata->p_flags & PF_NORANDMMAP)) + pax_flags |= PF_PAX_RANDMMAP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_aslr) +#endif + + if (!(elf_phdata->p_flags & PF_NORANDEXEC)) + pax_flags |= PF_PAX_RANDEXEC; +#endif + + return pax_flags; +} +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EI_PAX +static int pax_parse_ei_pax(const struct elfhdr * const elf_ex) +{ + unsigned long pax_flags = 0UL; + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (!(elf_ex->e_ident[EI_PAX] & EF_PAX_PAGEEXEC)) + pax_flags |= PF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (!(elf_ex->e_ident[EI_PAX] & EF_PAX_SEGMEXEC)) { + pax_flags &= ~PF_PAX_PAGEEXEC; + pax_flags |= PF_PAX_SEGMEXEC; + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + if ((pax_flags & (PF_PAX_PAGEEXEC | PF_PAX_SEGMEXEC)) && (elf_ex->e_ident[EI_PAX] & EF_PAX_EMUTRAMP)) + pax_flags |= PF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_MPROTECT + if ((pax_flags & (PF_PAX_PAGEEXEC | PF_PAX_SEGMEXEC)) && !(elf_ex->e_ident[EI_PAX] & EF_PAX_MPROTECT)) + pax_flags |= PF_PAX_MPROTECT; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_ASLR + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_aslr) +#endif + + if (!(elf_ex->e_ident[EI_PAX] & EF_PAX_RANDMMAP)) + pax_flags |= PF_PAX_RANDMMAP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_aslr) +#endif + + if ((elf_ex->e_ident[EI_PAX] & EF_PAX_RANDEXEC) && (elf_ex->e_type == ET_EXEC) && (pax_flags & PF_PAX_MPROTECT)) + pax_flags |= PF_PAX_RANDEXEC; +#endif + + return pax_flags; +} +#endif + +#if defined(CONFIG_GRKERNSEC_PAX_EI_PAX) || defined(CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS) +static int pax_parse_elf_flags(const struct elfhdr * const elf_ex, const struct elf_phdr * const elf_phdata) +{ + unsigned long pax_flags = 0UL; + +#ifdef CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS + unsigned long i; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_EI_PAX + pax_flags = pax_parse_ei_pax(elf_ex); +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS + for (i = 0UL; i < elf_ex->e_phnum; i++) + if (elf_phdata[i].p_type == PT_PAX_FLAGS) { + if (((elf_phdata[i].p_flags & PF_PAGEEXEC) && (elf_phdata[i].p_flags & PF_NOPAGEEXEC)) || + ((elf_phdata[i].p_flags & PF_SEGMEXEC) && (elf_phdata[i].p_flags & PF_NOSEGMEXEC)) || + ((elf_phdata[i].p_flags & PF_EMUTRAMP) && (elf_phdata[i].p_flags & PF_NOEMUTRAMP)) || + ((elf_phdata[i].p_flags & PF_MPROTECT) && (elf_phdata[i].p_flags & PF_NOMPROTECT)) || + ((elf_phdata[i].p_flags & PF_RANDMMAP) && (elf_phdata[i].p_flags & PF_NORANDMMAP)) || + ((elf_phdata[i].p_flags & PF_RANDEXEC) && ((elf_phdata[i].p_flags & PF_NORANDEXEC) || elf_ex->e_type == ET_DYN || !(elf_phdata[i].p_flags & PF_MPROTECT))) || + (!(elf_phdata[i].p_flags & PF_NORANDEXEC) && (elf_ex->e_type == ET_DYN || (elf_phdata[i].p_flags & PF_NOMPROTECT)))) + return -EINVAL; + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_softmode) + pax_flags = pax_parse_softmode(&elf_phdata[i]); + else +#endif + + pax_flags = pax_parse_hardmode(&elf_phdata[i]); + break; + } +#endif + + if (0 > pax_check_flags(&pax_flags)) + return -EINVAL; + + current->flags |= pax_flags; + return 0; +} +#endif + /* * These are the functions used to load ELF style executables and shared * libraries. There is no binary dependent code anywhere else. @@ -484,6 +696,11 @@ struct exec interp_ex; char passed_fileno[6]; struct files_struct *files; + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + unsigned long load_addr_random = 0UL; + unsigned long load_bias_random = 0UL; +#endif /* Get the exec-header */ elf_ex = *((struct elfhdr *) bprm->buf); @@ -679,7 +896,47 @@ current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; + +#ifdef CONFIG_GRKERNSEC_PAX_DLRESOLVE + current->mm->call_dl_resolve = 0UL; +#endif + +#if defined(CONFIG_PPC32) && defined(CONFIG_GRKERNSEC_PAX_EMUSIGRT) + current->mm->call_syscall = 0UL; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_ASLR + current->mm->delta_mmap = 0UL; + current->mm->delta_exec = 0UL; + current->mm->delta_stack = 0UL; +#endif + current->flags &= ~PF_FORKNOEXEC; + +#if defined(CONFIG_GRKERNSEC_PAX_EI_PAX) || defined(CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS) + if (0 > pax_parse_elf_flags(&elf_ex, elf_phdata)) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_HAVE_ACL_FLAGS + pax_set_flags(bprm); +#elif defined(CONFIG_GRKERNSEC_PAX_HOOK_ACL_FLAGS) + if (pax_set_flags_func) + (*pax_set_flags_func)(bprm); +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_ASLR + if (current->flags & PF_PAX_RANDMMAP) { +#define pax_delta_mask(delta, lsb, len) (((delta) & ((1UL << (len)) - 1)) << (lsb)) + + current->mm->delta_mmap = pax_delta_mask(get_random_long(), PAX_DELTA_MMAP_LSB(current), PAX_DELTA_MMAP_LEN(current)); + current->mm->delta_exec = pax_delta_mask(get_random_long(), PAX_DELTA_EXEC_LSB(current), PAX_DELTA_EXEC_LEN(current)); + current->mm->delta_stack = pax_delta_mask(get_random_long(), PAX_DELTA_STACK_LSB(current), PAX_DELTA_STACK_LEN(current)); + } +#endif + elf_entry = (unsigned long) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will @@ -688,7 +945,7 @@ retval = setup_arg_pages(bprm); if (retval < 0) { send_sig(SIGKILL, current, 0); - return retval; + goto out_free_dentry; } current->mm->start_stack = bprm->p; @@ -740,12 +997,92 @@ 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(PAX_ELF_ET_DYN_BASE(current) - vaddr + current->mm->delta_exec); + elf_flags |= MAP_FIXED; + } +#endif + } - error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); - if (BAD_ADDR(error)) { - send_sig(SIGKILL, current, 0); - goto out_free_dentry; +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + if ((current->flags & PF_PAX_RANDEXEC) && (elf_ex.e_type == ET_EXEC)) { + error = -ENOMEM; + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (current->flags & PF_PAX_PAGEEXEC) + error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot & ~PROT_EXEC, elf_flags); +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (current->flags & PF_PAX_SEGMEXEC) { + unsigned long addr, len; + + addr = ELF_PAGESTART(load_bias + vaddr); + len = elf_ppnt->p_filesz + ELF_PAGEOFFSET(elf_ppnt->p_vaddr); + if (len > SEGMEXEC_TASK_SIZE || addr > SEGMEXEC_TASK_SIZE-len) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } + down_write(¤t->mm->mmap_sem); + error = __do_mmap_pgoff(bprm->file, addr, len, elf_prot, elf_flags, (elf_ppnt->p_offset - ELF_PAGEOFFSET(elf_ppnt->p_vaddr)) >> PAGE_SHIFT); + up_write(¤t->mm->mmap_sem); + } +#endif + + if (BAD_ADDR(error)) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } + + /* PaX: mirror at a randomized base */ + down_write(¤t->mm->mmap_sem); + + if (!load_addr_set) { + load_addr_random = get_unmapped_area(bprm->file, 0UL, elf_ppnt->p_memsz + ELF_PAGEOFFSET(elf_ppnt->p_vaddr), (elf_ppnt->p_offset - ELF_PAGEOFFSET(elf_ppnt->p_vaddr)) >> PAGE_SHIFT, MAP_PRIVATE); + if (BAD_ADDR(load_addr_random)) { + up_write(¤t->mm->mmap_sem); + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } + load_bias_random = load_addr_random - vaddr; + } + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (current->flags & PF_PAX_PAGEEXEC) + load_addr_random = __do_mmap_pgoff(NULL, ELF_PAGESTART(load_bias_random + vaddr), 0UL, elf_prot, elf_flags | MAP_MIRROR, error); +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (current->flags & PF_PAX_SEGMEXEC) { + if (elf_prot & PROT_EXEC) { + load_addr_random = __do_mmap_pgoff(NULL, ELF_PAGESTART(load_bias_random + vaddr), elf_ppnt->p_memsz + ELF_PAGEOFFSET(elf_ppnt->p_vaddr), PROT_NONE, MAP_PRIVATE | MAP_FIXED, 0UL); + if (!BAD_ADDR(load_addr_random)) { + load_addr_random = __do_mmap_pgoff(NULL, ELF_PAGESTART(load_bias_random + vaddr + SEGMEXEC_TASK_SIZE), 0UL, elf_prot, elf_flags | MAP_MIRROR, error); + if (!BAD_ADDR(load_addr_random)) + load_addr_random -= SEGMEXEC_TASK_SIZE; + } + } else + load_addr_random = __do_mmap_pgoff(NULL, ELF_PAGESTART(load_bias_random + vaddr), 0UL, elf_prot, elf_flags | MAP_MIRROR, error); + } +#endif + + up_write(¤t->mm->mmap_sem); + if (BAD_ADDR(load_addr_random)) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } + } else +#endif + { + error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); + if (BAD_ADDR(error)) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } } if (!load_addr_set) { @@ -757,6 +1094,11 @@ load_addr += load_bias; reloc_func_desc = load_addr; } + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + current->mm->delta_exec = load_addr_random - load_addr; +#endif + } k = elf_ppnt->p_vaddr; if (k < start_code) start_code = k; @@ -796,6 +1138,17 @@ start_data += load_bias; end_data += load_bias; +#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_aslr) +#endif + + if (current->flags & PF_PAX_RANDMMAP) + elf_brk += PAGE_SIZE + pax_delta_mask(get_random_long(), 4, PAGE_SHIFT); +#undef pax_delta_mask +#endif + /* Calling set_brk effectively mmaps the pages that we need * for the bss and break sections. We must do this before * mapping in the interpreter, to make sure it doesn't wind @@ -893,6 +1246,10 @@ ELF_PLAT_INIT(regs, reloc_func_desc); #endif +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + pax_switch_segments(current); +#endif + start_thread(regs, elf_entry, bprm->p); if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); @@ -1124,8 +1481,11 @@ #undef DUMP_SEEK #define DUMP_WRITE(addr, nr) \ + do { \ + gr_learn_resource(current, RLIMIT_CORE, size + (nr), 1); \ if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ - goto end_coredump; + goto end_coredump; \ + } while (0); #define DUMP_SEEK(off) \ if (!dump_seek(file, (off))) \ goto end_coredump; diff -ruN linux-2.4.29/fs/binfmt_misc.c linux-2.4.29-BF6-C7_III-grsec/fs/binfmt_misc.c --- linux-2.4.29/fs/binfmt_misc.c 2002-08-02 18:39:45.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/fs/binfmt_misc.c 2005-03-21 17:27:01.128270060 -0700 @@ -102,9 +102,11 @@ int retval; retval = -ENOEXEC; - if (!enabled) + if (!enabled || bprm->misc) goto _ret; + bprm->misc++; + /* to keep locking time low, we copy the interpreter string */ read_lock(&entries_lock); fmt = check_file(bprm); diff -ruN linux-2.4.29/fs/buffer.c linux-2.4.29-BF6-C7_III-grsec/fs/buffer.c --- linux-2.4.29/fs/buffer.c 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/buffer.c 2005-03-21 17:27:01.129269912 -0700 @@ -1865,6 +1865,9 @@ int err; err = -EFBIG; + + gr_learn_resource(current, RLIMIT_FSIZE, (unsigned long) size, 1); + limit = current->rlim[RLIMIT_FSIZE].rlim_cur; if (limit != RLIM_INFINITY && size > (loff_t)limit) { send_sig(SIGXFSZ, current, 0); diff -ruN linux-2.4.29/fs/exec.c linux-2.4.29-BF6-C7_III-grsec/fs/exec.c --- linux-2.4.29/fs/exec.c 2005-01-19 07:10:10.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/exec.c 2005-03-21 17:27:01.131269614 -0700 @@ -43,6 +43,9 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_KMOD #include @@ -56,6 +59,20 @@ static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + +#if defined(CONFIG_GRKERNSEC_PAX_RANDMMAP) || defined(CONFIG_GRKERNSEC_PAX_RANDUSTACK) || defined(CONFIG_GRKERNSEC_PAX_RANDKSTACK) +unsigned int pax_aslr=1; +#endif + +unsigned int pax_softmode; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_HOOK_ACL_FLAGS +void (*pax_set_flags_func)(struct linux_binprm *bprm); +EXPORT_SYMBOL(pax_set_flags_func); +#endif + int register_binfmt(struct linux_binfmt * fmt) { struct linux_binfmt ** tmp = &formats; @@ -290,7 +307,11 @@ struct vm_area_struct *vma; pgprot_t prot = PAGE_COPY; +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (page_count(page) != 1 && (!(tsk->flags & PF_PAX_SEGMEXEC) || page_count(page) != 2)) +#else if (page_count(page) != 1) +#endif printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address); pgd = pgd_offset(tsk->mm, address); @@ -303,9 +324,19 @@ goto out; if (!pte_none(*pte)) goto out; + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (page_count(page) == 1) { +#endif + lru_cache_add(page); flush_dcache_page(page); flush_page_to_ram(page); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + } +#endif + /* lookup is cheap because there is only a single entry in the list */ vma = find_vma(tsk->mm, address); if (vma) @@ -329,6 +360,10 @@ struct vm_area_struct *mpnt; int i, ret; +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + struct vm_area_struct *mpnt_m = NULL; +#endif + stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; bprm->p += stack_base; @@ -340,23 +375,58 @@ if (!mpnt) return -ENOMEM; +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if ((current->flags & PF_PAX_SEGMEXEC) && (VM_STACK_FLAGS & VM_MAYEXEC)) { + mpnt_m = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!mpnt_m) { + kmem_cache_free(vm_area_cachep, mpnt); + return -ENOMEM; + } + } +#endif + down_write(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = STACK_TOP; mpnt->vm_flags = VM_STACK_FLAGS; +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (!(current->flags & PF_PAX_PAGEEXEC)) + mpnt->vm_page_prot = protection_map[(VM_STACK_FLAGS | VM_EXEC) & 0x7]; + else +#endif mpnt->vm_page_prot = protection_map[VM_STACK_FLAGS & 0x7]; mpnt->vm_ops = NULL; mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = (void *) 0; + mpnt->vm_mirror = 0; if ((ret = insert_vm_struct(current->mm, mpnt))) { up_write(¤t->mm->mmap_sem); kmem_cache_free(vm_area_cachep, mpnt); return ret; } current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (mpnt_m) { + *mpnt_m = *mpnt; + if (!(VM_STACK_FLAGS & VM_EXEC)) { + mpnt_m->vm_flags &= ~(VM_READ | VM_WRITE | VM_EXEC); + mpnt_m->vm_page_prot = PAGE_NONE; + } + mpnt_m->vm_start += SEGMEXEC_TASK_SIZE; + mpnt_m->vm_end += SEGMEXEC_TASK_SIZE; + mpnt_m->vm_flags |= VM_MIRROR; + mpnt->vm_flags |= VM_MIRROR; + mpnt_m->vm_mirror = mpnt->vm_start - mpnt_m->vm_start; + mpnt->vm_mirror = mpnt_m->vm_start - mpnt->vm_start; + insert_vm_struct(current->mm, mpnt_m); + current->mm->total_vm += (mpnt_m->vm_end - mpnt_m->vm_start) >> PAGE_SHIFT; + } +#endif + } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -364,6 +434,14 @@ if (page) { bprm->page[i] = NULL; put_dirty_page(current,page,stack_base); + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + if (mpnt_m) { + page_cache_get(page); + put_dirty_page(current, page, stack_base + SEGMEXEC_TASK_SIZE); + } +#endif + } stack_base += PAGE_SIZE; } @@ -637,6 +715,30 @@ tcomm[i] = '\0'; set_task_comm(current, tcomm); +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + 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_ASLR + current->flags &= ~PF_PAX_RANDMMAP; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + current->flags &= ~PF_PAX_RANDEXEC; +#endif + +#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC + current->flags &= ~PF_PAX_SEGMEXEC; +#endif + flush_thread(); de_thread(current); @@ -798,8 +900,13 @@ /* AUD: Audit candidate if current->cap_effective is set */ - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; + if (!gr_check_user_change(-1, bprm->e_uid, bprm->e_uid)) + current->suid = current->euid = current->fsuid = bprm->e_uid; + + if (!gr_check_group_change(-1, bprm->e_gid, bprm->e_gid)) + current->sgid = current->egid = current->fsgid = bprm->e_gid; + + gr_handle_chroot_caps(current); if(do_unlock) unlock_kernel(); @@ -934,6 +1041,11 @@ struct file *file; int retval; int i; +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif file = open_exec(filename); @@ -941,12 +1053,37 @@ if (IS_ERR(file)) return retval; + gr_learn_resource(current, RLIMIT_NPROC, atomic_read(¤t->user->processes), 1); + + if (gr_handle_nproc()) { + allow_write_access(file); + fput(file); + return -EAGAIN; + } + + if (!gr_acl_handle_execve(file->f_dentry, file->f_vfsmnt)) { + allow_write_access(file); + fput(file); + return -EACCES; + } + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + +#ifdef CONFIG_GRKERNSEC_PAX_RANDUSTACK + +#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE + if (pax_aslr) +#endif + + bprm.p -= (get_random_long() & ~(sizeof(void *)-1)) & ~PAGE_MASK; +#endif + memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); bprm.file = file; bprm.filename = filename; bprm.sh_bang = 0; + bprm.misc = 0; bprm.loader = 0; bprm.exec = 0; if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) { @@ -965,11 +1102,26 @@ if (retval < 0) goto out; + if (!gr_tpe_allow(file)) { + retval = -EACCES; + goto out; + } + + if(gr_check_crash_exec(file)) { + retval = -EACCES; + goto out; + } + retval = copy_strings_kernel(1, &bprm.filename, &bprm); if (retval < 0) goto out; bprm.exec = bprm.p; + + gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); + + gr_handle_exec_args(&bprm, argv); + retval = copy_strings(bprm.envc, envp, &bprm); if (retval < 0) goto out; @@ -978,11 +1130,35 @@ if (retval < 0) goto out; +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->rlim, sizeof(old_rlim)); + old_exec_file = current->exec_file; + get_file(file); + current->exec_file = file; +#endif + + retval = gr_set_proc_label(file->f_dentry, file->f_vfsmnt); + if (retval < 0) + goto out_fail; + retval = search_binary_handler(&bprm,regs); - if (retval >= 0) + if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif /* execve success */ return retval; + } +out_fail: +#ifdef CONFIG_GRKERNSEC + current->acl = old_acl; + memcpy(current->rlim, old_rlim, sizeof(old_rlim)); + fput(current->exec_file); + current->exec_file = old_exec_file; +#endif out: /* Something went wrong, return the inode and free the argument pages*/ allow_write_access(bprm.file); @@ -1124,6 +1300,126 @@ *out_ptr = 0; } +int pax_check_flags(unsigned long * flags) +{ + int retval = 0; + +#if !defined(__i386__) || !defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) + if (*flags & PF_PAX_SEGMEXEC) + { + *flags &= ~PF_PAX_SEGMEXEC; + retval = -EINVAL; + } +#endif + + if ((*flags & PF_PAX_PAGEEXEC) + +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + && (*flags & PF_PAX_SEGMEXEC) +#endif + + ) + { + *flags &= ~PF_PAX_PAGEEXEC; + retval = -EINVAL; + } + + if ((*flags & PF_PAX_MPROTECT) + +#ifdef CONFIG_GRKERNSEC_PAX_MPROTECT + && !(*flags & (PF_PAX_PAGEEXEC | PF_PAX_SEGMEXEC)) +#endif + + ) + { + *flags &= ~PF_PAX_MPROTECT; + retval = -EINVAL; + } + + if ((*flags & PF_PAX_EMUTRAMP) + +#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP + && !(*flags & (PF_PAX_PAGEEXEC | PF_PAX_SEGMEXEC)) +#endif + + ) + { + *flags &= ~PF_PAX_EMUTRAMP; + retval = -EINVAL; + } + + if ((*flags & PF_PAX_RANDEXEC) + +#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC + && !(*flags & PF_PAX_MPROTECT) +#endif + + ) + { + *flags &= ~PF_PAX_RANDEXEC; + retval = -EINVAL; + } + + return retval; +} + +EXPORT_SYMBOL(pax_check_flags); + +#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) +void pax_report_fault(struct pt_regs *regs, void *pc, void *sp) +{ + struct task_struct *tsk = current; + struct mm_struct *mm = current->mm; + char* buffer_exec = (char*)__get_free_page(GFP_ATOMIC); + char* buffer_fault = (char*)__get_free_page(GFP_ATOMIC); + char* path_exec=NULL; + char* path_fault=NULL; + unsigned long start=0UL, end=0UL, offset=0UL; + + if (buffer_exec && buffer_fault) { + struct vm_area_struct* vma, * vma_exec=NULL, * vma_fault=NULL; + + down_read(&mm->mmap_sem); + vma = mm->mmap; + while (vma && (!vma_exec || !vma_fault)) { + if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) + vma_exec = vma; + if (vma->vm_start <= (unsigned long)pc && (unsigned long)pc < vma->vm_end) + vma_fault = vma; + vma = vma->vm_next; + } + if (vma_exec) { + path_exec = d_path(vma_exec->vm_file->f_dentry, vma_exec->vm_file->f_vfsmnt, buffer_exec, PAGE_SIZE); + if (IS_ERR(path_exec)) + path_exec = ""; + } + if (vma_fault) { + start = vma_fault->vm_start; + end = vma_fault->vm_end; + offset = vma_fault->vm_pgoff << PAGE_SHIFT; + if (vma_fault->vm_file) { + path_fault = d_path(vma_fault->vm_file->f_dentry, vma_fault->vm_file->f_vfsmnt, buffer_fault, PAGE_SIZE); + if (IS_ERR(path_fault)) + path_fault = ""; + } else + path_fault = ""; + } + up_read(&mm->mmap_sem); + } + if (tsk->curr_ip) + printk(KERN_ERR "PAX: From %u.%u.%u.%u: execution attempt in: %s, %08lx-%08lx %08lx\n", NIPQUAD(tsk->curr_ip), path_fault, start, end, offset); + else + printk(KERN_ERR "PAX: execution attempt in: %s, %08lx-%08lx %08lx\n", path_fault, start, end, offset); + printk(KERN_ERR "PAX: terminating task: %s(%s):%d, uid/euid: %u/%u, " + "PC: %p, SP: %p\n", path_exec, tsk->comm, tsk->pid, + tsk->uid, tsk->euid, pc, sp); + free_page((unsigned long)buffer_exec); + free_page((unsigned long)buffer_fault); + pax_report_insns(pc, sp); + do_coredump(SIGKILL, regs); +} +#endif + int do_coredump(long signr, struct pt_regs * regs) { struct linux_binfmt * binfmt; @@ -1144,6 +1440,11 @@ current->fsuid = 0; } current->mm->dumpable = 0; + + if (signr == SIGKILL || signr == SIGILL) + gr_handle_brute_attach(current); + + gr_learn_resource(current, RLIMIT_CORE, binfmt->min_coredump, 1); if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) goto fail; @@ -1163,7 +1464,7 @@ goto close_fail; if (!file->f_op->write) goto close_fail; - if (do_truncate(file->f_dentry, 0) != 0) + if (do_truncate(file->f_dentry, 0, file->f_vfsmnt) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file); diff -ruN linux-2.4.29/fs/fcntl.c linux-2.4.29-BF6-C7_III-grsec/fs/fcntl.c --- linux-2.4.29/fs/fcntl.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/fcntl.c 2005-03-21 17:27:01.132269466 -0700 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,8 @@ int error; int start; + gr_learn_resource(current, RLIMIT_NOFILE, orig_start, 0); + write_lock(&files->file_lock); error = -EINVAL; @@ -87,6 +90,7 @@ } error = -EMFILE; + gr_learn_resource(current, RLIMIT_NOFILE, newfd, 0); if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out; @@ -142,6 +146,8 @@ struct file * file, *tofree; struct files_struct * files = current->files; + gr_learn_resource(current, RLIMIT_NOFILE, newfd, 0); + write_lock(&files->file_lock); if (!(file = fcheck(oldfd))) goto out_unlock; diff -ruN linux-2.4.29/fs/namei.c linux-2.4.29-BF6-C7_III-grsec/fs/namei.c --- linux-2.4.29/fs/namei.c 2005-01-19 07:10:11.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/namei.c 2005-03-21 17:27:01.134269168 -0700 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -343,6 +344,13 @@ current->state = TASK_RUNNING; schedule(); } + + if (gr_handle_follow_link(dentry->d_parent->d_inode, + dentry->d_inode, dentry, nd->mnt)) { + path_release(nd); + return -EACCES; + } + current->link_count++; current->total_link_count++; UPDATE_ATIME(dentry->d_inode); @@ -643,11 +651,18 @@ } } return_base: + if (!gr_acl_handle_hidden_file(nd->dentry, nd->mnt)) { + path_release(nd); + return -ENOENT; + } return 0; out_dput: dput(dentry); break; } + if (!gr_acl_handle_hidden_file(nd->dentry, nd->mnt)) + err = -ENOENT; + path_release(nd); return_err: return err; @@ -1005,7 +1020,7 @@ struct dentry *dentry; struct dentry *dir; int count = 0; - + acc_mode = ACC_MODE(flag); /* @@ -1015,7 +1030,19 @@ error = path_lookup(pathname, lookup_flags(flag), nd); if (error) return error; + + if (gr_handle_rawio(nd->dentry->d_inode)) { + error = -EPERM; + goto exit; + } + + if (!gr_acl_handle_open(nd->dentry, nd->mnt, flag)) { + error = -EACCES; + goto exit; + } + dentry = nd->dentry; + goto ok; } @@ -1048,8 +1075,22 @@ /* Negative dentry, just create the file */ if (!dentry->d_inode) { + if (gr_handle_chroot_chmod(dentry, nd->mnt, mode)) { + error = -EACCES; + up(&dir->d_inode->i_sem); + goto exit_dput; + } + if (!gr_acl_handle_creat(dentry, nd->dentry, nd->mnt, flag, mode)) { + error = -EACCES; + up(&dir->d_inode->i_sem); + goto exit_dput; + } + error = vfs_create(dir->d_inode, dentry, mode & ~current->fs->umask); + if (!error) + gr_handle_create(dentry, nd->mnt); + up(&dir->d_inode->i_sem); dput(nd->dentry); nd->dentry = dentry; @@ -1058,12 +1099,34 @@ /* Don't check for write permission, don't truncate */ acc_mode = 0; flag &= ~O_TRUNC; + goto ok; } /* * It already exists. */ + + if (gr_handle_rawio(dentry->d_inode)) { + error = -EPERM; + up(&dir->d_inode->i_sem); + goto exit_dput; + } + + if (!gr_acl_handle_open(dentry, nd->mnt, flag)) { + error = -EACCES; + up(&dir->d_inode->i_sem); + goto exit_dput; + } + + inode = dentry->d_inode; + + if (gr_handle_fifo(dentry, nd->mnt, dir, flag, acc_mode)) { + up(&dir->d_inode->i_sem); + error = -EACCES; + goto exit_dput; + } + up(&dir->d_inode->i_sem); error = -EEXIST; @@ -1153,7 +1216,7 @@ if (!error) { DQUOT_INIT(inode); - error = do_truncate(dentry, 0); + error = do_truncate(dentry,0,nd->mnt); } put_write_access(inode); if (error) @@ -1184,6 +1247,13 @@ * stored in nd->last.name and we will have to putname() it when we * are done. Procfs-like symlinks just set LAST_BIND. */ + + if (gr_handle_follow_link(dentry->d_parent->d_inode, dentry->d_inode, + dentry, nd->mnt)) { + error = -EACCES; + goto exit_dput; + } + UPDATE_ATIME(dentry->d_inode); error = dentry->d_inode->i_op->follow_link(dentry, nd); dput(dentry); @@ -1282,6 +1352,19 @@ mode &= ~current->fs->umask; if (!IS_ERR(dentry)) { + if (gr_handle_chroot_mknod(dentry, nd.mnt, mode) || + gr_handle_chroot_chmod(dentry, nd.mnt, mode)) { + error = -EPERM; + dput(dentry); + goto out_dput; + } + + if (!gr_acl_handle_mknod(dentry, nd.dentry, nd.mnt, mode)) { + error = -EACCES; + dput(dentry); + goto out_dput; + } + switch (mode & S_IFMT) { case 0: case S_IFREG: error = vfs_create(nd.dentry->d_inode,dentry,mode); @@ -1295,8 +1378,13 @@ default: error = -EINVAL; } + + if(!error) + gr_handle_create(dentry, nd.mnt); + dput(dentry); } +out_dput: up(&nd.dentry->d_inode->i_sem); path_release(&nd); out: @@ -1348,8 +1436,17 @@ dentry = lookup_create(&nd, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_mkdir(nd.dentry->d_inode, dentry, + error = 0; + + if (!gr_acl_handle_mkdir(dentry, nd.dentry, nd.mnt)) + error = -EACCES; + + if(!error) + error = vfs_mkdir(nd.dentry->d_inode, dentry, mode & ~current->fs->umask); + if(!error) + gr_handle_create(dentry, nd.mnt); + dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1433,6 +1530,8 @@ char * name; struct dentry *dentry; struct nameidata nd; + ino_t saved_ino = 0; + kdev_t saved_dev = 0; name = getname(pathname); if(IS_ERR(name)) @@ -1457,7 +1556,22 @@ dentry = lookup_hash(&nd.last, nd.dentry); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_rmdir(nd.dentry->d_inode, dentry); + error = 0; + if (dentry->d_inode) { + if (dentry->d_inode->i_nlink <= 1) { + saved_ino = dentry->d_inode->i_ino; + saved_dev = dentry->d_inode->i_dev; + } + + if (!gr_acl_handle_rmdir(dentry, nd.mnt)) + error = -EACCES; + } + + if (!error) + error = vfs_rmdir(nd.dentry->d_inode, dentry); + if (!error && (saved_dev || saved_ino)) + gr_handle_delete(saved_ino,saved_dev); + dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1501,6 +1615,8 @@ char * name; struct dentry *dentry; struct nameidata nd; + ino_t saved_ino = 0; + kdev_t saved_dev = 0; name = getname(pathname); if(IS_ERR(name)) @@ -1519,7 +1635,21 @@ /* 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); + error = 0; + if (dentry->d_inode) { + if (dentry->d_inode->i_nlink <= 1) { + saved_ino = dentry->d_inode->i_ino; + saved_dev = dentry->d_inode->i_dev; + } + + if (!gr_acl_handle_unlink(dentry, nd.mnt)) + error = -EACCES; + } + + if (!error) + error = vfs_unlink(nd.dentry->d_inode, dentry); + if (!error && (saved_ino || saved_dev)) + gr_handle_delete(saved_ino,saved_dev); exit2: dput(dentry); } @@ -1583,7 +1713,15 @@ dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_symlink(nd.dentry->d_inode, dentry, from); + error = 0; + + if (!gr_acl_handle_symlink(dentry, nd.dentry, nd.mnt, from)) + error = -EACCES; + + if(!error) + error = vfs_symlink(nd.dentry->d_inode, dentry, from); + if (!error) + gr_handle_create(dentry, nd.mnt); dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1667,7 +1805,27 @@ new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { - error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); + error = 0; + + if (gr_handle_hardlink(old_nd.dentry, old_nd.mnt, + old_nd.dentry->d_inode, + old_nd.dentry->d_inode->i_mode, to)) { + error = -EPERM; + goto out_error; + } + + if (!gr_acl_handle_link(new_dentry, nd.dentry, nd.mnt, + old_nd.dentry, old_nd.mnt, to)) { + error = -EACCES; + goto out_error; + } + + error = vfs_link(old_nd.dentry, + nd.dentry->d_inode, new_dentry); + + if (!error) + gr_handle_create(new_dentry, nd.mnt); +out_error: dput(new_dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1898,10 +2056,15 @@ if (IS_ERR(new_dentry)) goto exit4; - lock_kernel(); - error = vfs_rename(old_dir->d_inode, old_dentry, + error = gr_acl_handle_rename(new_dentry, newnd.dentry, newnd.mnt, + old_dentry, old_dir->d_inode, oldnd.mnt, newname); + + if (error == 1) { + lock_kernel(); + error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); - unlock_kernel(); + unlock_kernel(); + } dput(new_dentry); exit4: diff -ruN linux-2.4.29/fs/namespace.c linux-2.4.29-BF6-C7_III-grsec/fs/namespace.c --- linux-2.4.29/fs/namespace.c 2004-02-18 06:36:31.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/namespace.c 2005-03-21 17:27:01.135269020 -0700 @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -325,6 +326,8 @@ lock_kernel(); retval = do_remount_sb(sb, MS_RDONLY, 0); unlock_kernel(); + + gr_log_remount(mnt->mnt_devname, retval); } up_write(&sb->s_umount); return retval; @@ -350,6 +353,9 @@ } spin_unlock(&dcache_lock); up_write(¤t->namespace->sem); + + gr_log_unmount(mnt->mnt_devname, retval); + return retval; } @@ -732,6 +738,12 @@ if (retval) return retval; + if (gr_handle_chroot_mount(nd.dentry, nd.mnt, dev_name)) { + retval = -EPERM; + path_release(&nd); + return retval; + } + if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, data_page); @@ -743,6 +755,9 @@ retval = do_add_mount(&nd, type_page, flags, mnt_flags, dev_name, data_page); path_release(&nd); + + gr_log_mount(dev_name, dir_name, retval); + return retval; } @@ -912,6 +927,9 @@ if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (gr_handle_chroot_pivot()) + return -EPERM; + lock_kernel(); error = __user_walk(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd); diff -ruN linux-2.4.29/fs/open.c linux-2.4.29-BF6-C7_III-grsec/fs/open.c --- linux-2.4.29/fs/open.c 2004-02-18 06:36:31.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/open.c 2005-03-21 17:27:01.136268871 -0700 @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -95,7 +96,7 @@ write_unlock(&files->file_lock); } -int do_truncate(struct dentry *dentry, loff_t length) +int do_truncate(struct dentry *dentry, loff_t length, struct vfsmount *mnt) { struct inode *inode = dentry->d_inode; int error; @@ -105,6 +106,9 @@ if (length < 0) return -EINVAL; + if (!gr_acl_handle_truncate(dentry, mnt)) + return -EACCES; + down_write(&inode->i_alloc_sem); down(&inode->i_sem); newattrs.ia_size = length; @@ -165,7 +169,7 @@ error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); - error = do_truncate(nd.dentry, length); + error = do_truncate(nd.dentry, length, nd.mnt); } put_write_access(inode); @@ -217,7 +221,7 @@ error = locks_verify_truncate(inode, file, length); if (!error) - error = do_truncate(dentry, length); + error = do_truncate(dentry, length, file->f_vfsmnt); out_putf: fput(file); out: @@ -292,6 +296,12 @@ (error = permission(inode,MAY_WRITE)) != 0) goto dput_and_out; } + + if (!gr_acl_handle_utime(nd.dentry, nd.mnt)) { + error = -EACCES; + goto dput_and_out; + } + error = notify_change(nd.dentry, &newattrs); dput_and_out: path_release(&nd); @@ -344,6 +354,12 @@ (error = permission(inode,MAY_WRITE)) != 0) goto dput_and_out; } + + if (!gr_acl_handle_utime(nd.dentry, nd.mnt)) { + error = -EACCES; + goto dput_and_out; + } + error = notify_change(nd.dentry, &newattrs); dput_and_out: path_release(&nd); @@ -386,6 +402,10 @@ if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) && !special_file(nd.dentry->d_inode->i_mode)) res = -EROFS; + + if (!res && !gr_acl_handle_access(nd.dentry, nd.mnt, mode)) + res = -EACCES; + path_release(&nd); } @@ -409,6 +429,8 @@ if (error) goto dput_and_out; + gr_log_chdir(nd.dentry, nd.mnt); + set_fs_pwd(current->fs, nd.mnt, nd.dentry); dput_and_out: @@ -439,6 +461,13 @@ goto out_putf; error = permission(inode, MAY_EXEC); + + if (!error && !gr_chroot_fchdir(dentry, mnt)) + error = -EPERM; + + if (!error) + gr_log_chdir(dentry, mnt); + if (!error) set_fs_pwd(current->fs, mnt, dentry); out_putf: @@ -465,8 +494,16 @@ if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; + if (gr_handle_chroot_chroot(nd.dentry, nd.mnt)) + goto dput_and_out; + set_fs_root(current->fs, nd.mnt, nd.dentry); set_fs_altroot(); + + gr_handle_chroot_caps(current); + + gr_handle_chroot_chdir(nd.dentry, nd.mnt); + error = 0; dput_and_out: path_release(&nd); @@ -495,8 +532,20 @@ err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out_putf; + + if (!gr_acl_handle_fchmod(dentry, file->f_vfsmnt, mode)) { + err = -EACCES; + goto out_putf; + } + if (mode == (mode_t) -1) mode = inode->i_mode; + + if (gr_handle_chroot_chmod(dentry, file->f_vfsmnt, mode)) { + err = -EPERM; + goto out_putf; + } + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); @@ -527,8 +576,19 @@ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; + if (!gr_acl_handle_chmod(nd.dentry, nd.mnt, mode)) { + error = -EACCES; + goto dput_and_out; + } + if (mode == (mode_t) -1) mode = inode->i_mode; + + if (gr_handle_chroot_chmod(nd.dentry, nd.mnt, mode)) { + error = -EACCES; + goto dput_and_out; + } + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(nd.dentry, &newattrs); @@ -539,7 +599,7 @@ return error; } -static int chown_common(struct dentry * dentry, uid_t user, gid_t group) +static int chown_common(struct dentry * dentry, uid_t user, gid_t group, struct vfsmount *mnt) { struct inode * inode; int error; @@ -556,6 +616,12 @@ error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; + + if (!gr_acl_handle_chown(dentry, mnt)) { + error = -EACCES; + goto out; + } + if (user == (uid_t) -1) user = inode->i_uid; if (group == (gid_t) -1) @@ -606,7 +672,7 @@ error = user_path_walk(filename, &nd); if (!error) { - error = chown_common(nd.dentry, user, group); + error = chown_common(nd.dentry, user, group, nd.mnt); path_release(&nd); } return error; @@ -619,7 +685,7 @@ error = user_path_walk_link(filename, &nd); if (!error) { - error = chown_common(nd.dentry, user, group); + error = chown_common(nd.dentry, user, group, nd.mnt); path_release(&nd); } return error; @@ -633,7 +699,8 @@ file = fget(fd); if (file) { - error = chown_common(file->f_dentry, user, group); + error = chown_common(file->f_dentry, user, + group, file->f_vfsmnt); fput(file); } return error; @@ -753,6 +820,7 @@ * N.B. For clone tasks sharing a files structure, this test * will limit the total number of files that can be opened. */ + gr_learn_resource(current, RLIMIT_NOFILE, fd, 0); if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out; diff -ruN linux-2.4.29/fs/proc/array.c linux-2.4.29-BF6-C7_III-grsec/fs/proc/array.c --- linux-2.4.29/fs/proc/array.c 2005-01-19 07:10:11.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/proc/array.c 2005-03-21 17:27:01.137268722 -0700 @@ -276,6 +276,18 @@ cap_t(p->cap_effective)); } +#if defined(CONFIG_GRKERNSEC_PAX_NOEXEC) || defined(CONFIG_GRKERNSEC_PAX_ASLR) +static inline char *task_pax(struct task_struct *p, char *buffer) +{ + return buffer + sprintf(buffer, "PaX:\t%c%c%c%c%c%c\n", + p->flags & PF_PAX_PAGEEXEC ? 'P' : 'p', + p->flags & PF_PAX_EMUTRAMP ? 'E' : 'e', + p->flags & PF_PAX_MPROTECT ? 'M' : 'm', + p->flags & PF_PAX_RANDMMAP ? 'R' : 'r', + p->flags & PF_PAX_RANDEXEC ? 'X' : 'x', + p->flags & PF_PAX_SEGMEXEC ? 'S' : 's'); +} +#endif int proc_pid_status(struct task_struct *task, char * buffer) { @@ -298,9 +310,20 @@ #if defined(CONFIG_ARCH_S390) buffer = task_show_regs(task, buffer); #endif + +#if defined(CONFIG_GRKERNSEC_PAX_NOEXEC) || defined(CONFIG_GRKERNSEC_PAX_ASLR) + buffer = task_pax(task, buffer); +#endif + return buffer - orig; } +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP +#define PAX_RAND_FLAGS (task->flags & PF_PAX_RANDMMAP || \ + task->flags & PF_PAX_SEGMEXEC || \ + task->flags & PF_PAX_RANDEXEC) +#endif + int proc_pid_stat(struct task_struct *task, char * buffer) { unsigned long vsize, eip, esp, wchan; @@ -341,6 +364,19 @@ wchan = get_wchan(task); +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + if (PAX_RAND_FLAGS) { + eip = 0; + esp = 0; + wchan = 0; + } +#endif +#ifdef CONFIG_GRKERNSEC_HIDESYM + wchan = 0; + eip = 0; + esp = 0; +#endif + collect_sigign_sigcatch(task, &sigign, &sigcatch); /* scale priority and nice values from timeslices to -20..20 */ @@ -380,9 +416,15 @@ vsize, mm ? mm->rss : 0, /* you might want to shift this left 3 */ task->rlim[RLIMIT_RSS].rlim_cur, +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + PAX_RAND_FLAGS ? 0 : (mm ? mm->start_code : 0), + PAX_RAND_FLAGS ? 0 : (mm ? mm->end_code : 0), + PAX_RAND_FLAGS ? 0 : (mm ? mm->start_stack : 0), +#else mm ? mm->start_code : 0, mm ? mm->end_code : 0, mm ? mm->start_stack : 0, +#endif esp, eip, /* The signal information here is obsolete. @@ -520,6 +562,7 @@ static int show_map(struct seq_file *m, void *v) { + struct task_struct *task = m->private; struct vm_area_struct *map = v; struct file *file = map->vm_file; int flags = map->vm_flags; @@ -534,13 +577,22 @@ } seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + PAX_RAND_FLAGS ? 0UL : map->vm_start, + PAX_RAND_FLAGS ? 0UL : map->vm_end, +#else map->vm_start, map->vm_end, +#endif flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', flags & VM_EXEC ? 'x' : '-', flags & VM_MAYSHARE ? 's' : 'p', +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + PAX_RAND_FLAGS ? 0UL : map->vm_pgoff << PAGE_SHIFT, +#else map->vm_pgoff << PAGE_SHIFT, +#endif MAJOR(dev), MINOR(dev), ino, &len); if (map->vm_file) { @@ -608,6 +660,16 @@ .show = show_map }; +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR +int proc_pid_ipaddr(struct task_struct *task, char * buffer) +{ + int len; + + len = sprintf(buffer, "%u.%u.%u.%u\n", NIPQUAD(task->curr_ip)); + return len; +} +#endif + #ifdef CONFIG_SMP int proc_pid_cpu(struct task_struct *task, char * buffer) { diff -ruN linux-2.4.29/fs/proc/base.c linux-2.4.29-BF6-C7_III-grsec/fs/proc/base.c --- linux-2.4.29/fs/proc/base.c 2005-01-19 07:10:11.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/proc/base.c 2005-03-21 17:27:01.138268574 -0700 @@ -25,6 +25,7 @@ #include #include #include +#include /* * For hysterical raisins we keep the same inumbers as in the old procfs. @@ -40,6 +41,9 @@ int proc_pid_status(struct task_struct*,char*); int proc_pid_statm(struct task_struct*,char*); int proc_pid_cpu(struct task_struct*,char*); +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR +int proc_pid_ipaddr(struct task_struct*,char*); +#endif static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) { @@ -126,7 +130,8 @@ #define MAY_PTRACE(task) \ (task == current || \ (task->p_pptr == current && \ - (task->ptrace & PT_PTRACED) && task->state == TASK_STOPPED)) + (task->ptrace & PT_PTRACED) && task->state == TASK_STOPPED && \ + !gr_handle_proc_ptrace(task))) static int may_ptrace_attach(struct task_struct *task) { @@ -145,6 +150,8 @@ rmb(); if (!is_dumpable(task) && !capable(CAP_SYS_PTRACE)) goto out; + if (gr_handle_proc_ptrace(task)) + goto out; retval = 1; @@ -263,9 +270,22 @@ static int proc_permission(struct inode *inode, int mask) { + int ret; + struct task_struct *task; + if (vfs_permission(inode, mask) != 0) return -EACCES; - return proc_check_root(inode); + ret = proc_check_root(inode); + + if (ret) + return ret; + + task = inode->u.proc_i.task; + + if (!task) + return 0; + + return gr_acl_handle_procpidmem(task); } extern struct seq_operations proc_pid_maps_op; @@ -599,6 +619,9 @@ PROC_PID_STATM, PROC_PID_MAPS, PROC_PID_CPU, +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR + PROC_PID_IPADDR, +#endif PROC_PID_MOUNTS, PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */ }; @@ -614,6 +637,9 @@ #ifdef CONFIG_SMP E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO), #endif +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR + E(PROC_PID_IPADDR, "ipaddr", S_IFREG|S_IRUSR), +#endif E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO), E(PROC_PID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), E(PROC_PID_CWD, "cwd", S_IFLNK|S_IRWXUGO), @@ -770,10 +796,17 @@ get_task_struct(task); inode->u.proc_i.task = task; inode->i_uid = 0; +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#else inode->i_gid = 0; +#endif + if (ino == PROC_PID_INO || task_dumpable(task)) { inode->i_uid = task->euid; +#ifndef CONFIG_GRKERNSEC_PROC_USERGROUP inode->i_gid = task->egid; +#endif } out: @@ -982,6 +1015,12 @@ inode->u.proc_i.op.proc_read = proc_pid_cpu; break; #endif +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR + case PROC_PID_IPADDR: + inode->i_fop = &proc_info_file_operations; + inode->u.proc_i.op.proc_read = proc_pid_ipaddr; + break; +#endif case PROC_PID_MEM: inode->i_op = &proc_mem_inode_operations; inode->i_fop = &proc_mem_operations; @@ -1080,13 +1119,35 @@ if (!task) goto out; + if(gr_check_hidden_task(task)) { + free_task_struct(task); + goto out; + } + +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + if (current->uid && (task->uid != current->uid) +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + && !in_group_p(CONFIG_GRKERNSEC_PROC_GID) +#endif + ) { + 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; + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#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; @@ -1126,6 +1187,18 @@ int pid = p->pid; if (!pid) continue; + if(gr_pid_is_chrooted(p)) + continue; + if(gr_check_hidden_task(p)) + continue; +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + if (current->uid && (p->uid != current->uid) +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + && !in_group_p(CONFIG_GRKERNSEC_PROC_GID) +#endif + ) + continue; +#endif if (--index >= 0) continue; pids[nr_pids] = pid; diff -ruN linux-2.4.29/fs/proc/inode.c linux-2.4.29-BF6-C7_III-grsec/fs/proc/inode.c --- linux-2.4.29/fs/proc/inode.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/proc/inode.c 2005-03-21 17:27:01.139268425 -0700 @@ -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 -ruN linux-2.4.29/fs/proc/proc_misc.c linux-2.4.29-BF6-C7_III-grsec/fs/proc/proc_misc.c --- linux-2.4.29/fs/proc/proc_misc.c 2004-08-07 17:26:06.000000000 -0600 +++ linux-2.4.29-BF6-C7_III-grsec/fs/proc/proc_misc.c 2005-03-21 17:27:01.139268425 -0700 @@ -591,6 +591,7 @@ void __init proc_misc_init(void) { struct proc_dir_entry *entry; + int gr_mode = 0; static struct { char *name; int (*read_proc)(char*,char**,off_t,int,int*,void*); @@ -605,17 +606,21 @@ #ifdef CONFIG_STRAM_PROC {"stram", stram_read_proc}, #endif -#ifdef CONFIG_MODULES +#if defined(CONFIG_MODULES) && !defined(CONFIG_GRKERNSEC_PROC) {"modules", modules_read_proc}, #endif {"stat", kstat_read_proc}, +#ifndef CONFIG_GRKERNSEC_PROC_ADD {"devices", devices_read_proc}, -#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86) +#endif +#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86) && !defined(CONFIG_GRKERNSEC_PROC_ADD) {"interrupts", interrupts_read_proc}, #endif {"filesystems", filesystems_read_proc}, +#ifndef CONFIG_GRKERNSEC_PROC_ADD {"dma", dma_read_proc}, {"cmdline", cmdline_read_proc}, +#endif #ifdef CONFIG_SGI_DS1286 {"rtc", ds1286_read_proc}, #endif @@ -627,6 +632,23 @@ for (p = simple_ones; p->name; p++) create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL); +#ifdef CONFIG_GRKERNSEC_PROC_USER + gr_mode = S_IRUSR; +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + gr_mode = S_IRUSR | S_IRGRP; +#endif +#if defined(CONFIG_GRKERNSEC_PROC) && defined(CONFIG_MODULES) + create_proc_read_entry("modules", gr_mode, NULL, &modules_read_proc, NULL); +#endif +#ifdef CONFIG_GRKERNSEC_PROC_ADD + create_proc_read_entry("devices", gr_mode, NULL, &devices_read_proc, NULL); + create_proc_read_entry("dma", gr_mode, NULL, &dma_read_proc, NULL); + create_proc_read_entry("cmdline", gr_mode, NULL, &cmdline_read_proc, NULL); +#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86) + create_proc_read_entry("interrupts", gr_mode, NULL, &interrupts_read_proc, NULL); +#endif +#endif + proc_symlink("mounts", NULL, "self/mounts"); /* And now for trickier ones */ @@ -634,22 +656,32 @@ if (entry) entry->proc_fops = &proc_kmsg_operations; create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); -#if defined(CONFIG_X86) +#if defined(CONFIG_X86) && !defined(CONFIG_GRKERNSEC_PROC_ADD) create_seq_entry("interrupts", 0, &proc_interrupts_operations); +#elif defined(CONFIG_X86) + create_seq_entry("interrupts", gr_mode, &proc_interrupts_operations); #endif +#ifdef CONFIG_GRKERNSEC_PROC_ADD + create_seq_entry("ioports", gr_mode, &proc_ioports_operations); + create_seq_entry("iomem", gr_mode, &proc_iomem_operations); + create_seq_entry("slabinfo",gr_mode,&proc_slabinfo_operations); +#else create_seq_entry("ioports", 0, &proc_ioports_operations); create_seq_entry("iomem", 0, &proc_iomem_operations); - create_seq_entry("partitions", 0, &proc_partitions_operations); create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); +#endif + create_seq_entry("partitions", 0, &proc_partitions_operations); #ifdef CONFIG_MODULES - create_seq_entry("ksyms", 0, &proc_ksyms_operations); + create_seq_entry("ksyms", gr_mode, &proc_ksyms_operations); #endif +#ifndef CONFIG_GRKERNSEC_PROC_ADD proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL); if (proc_root_kcore) { proc_root_kcore->proc_fops = &proc_kcore_operations; proc_root_kcore->size = (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; } +#endif if (prof_shift) { entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL); if (entry) { diff -ruN linux-2.4.29/fs/proc/root.c linux-2.4.29-BF6-C7_III-grsec/fs/proc/root.c --- linux-2.4.29/fs/proc/root.c 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/proc/root.c 2005-03-21 17:27:01.140268276 -0700 @@ -37,7 +37,13 @@ return; } proc_misc_init(); - proc_net = proc_mkdir("net", 0); +#ifdef CONFIG_GRKERNSEC_PROC_USER + proc_net = proc_mkdir_mode("net", S_IRUSR | S_IXUSR, NULL); +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + proc_net = proc_mkdir_mode("net", S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP, NULL); +#else + proc_net = proc_mkdir("net", NULL); +#endif proc_net_stat = proc_mkdir("net/stat", NULL); #ifdef CONFIG_SYSVIPC @@ -69,7 +75,16 @@ #ifdef CONFIG_PPC_RTAS proc_rtas_init(); #endif - proc_bus = proc_mkdir("bus", 0); + +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + proc_bus = proc_mkdir_mode("bus", S_IRUSR | S_IXUSR, NULL); +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + proc_bus = proc_mkdir_mode("bus", S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP, NULL); +#endif +#else + proc_bus = proc_mkdir("bus", NULL); +#endif } static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry) diff -ruN linux-2.4.29/fs/readdir.c linux-2.4.29-BF6-C7_III-grsec/fs/readdir.c --- linux-2.4.29/fs/readdir.c 2004-11-17 04:54:21.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/readdir.c 2005-03-21 17:27:01.141268128 -0700 @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -181,6 +182,7 @@ struct readdir_callback { struct old_linux_dirent * dirent; + struct file * file; int count; }; @@ -192,6 +194,10 @@ if (buf->count) return -EINVAL; + + if (!gr_acl_handle_filldir(buf->file, name, namlen, ino)) + return 0; + buf->count++; dirent = buf->dirent; put_user(ino, &dirent->d_ino); @@ -214,6 +220,7 @@ goto out; buf.count = 0; + buf.file = file; buf.dirent = dirent; error = vfs_readdir(file, fillonedir, &buf); @@ -241,6 +248,7 @@ struct getdents_callback { struct linux_dirent * current_dir; struct linux_dirent * previous; + struct file * file; int count; int error; }; @@ -255,6 +263,10 @@ buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + + if (!gr_acl_handle_filldir(buf->file, name, namlen, ino)) + return 0; + dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); @@ -284,6 +296,7 @@ buf.current_dir = (struct linux_dirent *) dirent; buf.previous = NULL; + buf.file = file; buf.count = count; buf.error = 0; @@ -319,6 +332,7 @@ struct getdents_callback64 { struct linux_dirent64 * current_dir; struct linux_dirent64 * previous; + struct file * file; int count; int error; }; @@ -333,6 +347,10 @@ buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + + if (!gr_acl_handle_filldir(buf->file, name, namlen, ino)) + return 0; + dirent = buf->previous; if (dirent) { d.d_off = offset; @@ -367,6 +385,7 @@ buf.current_dir = (struct linux_dirent64 *) dirent; buf.previous = NULL; + buf.file = file; buf.count = count; buf.error = 0; diff -ruN linux-2.4.29/fs/xfs/linux-2.4/xfs_file.c linux-2.4.29-BF6-C7_III-grsec/fs/xfs/linux-2.4/xfs_file.c --- linux-2.4.29/fs/xfs/linux-2.4/xfs_file.c 2005-01-19 07:10:11.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/fs/xfs/linux-2.4/xfs_file.c 2005-03-21 17:27:01.141268128 -0700 @@ -330,6 +330,11 @@ return error; } +#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC + if (current->flags & PF_PAX_PAGEEXEC) + vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f]; +#endif + vma->vm_ops = &linvfs_file_vm_ops; VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error); diff -ruN linux-2.4.29/grsecurity/Config.in linux-2.4.29-BF6-C7_III-grsec/grsecurity/Config.in --- linux-2.4.29/grsecurity/Config.in 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.29-BF6-C7_III-grsec/grsecurity/Config.in 2005-03-21 17:27:01.142267979 -0700 @@ -0,0 +1,403 @@ +define_bool CONFIG_CRYPTO y +define_bool CONFIG_CRYPTO_SHA256 y +choice 'Security level' \ + "Low CONFIG_GRKERNSEC_LOW \ + Medium CONFIG_GRKERNSEC_MID \ + High CONFIG_GRKERNSEC_HI \ + Customized CONFIG_GRKERNSEC_CUSTOM" Customized +if [ "$CONFIG_GRKERNSEC_LOW" = "y" ]; then +define_bool CONFIG_GRKERNSEC_RANDSRC n +define_bool CONFIG_GRKERNSEC_FORKFAIL n +define_bool CONFIG_GRKERNSEC_TIME n +define_bool CONFIG_GRKERNSEC_SIGNAL n +define_bool CONFIG_GRKERNSEC_CHROOT_SHMAT n +define_bool CONFIG_GRKERNSEC_CHROOT_MOUNT n +define_bool CONFIG_GRKERNSEC_CHROOT_FCHDIR n +define_bool CONFIG_GRKERNSEC_CHROOT_DOUBLE n +define_bool CONFIG_GRKERNSEC_CHROOT_PIVOT n +define_bool CONFIG_GRKERNSEC_CHROOT_MKNOD n +define_bool CONFIG_GRKERNSEC_PROC n +define_bool CONFIG_GRKERNSEC_PROC_IPADDR n +define_bool CONFIG_GRKERNSEC_PROC_MEMMAP n +define_bool CONFIG_GRKERNSEC_HIDESYM n +define_bool CONFIG_GRKERNSEC_BRUTE n +define_bool CONFIG_GRKERNSEC_SHM n +define_bool CONFIG_GRKERNSEC_CHROOT_CAPS n +define_bool CONFIG_GRKERNSEC_CHROOT_SYSCTL n +define_bool CONFIG_GRKERNSEC_PROC_USERGROUP n +define_bool CONFIG_GRKERNSEC_KMEM n +define_bool CONFIG_GRKERNSEC_PROC_ADD n +define_bool CONFIG_GRKERNSEC_CHROOT_CHMOD n +define_bool CONFIG_GRKERNSEC_CHROOT_NICE n +define_bool CONFIG_GRKERNSEC_CHROOT_FINDTASK n +define_bool CONFIG_GRKERNSEC_PAX_RANDUSTACK n +define_bool CONFIG_GRKERNSEC_PAX_ASLR n +define_bool CONFIG_GRKERNSEC_PAX_RANDMMAP n +define_bool CONFIG_GRKERNSEC_PAX_NOEXEC n +define_bool CONFIG_GRKERNSEC_PAX_PAGEEXEC n +define_bool CONFIG_GRKERNSEC_PAX_NOELFRELOCS n +define_bool CONFIG_GRKERNSEC_PAX_ETEXECRELOCS n +define_bool CONFIG_GRKERNSEC_PAX_MPROTECT n +define_bool CONFIG_GRKERNSEC_PAX_SOFTMODE n +define_bool CONFIG_GRKERNSEC_PAX_EI_PAX n +define_bool CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS n +define_bool CONFIG_GRKERNSEC_PAX_NO_ACL_FLAGS n +define_bool CONFIG_GRKERNSEC_PAX_EMUTRAMP n +define_bool CONFIG_GRKERNSEC_PAX_EMUSIGRT n +if [ "$CONFIG_X86" = "y" ]; then +define_bool CONFIG_GRKERNSEC_PAX_RANDKSTACK n +define_bool CONFIG_GRKERNSEC_PAX_KERNEXEC n +define_bool CONFIG_GRKERNSEC_IO n +define_bool CONFIG_GRKERNSEC_PAX_SEGMEXEC n +fi +define_bool CONFIG_GRKERNSEC_AUDIT_MOUNT n +define_bool CONFIG_GRKERNSEC_ACL_HIDEKERN n +define_bool CONFIG_GRKERNSEC_RESLOG n +define_int CONFIG_GRKERNSEC_ACL_MAXTRIES 3 +define_int CONFIG_GRKERNSEC_ACL_TIMEOUT 30 + +define_int CONFIG_GRKERNSEC_FLOODTIME 10 +define_int CONFIG_GRKERNSEC_FLOODBURST 4 +define_bool CONFIG_GRKERNSEC_LINK y +define_bool CONFIG_GRKERNSEC_FIFO y +define_bool CONFIG_GRKERNSEC_RANDPID y +define_bool CONFIG_GRKERNSEC_EXECVE y +define_bool CONFIG_GRKERNSEC_RANDNET y +define_bool CONFIG_GRKERNSEC_DMESG y +define_bool CONFIG_GRKERNSEC_CHROOT_CHDIR y +fi +if [ "$CONFIG_GRKERNSEC_MID" = "y" ]; then +define_bool CONFIG_GRKERNSEC_KMEM n +define_bool CONFIG_GRKERNSEC_PROC_IPADDR n +define_bool CONFIG_GRKERNSEC_HIDESYM n +define_bool CONFIG_GRKERNSEC_PROC_ADD n +define_bool CONFIG_GRKERNSEC_CHROOT_CHMOD n +define_bool CONFIG_GRKERNSEC_CHROOT_NICE n +define_bool CONFIG_GRKERNSEC_CHROOT_FINDTASK n +define_bool CONFIG_GRKERNSEC_PAX_NOEXEC n +define_bool CONFIG_GRKERNSEC_PAX_PAGEEXEC n +define_bool CONFIG_GRKERNSEC_PAX_NOELFRELOCS n +define_bool CONFIG_GRKERNSEC_PAX_ETEXECRELOCS n +define_bool CONFIG_GRKERNSEC_PAX_MPROTECT n +define_bool CONFIG_GRKERNSEC_PAX_SOFTMODE n +define_bool CONFIG_GRKERNSEC_PAX_EI_PAX y +define_bool CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS y +define_bool CONFIG_GRKERNSEC_PAX_HAVE_ACL_FLAGS y +define_bool CONFIG_GRKERNSEC_PAX_EMUTRAMP n +define_bool CONFIG_GRKERNSEC_PAX_EMUSIGRT n +if [ "$CONFIG_X86" = "y" ]; then +define_bool CONFIG_GRKERNSEC_IO n +define_bool CONFIG_GRKERNSEC_PAX_SEGMEXEC n +fi +define_bool CONFIG_GRKERNSEC_AUDIT_MOUNT n +define_bool CONFIG_GRKERNSEC_CHROOT_CAPS n +define_bool CONFIG_GRKERNSEC_AUDIT_MOUNT n +define_bool CONFIG_GRKERNSEC_CHROOT_FCHDIR n +define_bool CONFIG_GRKERNSEC_ACL_HIDEKERN n +define_bool CONFIG_GRKERNSEC_RESLOG n +define_int CONFIG_GRKERNSEC_ACL_MAXTRIES 3 +define_int CONFIG_GRKERNSEC_ACL_TIMEOUT 30 + +define_int CONFIG_GRKERNSEC_FLOODTIME 10 +define_int CONFIG_GRKERNSEC_FLOODBURST 4 +define_bool CONFIG_GRKERNSEC_PROC_MEMMAP y +define_bool CONFIG_GRKERNSEC_CHROOT_SYSCTL y +define_bool CONFIG_GRKERNSEC_LINK y +define_bool CONFIG_GRKERNSEC_FIFO y +define_bool CONFIG_GRKERNSEC_RANDPID y +define_bool CONFIG_GRKERNSEC_EXECVE y +define_bool CONFIG_GRKERNSEC_DMESG y +define_bool CONFIG_GRKERNSEC_RANDNET y +define_bool CONFIG_GRKERNSEC_RANDSRC y +define_bool CONFIG_GRKERNSEC_FORKFAIL y +define_bool CONFIG_GRKERNSEC_TIME y +define_bool CONFIG_GRKERNSEC_SIGNAL y +define_bool CONFIG_GRKERNSEC_CHROOT y +define_bool CONFIG_GRKERNSEC_CHROOT_SHMAT n +define_bool CONFIG_GRKERNSEC_CHROOT_UNIX y +define_bool CONFIG_GRKERNSEC_CHROOT_MOUNT y +define_bool CONFIG_GRKERNSEC_CHROOT_PIVOT y +define_bool CONFIG_GRKERNSEC_CHROOT_DOUBLE y +define_bool CONFIG_GRKERNSEC_CHROOT_CHDIR y +define_bool CONFIG_GRKERNSEC_CHROOT_MKNOD y +define_bool CONFIG_GRKERNSEC_PROC y +define_bool CONFIG_GRKERNSEC_PROC_USERGROUP y +define_int CONFIG_GRKERNSEC_PROC_GID 10 +define_bool CONFIG_GRKERNSEC_PAX_RANDUSTACK y +define_bool CONFIG_GRKERNSEC_PAX_RANDKSTACK n +define_bool CONFIG_GRKERNSEC_PAX_KERNEXEC n +define_bool CONFIG_GRKERNSEC_PAX_ASLR y +define_bool CONFIG_GRKERNSEC_PAX_RANDMMAP y +define_bool CONFIG_GRKERNSEC_BRUTE n +define_bool CONFIG_GRKERNSEC_SHM n +fi +if [ "$CONFIG_GRKERNSEC_HI" = "y" ]; then +define_int CONFIG_GRKERNSEC_FLOODTIME 10 +define_int CONFIG_GRKERNSEC_FLOODBURST 4 +define_bool CONFIG_GRKERNSEC_LINK y +define_bool CONFIG_GRKERNSEC_FIFO y +define_bool CONFIG_GRKERNSEC_RANDPID y +define_bool CONFIG_GRKERNSEC_EXECVE y +define_bool CONFIG_GRKERNSEC_DMESG y +define_bool CONFIG_GRKERNSEC_RANDSRC y +define_bool CONFIG_GRKERNSEC_FORKFAIL y +define_bool CONFIG_GRKERNSEC_TIME y +define_bool CONFIG_GRKERNSEC_SHM y +define_bool CONFIG_GRKERNSEC_SIGNAL y +define_bool CONFIG_GRKERNSEC_CHROOT_SHMAT y +define_bool CONFIG_GRKERNSEC_CHROOT_UNIX y +define_bool CONFIG_GRKERNSEC_CHROOT_MOUNT y +define_bool CONFIG_GRKERNSEC_CHROOT_FCHDIR y +define_bool CONFIG_GRKERNSEC_CHROOT_PIVOT y +define_bool CONFIG_GRKERNSEC_CHROOT_DOUBLE y +define_bool CONFIG_GRKERNSEC_CHROOT_CHDIR y +define_bool CONFIG_GRKERNSEC_CHROOT_MKNOD y +define_bool CONFIG_GRKERNSEC_CHROOT_CAPS y +define_bool CONFIG_GRKERNSEC_CHROOT_SYSCTL y +define_bool CONFIG_GRKERNSEC_CHROOT_FINDTASK y +define_bool CONFIG_GRKERNSEC_PROC y +define_bool CONFIG_GRKERNSEC_PROC_IPADDR n +define_bool CONFIG_GRKERNSEC_PROC_MEMMAP y +define_bool CONFIG_GRKERNSEC_HIDESYM y +define_bool CONFIG_GRKERNSEC_BRUTE y +define_bool CONFIG_GRKERNSEC_PROC_USERGROUP y +define_int CONFIG_GRKERNSEC_PROC_GID 10 +define_bool CONFIG_GRKERNSEC_KMEM y +define_bool CONFIG_GRKERNSEC_RESLOG y +define_bool CONFIG_GRKERNSEC_RANDNET y + +define_bool CONFIG_GRKERNSEC_AUDIT_MOUNT n +define_bool CONFIG_GRKERNSEC_ACL_HIDEKERN n +define_int CONFIG_GRKERNSEC_ACL_MAXTRIES 3 +define_int CONFIG_GRKERNSEC_ACL_TIMEOUT 30 + +define_bool CONFIG_GRKERNSEC_PROC_ADD y +define_bool CONFIG_GRKERNSEC_CHROOT_CHMOD y +define_bool CONFIG_GRKERNSEC_CHROOT_NICE y +define_bool CONFIG_GRKERNSEC_PAX_RANDUSTACK y +define_bool CONFIG_GRKERNSEC_PAX_ASLR y +define_bool CONFIG_GRKERNSEC_PAX_RANDMMAP y +define_bool CONFIG_GRKERNSEC_PAX_NOEXEC y +define_bool CONFIG_GRKERNSEC_PAX_PAGEEXEC n +define_bool CONFIG_GRKERNSEC_PAX_NOELFRELOCS n +define_bool CONFIG_GRKERNSEC_PAX_MPROTECT y +define_bool CONFIG_GRKERNSEC_PAX_ETEXECRELOCS n +define_bool CONFIG_GRKERNSEC_PAX_SOFTMODE n +define_bool CONFIG_GRKERNSEC_PAX_EI_PAX y +define_bool CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS y +define_bool CONFIG_GRKERNSEC_PAX_HAVE_ACL_FLAGS y +if [ "$CONFIG_X86" = "y" ]; then +define_bool CONFIG_GRKERNSEC_IO n +if [ "$CONFIG_MODULES" != "y" -a "$CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM" != "y" -a "$CONFIG_PCI_BIOS" != "y" ]; then +define_bool CONFIG_GRKERNSEC_PAX_KERNEXEC y +fi +if [ "$CONFIG_X86_TSC" = "y" ]; then +define_bool CONFIG_GRKERNSEC_PAX_RANDKSTACK y +else +define_bool CONFIG_GRKERNSEC_PAX_RANDKSTACK n +fi +define_bool CON