diff -urN linux/Documentation/Configure.help linux/Documentation/Configure.help --- linux/Documentation/Configure.help Thu May 24 15:03:06 2001 +++ linux/Documentation/Configure.help Sun Jun 3 06:29:00 2001 @@ -1860,6 +1860,30 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +Eggdrop bot support +CONFIG_IP_NF_EGG + If you are running an eggdrop hub bot on this machine, then you + may want to enable this feature. This enables eggdrop bots to share + their user file to other eggdrop bots. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +CONFIG_IP_NF_FTP +IRC Send/Chat support +CONFIG_IP_NF_IRC + There is a commonly-used extension to IRC called + Direct Client-to-Client Protocol (DCC). This enables users to send + files to each other, and also chat to each other without the need + of a server. DCC Sending is used anywhere you send files over IRC, + and DCC Chat is most commonly used by Eggdrop bots. If you are + using NAT, this extension will enable you to send files and initiate + chats. Note that you do NOT need this extension to get files or + have others initiate chats, or everything else in IRC. + + If you want to compile it as a module, say 'M' here and read + Documentation/modules.txt. If unsure, say 'N'. + FTP protocol support CONFIG_IP_NF_FTP Tracking FTP connections is problematic: special helpers are @@ -1922,6 +1946,47 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +PSD match support +CONFIG_IP_NF_MATCH_PSD + This option adds a `psd' match, which allows you to create rules in + any iptables table wich will detect TCP and UDP port scans. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + +IPV4OPTIONS patch support +CONFIG_IP_NF_MATCH_IPV4OPTIONS + This option adds a IPV4OPTIONS match. + It allows you to filter options like source routing, + record route, and timestamp. + + If you say Y here, try iptables -m ipv4options --help for more information. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + +length match support +CONFIG_IP_NF_MATCH_LENGTH + This option allows you to match the length of a packet against a + specific value or range of values. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +TIME patch support +CONFIG_IP_NF_MATCH_TIME + This option adds a `time' match, which allows you to create rules in + any iptables table wich will match packet arrival timestamp + (arrival time at the machine which the netfilter is running on). + + If you say Y here, try iptables -m time --help for more information. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + TOS match support CONFIG_IP_NF_MATCH_TOS TOS matching allows you to match packets based on the Type Of @@ -1930,6 +1995,14 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +Connections/IP limit match support +CONFIG_IP_NF_MATCH_IPLIMIT + This match allows you to restrict the number of parallel TCP + connections to a server per client IP address (or address block). + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + Connection state match support CONFIG_IP_NF_MATCH_STATE Connection state matching allows you to match packets based on their @@ -1939,6 +2012,14 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +String match support (EXPERIMENTAL) +CONFIG_IP_NF_MATCH_STRING + String matching alows you to match packets which contain a + specified string of characters. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + Unclean match support (EXPERIMENTAL) CONFIG_IP_NF_MATCH_UNCLEAN Unclean packet matching matches any strange or invalid packets, by @@ -2083,6 +2164,15 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +Packet `drop' table +CONFIG_IP_NF_DROPTABLE + The `drop; table is traversed by `interesting' packets which + are going to be dropped. This is mainly useful for logging packet + drops. See the man page for iptables(8). + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + ipchains (2.2-style) support CONFIG_IP_NF_COMPAT_IPCHAINS This option places ipchains (with masquerading and redirection @@ -16972,6 +17062,268 @@ boards supported by this driver, and for further information on the use of this driver. +Openwall non-executable stack +CONFIG_GRKERNSEC_STACK + If you say Y here, your system will not allow execution of + code on the stack, making buffer overflow exploitation more difficult. + Exploits will have to dabble in more obscure methods of + exploitation(bss,got,heap..) + +Gcc trampoline support +CONFIG_GRKERNSEC_STACK_GCC + If you say Y here, the system will support trampoline code along + with the stack protection. If you do not have any programs on + your system that require this (glibc 2.0 users must say YES to + this option) you may say no here. + +PaX protection +CONFIG_GRKERNSEC_PAX + PaX (http://pax.low-level.net) enforces no execution on the stack + as well as all memory pages. This not only stops buffer overflows + that execute code on the stack, but also many other methods of + exploitation including bss and the heap. This greatly reduces the + window attackers have to compromise a system, and raises the difficulty + of ways to do so. It has a few drawbacks however, as compared to + the Openwall patch. It incurs a greater performance hit; reportedly + 5-8% for certain intensive operations, and a negligable amount for normal + operations. It has problems with XFree86 4.x though, making it + kill random things in X and slowing it down to a crawl. If you don't use + XFree86 4.x, it's highly recommended you say Y here instead of choosing + the Openwall patch. + +Proc Restrictions +CONFIG_GRKERNSEC_PROC + If you say Y here, the permissions of the /proc filesystem + will be altered to enhance system security and privacy. Depending + upon the options you choose, you can either restrict users to see + only the processes they themselves run, or choose a group that can + not see all processes, but can view other proc entries that would + normally be restricted to the user. If you're running identd as + a non-root user, you will have to run it as the group you specify here. + +Linking restrictions +CONFIG_GRKERNSEC_LINK + If you say Y here, /tmp race exploits will be prevented, since users + will no longer be able to follow symlinks owned by other users in + world-writeable +t directories (i.e. /tmp), unless the owner of the + symlink is the owner of the directory. users will also not be + able to hardlink to files they do not own. + +FIFO restrictions +CONFIG_GRKERNSEC_FIFO + If you say Y here, users will not be able to write to FIFOs they don't + own in world-writeable +t directories (i.e. /tmp), unless the owner of + the FIFO is the same owner of the directory it's held in. + +Secure file descriptors +CONFIG_GRKERNSEC_FD + If you say Y here, set*id binaries will be protected from data spoofing + attacks (eg. making a program read /etc/shadow). The patches do this + by opening up /dev/null to any of the stdin, stdout, stderr file descriptors + for set*id binaries that are open and run by a user that is not the owner + of the file. + +Exec process limiting +CONFIG_GRKERNSEC_EXECVE + If you say Y here, users with a resource limit on processes will + have the value checked during execve() calls. The current system + only checks the system limit during fork() calls. + +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. + WARNING: This option when enabled will produce a LOT of logs, especially + on an active system. + +Set*id logging +CONFIG_GRKERNSEC_SUID + If you say Y here, all set*id() calls will be logged. Such information + could be useful when detecting a possible intrusion attempt. + +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 + occured, which in some cases could mean a possible exploit attempt. + +BSD-style coredumps +CONFIG_GRKERNSEC_COREDUMP + If you say Y here, linux will use a style similar to BSD for + coredumps, core.processname. Not a security feature, just + a useful one. + +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. + +Time change logging +CONFIG_GRKERNSEC_TIME + If you say Y here, any changes of the system clock will be logged. + +Secure keymap loading +CONFIG_GRKERNSEC_KBMAP + If you say Y here, KDSKBENT and KDSKBSENT ioctl calls being + called by unprivileged users will be denied. If you answer N, + everyone will be able to modify keyboard bindings. + + Saying N makes hacking root account easier for anyone who + has access to the console. + +Enhanced network randomness +CONFIG_GRKERNSEC_RANDNET + If you say Y here, the functions controlling the randomness + of the Linux IP stack will be enhanced to decrease the chances + of being able to predict certain packets that require some + amount of randomness. + +Chroot jail restrictions +CONFIG_GRKERNSEC_CHROOT + If you say Y here, processes in a chrooted jail will be much more + difficult to break out of. It stops most generic ways of breaking + a chroot jail. Adding in chroot jail restrictions adds these + protective measures to the kernel: + No mknod() + No ptracing + No fchmod +s or chmod +s (usually used to create a rootshell) + No double chroots + Restricted signal sending to other processes + No mounting or remounting of devices + Enforced chdir("/") on all chroots + +Log all execs within a jail +CONFIG_GRKERNSEC_CHROOT_EXECLOG + If you say Y here, all executions inside a chroot jail will be logged to + syslog. + +Chroot jail capability restrictions +CONFIG_GRKERNSEC_CHROOT_CAPS + If you say Y here, the capabilities on all root processes within a + chroot jail will be lowered to stop module insertion, raw i/o, + system and net admin tasks, transferring capabilities, and + tty configuration tasks. This is left an option because it breaks + some apps (glftpd) Disable this if your chrooted apps are having + problems. + +Trusted path execution +CONFIG_GRKERNSEC_TPE + If you say Y here, you will be able to choose a gid to add to the + supplementary groups of users you want to mark as "untrusted." + These users will not be able to execute any files that are not in + root-owned directories writeable only by root. + +Partially restrict non-root users +CONFIG_GRKERNSEC_TPE_ALL + If you say Y here, All other non-root users will only be allowed to + execute files in directories they own that are not group or + world-writeable, or in directories owned by root and writeable only by + root. + +Trusted path execution glibc protection +CONFIG_GRKERNSEC_TPE_GLIBC + If you say Y here, all non-root users will not be able to execute + any files while glibc specific environment variables such as + LD_PRELOAD are set, which could be used to evade the trusted + path execution protection. It also protects against evasion + through /lib/ld-2.* It is recommended you say Y here also. + +Exec protection +CONFIG_GRKERNSEC_NOEXEC + If you say Y here, you will be able to choose a gid to be used to + run remote daemons that do not normally execute files as. You + can also setgid suid apps to provide protection as well. + Example: + chgrp noexec /bin/ping + chmod g+s /bin/ping + applications running as this group, even if running as root will + not be able to remove this group from their set or execute any + files. Files that you want the processes to be able to execute + should be chgrp'd to the gid you choose here. Processes running + as this group will be unable to change the group of files they + are not allowed to execute (all files without group of gid you + specify here) to this group to allow them to execute the file. + +Exec protection glibc protection +CONFIG_GRKERNSEC_NOEXEC_GLIBC + If you say Y here, all users will not be able to execute + any files while glibc specific environment variables such as + LD_PRELOAD are set, which could be used to evade the exec + protection. It also protects against evasion + through /lib/ld-2.* It is recommended you say Y here also. + +Exec protection capability restrictions +CONFIG_GRKERNSEC_NOEXEC_CAPS + If you say Y here, the capability set for processes running as + the noexec group will be lowered, disallowing them from inserting + modules, using raw i/o, changing their capability set, rebooting + the system, performing network or system admin tasks, or changing + the attributes of immutable or append-only files on the system. + +Suid/sgid root executable restrictions +CONFIG_GRKERNSEC_SIDCAPS + If you say Y here, the capability set of all suid/sgid root + executables on your system will be lowered to increase security. + This would disallow any suid/sgid root programs on your system + from doing things like inserting modules, using raw i/o, changing + their capability set, rebooting the system, or changing the attributes + of immutable or append-only files on the system. This option should + not cause a problem with nearly all suid/sgid root apps on your + system, however if you have any suid/sgid apps that require those + capabilities, consider perhaps removing the suid/sgid bit and running + it only as root, or disable this option. + +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. + +Randomized IP IDs +CONFIG_GRKERNSEC_RANDID + If you say Y here, all the id field on all outgoing packets + will be randomized. This hinders os fingerprinters and + keeps your machine from being used as a bounce for an untraceable + portscan. Ids are used for fragmented packets, fragments belonging + to the same packet have the same id. By default linux only + increments the id value on each packet sent to an individual host. + This option will make your system more OpenBSD-ish ;) + +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. + +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 do one of three things, based on the option(s) you choose. + Deny all socket access: keeps users from connecting to other hosts + from the machine or running servers from the machine + Deny all client sockets: keeps users from connecting to other machines + only + Deny all server sockets: keeps users from running servers on the machine + You should change the GID's from the default to what you have set up on + your system. + +Stealth network enhancements +CONFIG_GRKERNSEC_STEALTH + If you say Y here, you will enable several enhancements that will + improve your system's protection against portscans. + Enabling these options and filtering all open ports should make + your machine very hard to detect, while not interfering with (most) + normal operation. + # # ARM options # @@ -17773,6 +18125,278 @@ To use this option, you have to check that the "/proc file system support" (CONFIG_PROC_FS) is enabled, too. +Intrusion Detection System support (EXPERIMENTAL) +CONFIG_LIDS + If you say Y here, you will be able to protect important files + from being modified by an intruder. The security option defines two + states of the kernel. + 1. normal mode , boot with LILO parameter "security=0". + This will turn off the security option and it will be the same + as a normal linux kernel. + 2. security mode , boot default. + This will turn on the security option. The kernel will protect + the defined files, directories and their subdirectories. + No one (root included) can modify the files (delete, + chmod, chown, etc). And more features are included... + + Please read help provided with each option carefully. At the end of + each option we indicate what answer will increase security. + Be aware that security always has side effects, and some programs could + break. + + If you have any questions about LIDS, mail to the authors : + Huagang Xie ( xie@gnuchina.org) + Philippe.biondi (philippe.biondi@webmotion.net) + Steve Bremer (steve@clublinux.org) + + or visit lids home , + http://www.lids.org/ + or mirrors: + http://www.ca.lids.org/ + http://www.fi.lids.org/ + http://www.it.lids.org/ + http://www.cz.lids.org/ + http://www.hu.lids.org/ + http://www.chorche.cz/linux/ids.html (czech language) + ftp mirrors: + ftp://ftp.lids.org/ + ftp://ftp.hu.lids.org/pub/mirrors/lids/ + + And you can get help from the LIDS Mailing list at + http://www.lids.org/maillist.html + and the FAQ by Steve Bremer at + http://www.clublinux.org/lids/ + + If your want to secure your linux , say "Y" here , if not , say "N". + +Hang up console when raising a security alert +CONFIG_LIDS_HANGUP + If you say yes here, each time a program violates the rules, LIDS will + try to hang up the console the program is currently attached to. + + Warning: If the LIDS ACLs are not properly set up, and you select this + option you may lock yourself out of your linux box. + +Security alert when executing unprotected programs before sealing +CONFIG_LIDS_SA_EXEC_UP + Saying yes will generate a security alert for each unprotected program + that is executed before LIDS is sealed (with lidsadm -I). + This can help a lot to check whether your boot sequence is secured. + This can also warn you if a weakness has been exploited and an + unprotected program has been added to the boot process. + + Saying yes increases security. + +Do not execute unprotected programs before sealing +CONFIG_LIDS_NO_EXEC_UP + This option makes LIDS refuse the execution of the unprotected programs + before it is sealed. Be aware that you can prevent the system from + booting with an incomplete lids.conf. + + Saying yes increases security. + + Warning: Selecting this may cause your system to fail to boot, you must + create proper ACLs to protect all the programs running before + sealing. So, if you got problem with booting, disable this option, + recompile and boot again. + +Enable init children lock feature +CONFIG_LIDS_INIT_CHILDREN_LOCK + Saying yes here will compile the necessary code for the + init children lock feature. You can then activate the feature with + lidsadm (+LOCK_INIT_CHILDREN). It will prevent anybody from killing + processes whose parent is init and which are running when you issue + the command. + + This mean that no one can stop them (denial of service) or even + reload them with a new configuration file (restart or kill -HUP). + + Saying yes and using it increases security. + + +Logging behaviour +CONFIG_LIDS_NO_FLOOD_LOG + If you say Yes here, LIDS will try not to flood logs with the + same message repeated a lot of times. + + Saying yes will increase security. + +Number of similiar log events to allow within a given interval(Experimental) +CONFIG_LIDS_FLOOD_EVENT_THRESHOLD + This is the maximum number of similiar events that LIDS will + log within the interval defined in: + CONFIG_LIDS_FLOOD_EVENT_INTERVAL + + This is to compensate for the problem of multiple different + LIDS alerts for "exec() before LIDS sealing" as well as + for other cases. + +Threshold interval period for the maximum number of LIDS events(Experimental) +CONFIG_LIDS_FLOOD_EVENT_INTERVAL + This is the interval in which we count the number of similiar + events that may be flooding the LIDS logs. + +Port Scanner Detector in kernel(NEW) +CONFIG_LIDS_PORT_SCAN_DETECTOR + If you say Yes here, LIDS will also build a port scanner detector in + kernel. When somebody uses a port scanner to scan your host, LIDS will + report it to you by logging the necessary message. It can detect many + scanners, including nmap, satan, sscan with many methods including half + open scanning. + + When you disable raw socket (disable sniffer) by LIDS, it can replace + the user space portscan detector, for it does not use any socket at all. + + Saying yes will increase security. + +Time between two logs +CONFIG_LIDS_TIMEOUT_AFTER_FLOOD + This is the minimum time (in seconds) allowed between two different + security alerts. When a security alert occurs, no more alerts will be + logged before expiration of this timeout. (Except the first alert, with + a flood warning). + +Allow switching normal/security mode +CONFIG_LIDS_ALLOW_SWITCH + If you say Yes here, you will enable the possibility to switch + LIDS on and off. + + Note: You must set a password with 'lidsadm -P' + + Saying no increases security. + +Restrict mode switching to specified terminal types +CONFIG_LIDS_RESTRICT_MODE_SWITCH + If you enable this option, mode switching will be only allowed + from specified terminal types. + +Allow mode switching from Linux Console +CONFIG_LIDS_MODE_SWITCH_CONSOLE + Allow mode switching from a Linux Console. + +Allow mode switching from serial Console +CONFIG_LIDS_MODE_SWITCH_SERIAL + Allow mode switching from a serial Console. + +Allow mode switching from a PTY +CONFIG_LIDS_MODE_SWITCH_PTY + Allow mode switching from a PTY. + +Number of attempts to submit password +CONFIG_LIDS_MAX_TRY + Here you put the number of tries you will allow before disabling the + switch capability for a while. + + The lower it is, the more secure the system will be. + +Time to wait after a fail +CONFIG_LIDS_TTW_FAIL + Here you put the time (in seconds) the switch capability will be + disabled when the authorised number of fails is reached. + + The higher it is, the more secure the system will be. + +Allow remote users to switch LIDS on/off +CONFIG_LIDS_REMOTE_SWITCH + Say Yes here if you want to allow users which are not logged + on through the console to be able switch LIDS on and off. + + If you have access to the console, you might disable this + option, so that a remote user can not disable LIDS, even + with the password. + + Saying no is more secure. + +Allow any program to switch LIDS on/off +CONFIG_LIDS_ALLOW_ANY_PROG_SWITCH + If you say Yes here, you will allow programs others than + /sbin/lidsadm to feed /proc/sys/lids/locks. + + Notes : * It is strongly recommended to leave this option + unmarked ! Don't say yes ! + * I don't know what it could be usesful to :) + + Say no. + +Allow reloading config file when switched off +CONFIG_LIDS_RELOAD_CONF + Saying Yes here will compile the necessary code to reload the config + file. Each time you pass +RELOAD_CONF argument to lidsadm, LIDS reloads + /etc/lids.conf and re-reads dev/inode numbers of special programs + (/sbin/lidsadm and every program you allow to do something LIDS + forbids) + + If an error occurs during the reload phase, the kernel does not panic + as it does at startup, because it considers you see the error + immediately and correct it. + +Send security alerts through network +CONFIG_LIDS_SA_THROUGH_NET + Say yes here if you want to send LIDS security alerts to + a remote machine through the network, directly from the + kernel, without the help of any potentially corrupted + user space program (especially mailer programs) + You can send them via mail or via UDP datagrams to a + remote syslog, http POST, or anything else you can imagine. + + A pseudo scripting language a la expect is provided to + use some communication protocols (as the mail one). + + Below is a summary of the important parameters for the + connection. See their respective help section for more + help. + + You must provide + - the IP of the remote machine + - the TCP/UDP port for the connection + + If you choose to use the provided mailer script + - Name of the source machine + - Name of the sender + - Mail address of the receiver + - Subject of the mail + + If you choose to use your own script + (or the remote syslog one, provided) : + - Socket type (TCP/UDP) + - Path of the script + +Hide klids kernel thread +CONFIG_LIDS_HIDE_KLIDS + If you say yes here, the klids kernel thread won't appear in + /proc (thus neither in ps nor in top, nor in anything else) + and its network connection won't appear in netstat. + + Moreover, klids network errors (can't connect, etc.) will + be silently ignored instead of being logged in syslog. + +Number of connection tries before giving up +CONFIG_LIDS_NET_MAX_TRIES + How many times klids will try to send the security alert, if + it can't connect (you forgot a firewall ? :) ), or if there + is a protocol error (remote sendmail doesn't accept your mail ?). + After this number of tries, the message is deleted, even + if it was not send (we can imagine that, for some unknown + reason (protocol error, defectious IP stack on the road,..) + the message can't be send and block the remaining of the + queue). + + If you don't want to loose any messages, put a big number + of tries here, and give a reasonnable sleep period. + +Sleep time after a failed connection +CONFIG_LIDS_NET_TIMEOUT + When klids fails to send the security alert, how many seconds + will it sleep before retrying ? + +Message queue size +CONFIG_LIDS_MSGQUEUE_SIZE + The security alerts are stored in a message queue. Give + the number of messages that could be queued before loosing + new messages here. + +Use generic mailer pseudo-script + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -urN linux/Makefile linux/Makefile --- linux/Makefile Fri May 25 09:51:33 2001 +++ linux/Makefile Sun Jun 3 06:22:32 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 5 -EXTRAVERSION = +EXTRAVERSION = -LIDS-getrewted KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux/arch/alpha/config.in linux/arch/alpha/config.in --- linux/arch/alpha/config.in Fri May 25 09:55:36 2001 +++ linux/arch/alpha/config.in Sun Jun 3 06:22:33 2001 @@ -362,3 +362,5 @@ bool 'Legacy kernel start address' CONFIG_ALPHA_LEGACY_START_ADDRESS endmenu + +source kernel/Config.in diff -urN linux/arch/arm/config.in linux/arch/arm/config.in --- linux/arch/arm/config.in Tue Apr 17 17:19:24 2001 +++ linux/arch/arm/config.in Sun Jun 3 06:22:33 2001 @@ -499,3 +499,4 @@ dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE dep_bool ' kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X endmenu +source kernel/Config.in diff -urN linux/arch/i386/config.in linux/arch/i386/config.in --- linux/arch/i386/config.in Thu May 24 15:14:08 2001 +++ linux/arch/i386/config.in Sun Jun 3 06:22:33 2001 @@ -381,3 +381,15 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu + +mainmenu_option next_comment +comment 'Getrewted Kernel Security' +bool 'Getrewted Kernel Security' CONFIG_GRKERNSEC +if [ "$CONFIG_GRKERNSEC" = "y" ]; then + source grkernsec/Config.in +fi +endmenu + +# LIDS main menu read +source kernel/Config.in + diff -urN linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- linux/arch/i386/kernel/entry.S Wed Nov 8 17:09:50 2000 +++ linux/arch/i386/kernel/entry.S Sun Jun 3 06:22:33 2001 @@ -320,6 +320,48 @@ addl $8,%esp jmp ret_from_exception +#ifdef CONFIG_GRKERNSEC_PAX + ALIGN + error_code_page_fault: + pushl %ds + pushl %eax + xorl %eax,%eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + decl %eax# eax = -1 + pushl %ecx + pushl %ebx + cld + movl %es,%cx + xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) + movl %esp,%edx + xchgl %ecx, ES(%esp) # get the address and save es. + pushl %eax # push the error code + pushl %edx + movl $(__KERNEL_DS),%edx + movl %dx,%ds + movl %dx,%es + GET_CURRENT(%ebx) + call *%ecx + 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(coprocessor_error) pushl $0 pushl $ SYMBOL_NAME(do_coprocessor_error) @@ -408,8 +450,13 @@ jmp error_code ENTRY(page_fault) +#ifdef CONFIG_GRKERNSEC_PAX + pushl $ SYMBOL_NAME(pax_do_page_fault) + jmp error_code_page_fault +#else pushl $ SYMBOL_NAME(do_page_fault) jmp error_code +#endif ENTRY(machine_check) pushl $0 diff -urN linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- linux/arch/i386/kernel/head.S Fri Apr 20 16:23:30 2001 +++ linux/arch/i386/kernel/head.S Sun Jun 3 06:22:33 2001 @@ -429,7 +429,11 @@ .quad 0x0000000000000000 /* not used */ .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ +#ifdef CONFIG_GRKERNSEC_STACK + .quad 0x00cbfa000000f7ff /* 0x23 user 3GB-8MB code at 0 */ +#else .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */ +#endif .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ .quad 0x0000000000000000 /* not used */ .quad 0x0000000000000000 /* not used */ diff -urN linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- linux/arch/i386/kernel/ptrace.c Tue Mar 6 19:44:37 2001 +++ linux/arch/i386/kernel/ptrace.c Sun Jun 3 06:22:33 2001 @@ -20,7 +20,9 @@ #include #include #include - +#ifdef CONFIG_GRKERNSEC_CHROOT +extern struct task_struct *child_reaper; +#endif /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. @@ -181,6 +183,25 @@ /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) goto out_tsk; +#ifdef CONFIG_GRKERNSEC_CHROOT + if(!( (current->fs->root->d_inode->i_dev == + child_reaper->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child_reaper->fs->root->d_inode->i_ino) ) && + !( (current->fs->root->d_inode->i_dev == + child->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child->fs->root->d_inode->i_ino) ) ) { + security_alert("denied ptrace of process(%.16s:%d) within chroot() jail " + "(%.32s:%lu) by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), " + "UID (%d), EUID(%d)","ptrace from chroot()", + child->comm,child->pid,kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino, current->comm, current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + goto out_tsk; + } +#endif child->ptrace |= PT_PTRACED; write_lock_irq(&tasklist_lock); diff -urN linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- linux/arch/i386/kernel/signal.c Tue Feb 13 13:15:04 2001 +++ linux/arch/i386/kernel/signal.c Sun Jun 3 06:22:33 2001 @@ -7,6 +7,7 @@ * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes */ +#include #include #include #include @@ -169,7 +170,11 @@ struct sigcontext sc; struct _fpstate fpstate; unsigned long extramask[_NSIG_WORDS-1]; +#ifdef CONFIG_GRKERNSEC_PAX + char retcode[16]; +#else char retcode[8]; +#endif }; struct rt_sigframe @@ -420,11 +425,21 @@ if (ka->sa.sa_flags & SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { +#if defined(CONFIG_GRKERNSEC_STACK) + err |= __put_user(MAGIC_SIGRETURN, &frame->pretcode); +#elif defined(CONFIG_GRKERNSEC_PAX) + unsigned long retcode = ((unsigned long)&frame->retcode + 7ul) & ~7ul; + err |= __put_user(retcode, &frame->pretcode); + err |= __put_user(0xb858, (short *)(retcode+0)); + err |= __put_user(__NR_sigreturn, (int *)(retcode+2)); + err |= __put_user(0x80cd, (short *)(retcode+6)); +#else err |= __put_user(frame->retcode, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ err |= __put_user(0xb858, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2)); err |= __put_user(0x80cd, (short *)(frame->retcode+6)); +#endif } if (err) @@ -495,11 +510,21 @@ if (ka->sa.sa_flags & SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { +#if defined(CONFIG_GRKERNSEC_STACK) + err |= __put_user(MAGIC_RT_SIGRETURN, &frame->pretcode); +#elif defined(CONFIG_GRKERNSEC_PAX) + unsigned long retcode = ((unsigned long)&frame->retcode + 7ul) & ~7ul; + err |= __put_user(retcode, &frame->pretcode); + err |= __put_user(0xb8, (char *)(retcode+0)); + err |= __put_user(__NR_rt_sigreturn, (int *)(retcode+1)); + err |= __put_user(0x80cd, (short *)(retcode+5)); +#else err |= __put_user(frame->retcode, &frame->pretcode); /* This is movl $,%eax ; int $0x80 */ err |= __put_user(0xb8, (char *)(frame->retcode+0)); err |= __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1)); err |= __put_user(0x80cd, (short *)(frame->retcode+5)); +#endif } if (err) @@ -556,6 +581,18 @@ regs->eip -= 2; } } + +#ifdef CONFIG_GRKERNSEC_PAX + /* PaX: clean up as our trace attempt became obsolete */ + if (current->ptrace & PT_PAX_TRACE) { + if (!(current->ptrace & PT_PAX_OLDTF)) { + regs->eflags &= ~TF_MASK; + } + current->ptrace &= ~(PT_PAX_TRACE | PT_PAX_KEEPTF | PT_PAX_OLDTF); + current->thread.pax_faults.eip = 0; + current->thread.pax_faults.count = 0; + } +#endif /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) diff -urN linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- linux/arch/i386/kernel/traps.c Mon May 7 14:15:21 2001 +++ linux/arch/i386/kernel/traps.c Sun Jun 3 06:22:33 2001 @@ -315,15 +315,185 @@ 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()) - +#if defined(CONFIG_GRKERNSEC_STACK) && defined(CONFIG_GRKERNSEC_STACK_GCC) +static unsigned long *get_reg(struct pt_regs *regs, unsigned char regnum) +{ + switch (regnum) { + case 0: return ®s->eax; + case 1: return ®s->ecx; + case 2: return ®s->edx; + case 3: return ®s->ebx; + case 4: return ®s->esp; + case 5: return ®s->ebp; + case 6: return ®s->esi; + case 7: return ®s->edi; + } + return NULL; +} +static unsigned long get_modrm(struct pt_regs *regs, int *err) +{ + unsigned char modrm, sib; + signed char rel8; + unsigned long rel32; + int size, regnum, scale; + unsigned long index, base, addr, value; + + *err |= __get_user(modrm, (unsigned char *)(regs->eip + 1)); + size = 2; + regnum = modrm & 7; + addr = *get_reg(regs, regnum); + if (regnum == 4 && (modrm & 0xC0) != 0xC0) { + *err |= __get_user(sib, (unsigned char *)(regs->eip + 2)); + size = 3; + scale = sib >> 6; + index = *get_reg(regs, (sib >> 3) & 7); + base = *get_reg(regs, sib & 7); + addr = base + (index << scale); + } + + switch (modrm & 0xC0) { + case 0x00: + if (regnum == 5) { + *err |= __get_user(addr, + (unsigned long *)(regs->eip + 2)); + size = 6; + } + *err |= __get_user(value, (unsigned long *)addr); + break; + + case 0x40: + *err |= __get_user(rel8, (signed char *)(regs->eip + size)); + size++; + addr += rel8; + *err |= __get_user(value, (unsigned long *)addr); + break; + + case 0x80: + *err |= __get_user(rel32, (unsigned long *)(regs->eip + size)); + size += 4; + addr += rel32; + *err |= __get_user(value, (unsigned long *)addr); + break; + + case 0xC0: + default: + value = addr; + } + + if (*err) return 0; + regs->eip += size; + return value; +} +#endif asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { +#ifdef CONFIG_GRKERNSEC_STACK + unsigned long addr; +#ifdef CONFIG_GRKERNSEC_STACK_GCC + unsigned char insn; + int err, count; +#endif +#endif if (regs->eflags & VM_MASK) goto gp_in_vm86; if (!(regs->xcs & 3)) goto gp_in_kernel; - +#ifdef CONFIG_GRKERNSEC_STACK +/* Check if it was return from a signal handler */ + if ((regs->xcs & 0xFFFF) == __USER_CS) + if (*(unsigned char *)regs->eip == 0xC3) + if (!__get_user(addr, (unsigned long *)regs->esp)) { + if ((addr & 0xFFFFFFFE) == MAGIC_SIGRETURN) { +/* Call sys_sigreturn() or sys_rt_sigreturn() to restore the context */ + regs->esp += 8; + __asm__("movl %3,%%esi\n\t" + "subl %1,%%esp\n\t" + "movl %2,%%ecx\n\t" + "movl %%esp,%%edi\n\t" + "rep; movsl\n\t" + "testl $1,%4\n\t" + "jnz 1f\n\t" + "call sys_sigreturn\n\t" + "leal %3,%%edi\n\t" + "jmp 2f\n\t" + "1:\n\t" + "call sys_rt_sigreturn\n\t" + "leal %3,%%edi\n\t" + "2:\n\t" + "addl %1,%%edi\n\t" + "movl %%esp,%%esi\n\t" + "movl %2,%%ecx\n\t" + "movl (%%edi),%%edi\n\t" + "rep; movsl\n\t" + "movl %%esi,%%esp" + : +/* %eax is returned separately */ + "=a" (regs->eax) + : + "i" (sizeof(*regs)), + "i" (sizeof(*regs) >> 2), + "m" (regs), + "r" (addr) + : + "cx", "dx", "si", "di", "cc", "memory"); + return; + } +/* + * * Check if we're returning to the stack area, which is only likely to happen + * * when attempting to exploit a buffer overflow. + * */ + if ((addr & 0xFF800000) == 0xBF800000 || + (addr >= PAGE_OFFSET - _STK_LIM && addr < PAGE_OFFSET)) + security_alert("return onto stack by (%.16s:%d), UID(%d), EUID (%d), parent (%.16s:%d), UID(%d), EUID (%d)", + "returns onto stack", + current->comm,current->pid,current->uid, + current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + } + +#ifdef CONFIG_GRKERNSEC_STACK_GCC +/* Check if it could have been a trampoline call */ + if ((regs->xcs & 0xFFFF) == __USER_CS) + if (*(unsigned char *)regs->eip == 0xFF) + if (!__get_user(insn, (unsigned char *)(regs->eip + 1))) + if ((insn & 0x38) == 0x10 && insn != 0xD4) { /* call mod r/m */ +/* First, emulate the call */ + err = 0; + addr = get_modrm(regs, &err); + if (!err) { + regs->esp -= 4; + err = __put_user(regs->eip, (unsigned long *)regs->esp); + regs->eip = addr; + } +/* Then, start emulating the trampoline itself */ + count = 0; + while (!err && !__get_user(insn, (unsigned char *)regs->eip++)) + if ((insn & 0xF8) == 0xB8) { /* movl imm32,%reg */ +/* We only have 8 GP registers, no reason to initialize one twice */ + if (count++ >= 8) break; + err |= __get_user(addr, (unsigned long *)regs->eip); + regs->eip += 4; + *get_reg(regs, insn & 7) = addr; + } else + if (insn == 0xFF) { + err |= __get_user(insn, (unsigned char *)regs->eip); + if ((insn & 0xF8) == 0xE0) { /* jmp *%reg */ + regs->eip = *get_reg(regs, insn & 7); + if (err) break; else return; + } + break; + } else + if (insn == 0xE9) { /* jmp rel32 */ + err |= __get_user(addr, (unsigned long *)regs->eip); + if (err) break; + regs->eip += 4 + addr; + return; + } else + break; + } +#endif +#endif current->thread.error_code = error_code; current->thread.trap_no = 13; force_sig(SIGSEGV, current); @@ -491,6 +661,10 @@ inb(0x71); /* dummy */ } +#ifdef CONFIG_GRKERNSEC_PAX +void pax_handle_ptes(struct task_struct *tsk); +#endif + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -521,6 +695,22 @@ __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); +#ifdef CONFIG_GRKERNSEC_PAX + /* PaX: clean up */ + if ((condition & DR_STEP) && (tsk->ptrace & PT_PAX_TRACE)) { + tsk->ptrace &= ~PT_PAX_TRACE; + pax_handle_ptes(tsk); + if (!(tsk->ptrace & PT_PAX_KEEPTF) && !(tsk->ptrace & PT_PAX_OLDTF)) + regs->eflags &= ~TF_MASK; + tsk->ptrace &= ~PT_PAX_KEEPTF; + if (!(tsk->ptrace & PT_PAX_OLDTF)) { + condition &= ~DR_STEP; + if (!(condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))) + return; + } + tsk->ptrace &= ~PT_PAX_OLDTF; + } +#endif /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) diff -urN linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- linux/arch/i386/mm/fault.c Tue May 15 00:16:51 2001 +++ linux/arch/i386/mm/fault.c Sun Jun 3 06:22:33 2001 @@ -4,6 +4,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include @@ -17,6 +18,9 @@ #include #include #include +#ifdef CONFIG_GRKERNSEC_PAX +#include +#endif #include #include @@ -177,21 +181,37 @@ good_area: info.si_code = SEGV_ACCERR; write = 0; +#ifdef CONFIG_GRKERNSEC_PAX + switch (error_code & 7) { +#else switch (error_code & 3) { +#endif default: /* 3: write, present */ #ifdef TEST_VERIFY_AREA if (regs->cs == KERNEL_CS) printk("WP fault at %08lx\n", regs->eip); #endif /* fall through */ +#ifdef CONFIG_GRKERNSEC_PAX + case 7: /* PaX: write, present, some protection violation */ +#endif case 2: /* write, not present */ +#ifdef CONFIG_GRKERNSEC_PAX + case 6: +#endif if (!(vma->vm_flags & VM_WRITE)) goto bad_area; write++; break; case 1: /* read, present */ goto bad_area; +#ifdef CONFIG_GRKERNSEC_PAX + case 5: /* PaX: read, present, protection violation */ +#endif case 0: /* read, not present */ +#ifdef CONFIG_GRKERNSEC_PAX + case 4: +#endif if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } @@ -358,3 +378,414 @@ return; } } +#ifdef CONFIG_GRKERNSEC_PAX +/* PaX: called with the page_table_lock spinlock held */ +static inline pte_t * pax_get_pte(struct mm_struct *mm, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + + pgd = pgd_offset(mm, address); + if (!pgd || !pgd_present(*pgd)) + return 0; + pmd = pmd_offset(pgd, address); + if (!pmd || pmd_none(*pmd) || pmd_bad(*pmd) || !pmd_present(*pmd)) + return 0; + return pte_offset(pmd, address); +} + +/* + * PaX: decide what to do with offenders + * + * returns 0 when access should be allowed + * 1 when task should be killed + * 2 when sigreturn trampoline was detected + * 3 when rt_sigreturn trampoline was detected + * 4 when gcc trampoline was detected + */ +static inline int pax_handle_read_fault(struct pt_regs *regs, unsigned long address) +{ + unsigned char trans[8] = {6, 1, 2, 0, 13, 5, 3, 4}; + int err; + + if ((VM_MASK & regs->eflags) || regs->xcs != __USER_CS || regs->eip != address) + return 0; + + { /* PaX: sigreturn emulation */ + unsigned char pop, mov; + unsigned short sys; + unsigned long nr; + + err = __get_user(pop, (unsigned char *)(regs->eip)); + err |= __get_user(mov, (unsigned char *)(regs->eip + 1)); + err |= __get_user(nr, (unsigned long *)(regs->eip + 2)); + err |= __get_user(sys, (unsigned short *)(regs->eip + 6)); + + if (!err) { + if (pop == 0x58 && + mov == 0xb8 && + nr == __NR_sigreturn && + sys == 0x80cd) + { + regs->esp += 4; + regs->eax = nr; + regs->eip += 8; + return 2; + } + } + } + + { /* PaX: rt_sigreturn emulation */ + unsigned char mov; + unsigned short sys; + unsigned long nr; + + err = __get_user(mov, (unsigned char *)(regs->eip)); + err |= __get_user(nr, (unsigned long *)(regs->eip + 1)); + err |= __get_user(sys, (unsigned short *)(regs->eip + 5)); + + if (!err) { + if (mov == 0xb8 && + nr == __NR_rt_sigreturn && + sys == 0x80cd) + { + regs->eax = nr; + regs->eip += 7; + return 3; + } + } + } + + { /* PaX: gcc trampoline emulation #1 */ + unsigned char mov1, mov2; + unsigned short jmp; + unsigned long addr1, addr2, ret; + + err = __get_user(mov1, (unsigned char *)(regs->eip)); + err |= __get_user(addr1, (unsigned long *)(regs->eip + 1)); + err |= __get_user(mov2, (unsigned char *)(regs->eip + 5)); + err |= __get_user(addr2, (unsigned long *)(regs->eip + 6)); + err |= __get_user(jmp, (unsigned short *)(regs->eip + 10)); + err |= __get_user(ret, (unsigned long *)(regs->esp)); + + if (!err) { + unsigned short call; + + err = __get_user(call, (unsigned short *)(ret-2)); + if (!err) { + if ((mov1 & 0xF8) == 0xB8 && + (mov2 & 0xF8) == 0xB8 && + (mov1 & 0x07) != (mov2 & 0x07) && + (jmp & 0xF8FF) == 0xE0FF && + (mov2 & 0x07) == ((jmp>>8) & 0x07) && + (call & 0xF8FF) == 0xD0FF && + (regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]])) + { + ((unsigned long *)regs)[trans[mov1 & 0x07]] = addr1; + ((unsigned long *)regs)[trans[mov2 & 0x07]] = addr2; + regs->eip = addr2; + return 4; + } + } + } + } + + { /* PaX: gcc trampoline emulation #2 */ + unsigned char mov, jmp; + unsigned long addr1, addr2, ret; + + err = __get_user(mov, (unsigned char *)(regs->eip)); + err |= __get_user(addr1, (unsigned long *)(regs->eip + 1)); + err |= __get_user(jmp, (unsigned char *)(regs->eip + 5)); + err |= __get_user(addr2, (unsigned long *)(regs->eip + 6)); + err |= __get_user(ret, (unsigned long *)(regs->esp)); + + if (!err) { + unsigned short call; + + err = __get_user(call, (unsigned short *)(ret-2)); + if (!err) { + if ((mov & 0xF8) == 0xB8 && + jmp == 0xE9 && + (call & 0xF8FF) == 0xD0FF && + (regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]])) + { + ((unsigned long *)regs)[trans[mov & 0x07]] = addr1; + regs->eip += addr2 + 10; + return 4; + } + } + } + } + + return 1; /* PaX in action */ +} + +static int pax_handle_opcode(struct task_struct *tsk, struct pt_regs *regs) +{ + unsigned long eip = regs->eip; + unsigned long esp = regs->esp; + unsigned long opsize = 1; + unsigned long opsize_override = 0; + unsigned long i; + + if (regs->eflags & TF_MASK) + tsk->ptrace |= PT_PAX_OLDTF; + else + tsk->ptrace &= ~PT_PAX_OLDTF; + tsk->ptrace &= ~PT_PAX_KEEPTF; + + if (regs->eflags & VM_MASK) { + eip = (((regs->xcs)&0xFFFF)<<4) + ((regs->eip)&0xFFFF); + esp = (((regs->xss)&0xFFFF)<<4) + ((regs->esp)&0xFFFF); + opsize= 0; + } + + for (i=0; i<15; i++) { + unsigned char opcode; + if (__get_user(opcode, (unsigned char*)(eip+i))) + break; + switch (opcode) { + case 0x26: + case 0x2E: + case 0x36: + case 0x3E: + case 0x64: + case 0x65: + case 0x67: + case 0xF0: + case 0xF2: + case 0xF3: + break; + + case 0x66: + opsize_override = 1; + break; + + case 0x9C: /* PUSHF */ + if (opsize ^ opsize_override) { + __put_user(regs->eflags & 0x00FCFFFFul, (unsigned long*)(esp-4)); + regs->esp -= 4; + } else { + __put_user(regs->eflags, (unsigned short*)(esp-2)); + regs->esp -= 2; + } + regs->eip += i + 1; + return 1; + + case 0x9D: /* POPF */ + case 0xCF: /* IRET */ + tsk->ptrace |= PT_PAX_KEEPTF; + return 0; + + default: + return 0; + } + } + return 0; +} + +static inline void pax_handle_pte(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + pte = pax_get_pte(mm, address); + if (pte) { + set_pte(pte, pte_exprotect(*pte)); + __flush_tlb_one(address); + } +} + +#define PAX_SPIN_COUNT 16 + +void pax_handle_ptes(struct task_struct *tsk) +{ + struct mm_struct *mm; + + mm = tsk->mm; + spin_lock(&mm->page_table_lock); + switch (tsk->thread.pax_faults.count) { + default: + printk(KERN_ERR "PAX: wtf: %s:%d, %ld\n", tsk->comm, tsk->pid, + tsk->thread.pax_faults.count); + break; + + case PAX_SPIN_COUNT+4: + pax_handle_pte(mm, tsk->thread.pax_faults.addresses[3]); + + case PAX_SPIN_COUNT+3: + pax_handle_pte(mm, tsk->thread.pax_faults.addresses[2]); + + case PAX_SPIN_COUNT+2: + pax_handle_pte(mm, tsk->thread.pax_faults.addresses[1]); + + case PAX_SPIN_COUNT+1: + pax_handle_pte(mm, tsk->thread.pax_faults.addresses[0]); + } + spin_unlock(&mm->page_table_lock); + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; +} + +/* + * PaX: handle the extra page faults or pass it down to the original handler + * + * returns 0 when nothing special was detected + * 1 when sigreturn trampoline (syscall) has to be emulated + */ +asmlinkage int pax_do_page_fault(struct pt_regs *regs, unsigned long error_code) +{ + struct task_struct *tsk = current; + struct mm_struct *mm = current->mm; + unsigned long address; + unsigned long pax_eip; + pte_t *pte; + unsigned char pte_mask; + int ret; + + __asm__("movl %%cr2,%0":"=r" (address)); + + if (address >= TASK_SIZE || in_interrupt() || !mm || (error_code & 5) != 5) + goto chain; + + /* It's safe to allow irq's after cr2 has been saved */ + if (regs->eflags & X86_EFLAGS_IF) + local_irq_enable(); + + current->state = TASK_RUNNING; + + /* PaX: it's our fault, let's handle it if we can */ + + /* PaX: take a look at read faults before acquiring any locks */ + if (error_code == 5) { /* read/instruction fetch attempt from a protected page in user mode */ + ret = pax_handle_read_fault(regs, address); + switch (ret) { + case 4: + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + return 0; + + case 3: + case 2: + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + return 1; + + default: + case 1: + printk(KERN_ERR "PAX: terminating task: %s:%d, EIP: %08lX, ESP: %08lX\n", tsk->comm, tsk->pid, regs->eip, regs->esp); + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + tsk->ptrace &= ~(PT_PAX_TRACE | PT_PAX_KEEPTF | PT_PAX_OLDTF); + regs->eflags &= ~TF_MASK; + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + force_sig(SIGKILL,tsk); + return 0; + + case 0: + } + } + + down_read(&mm->mmap_sem); + spin_lock(&mm->page_table_lock); + pte = pax_get_pte(mm, address); + if (!pte || pte_none(*pte) || !(pte_val(*pte) & _PAGE_PRESENT) || pte_exec(*pte)) { + spin_unlock(&mm->page_table_lock); + up_read(&mm->mmap_sem); + goto chain; + } + + if (error_code == 5) { /* read/instruction fetch attempt from a protected page in user mode */ + pte_mask = _PAGE_ACCESSED | _PAGE_USER; + } else if (!pte_write(*pte)) { /* write attempt to a protected page in user mode */ + spin_unlock(&mm->page_table_lock); + up_read(&mm->mmap_sem); + goto chain; + } else { + pte_mask = _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_USER; + } + + if (regs->eflags & VM_MASK) { + pax_eip = (((regs->xcs)&0xFFFF)<<4) + ((regs->eip)&0xFFFF); + } else { + pax_eip = regs->eip; + } + + /* + * PaX: fill DTLB with user rights and retry + */ + if (pax_eip != tsk->thread.pax_faults.eip) { /* detect DTLB trashing */ + tsk->thread.pax_faults.eip = pax_eip; + tsk->thread.pax_faults.count = 0; + + pax_emu: + __asm__ __volatile__ ( + "orb %2,%1\n" + "invlpg %0\n" + "testb $0,%0\n" + "xorb %3,%1\n" + "testb $0,%0\n" + : + : "m" (*(char*)address), "m" (*(char*)pte) , "r" (pte_mask) , "i" (_PAGE_USER) + : "memory", "cc"); + spin_unlock(&mm->page_table_lock); + up_read(&mm->mmap_sem); + return 0; + } + + if (tsk->thread.pax_faults.count < PAX_SPIN_COUNT) { + ++tsk->thread.pax_faults.count; + goto pax_emu; + } + spin_unlock(&mm->page_table_lock); + + if (tsk->thread.pax_faults.count == PAX_SPIN_COUNT) { + if (pax_handle_opcode(tsk, regs)) { + up_read(&mm->mmap_sem); + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + tsk->ptrace &= ~(PT_PAX_TRACE | PT_PAX_KEEPTF | PT_PAX_OLDTF); + return 0; + } else { + ++tsk->thread.pax_faults.count; + } + } + + if (tsk->thread.pax_faults.count > PAX_SPIN_COUNT+1+3) { + up_read(&mm->mmap_sem); + printk(KERN_ERR "PAX: preventing DoS: %s:%d, EIP: %08lX, ESP: %08lX\n", tsk->comm, tsk->pid, regs->eip, regs->esp); + tsk->thread.pax_faults.eip = 0; + tsk->thread.pax_faults.count = 0; + tsk->ptrace &= ~(PT_PAX_TRACE | PT_PAX_KEEPTF | PT_PAX_OLDTF); + regs->eflags &= ~TF_MASK; + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + force_sig(SIGKILL,tsk); + return 0; + } + + spin_lock(&mm->page_table_lock); + pte = pax_get_pte(mm, address); + if (pte) { + set_pte(pte, pte_mkexec(*pte)); + __flush_tlb_one(address); + tsk->thread.pax_faults.addresses[tsk->thread.pax_faults.count-PAX_SPIN_COUNT-1] = address; + ++tsk->thread.pax_faults.count; + } + spin_unlock(&mm->page_table_lock); + up_read(&mm->mmap_sem); + tsk->ptrace |= PT_PAX_TRACE; + regs->eflags |= TF_MASK; + /* + if (tsk->thread.pax_faults.count > PAX_SPIN_COUNT+1+2) + printk(KERN_ERR "PAX: DTLB trashing level %ld: %s:%d, EIP: %08lX, ESP: %08lX, cr2: %08lX\n", tsk->thread.pax_faults.count - (PAX_SPIN_COUNT+1), tsk->comm, tsk->pid, regs->eip, regs->esp, address); + */ + return 0; + + chain: + do_page_fault(regs, error_code); + return 0; +} +#endif diff -urN linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- linux/arch/i386/mm/init.c Fri Apr 20 16:15:20 2001 +++ linux/arch/i386/mm/init.c Sun Jun 3 06:22:33 2001 @@ -397,7 +397,11 @@ pmd = pmd_offset(pgd, vaddr); pte = pte_offset(pmd, vaddr); old_pte = *pte; +#ifdef CONFIG_GRKERNSEC_PAX + *pte = mk_pte_phys(0, PAGE_READONLY_EXEC); +#else *pte = mk_pte_phys(0, PAGE_READONLY); +#endif local_flush_tlb(); boot_cpu_data.wp_works_ok = do_test_wp_bit(vaddr); diff -urN linux/arch/ia64/config.in linux/arch/ia64/config.in --- linux/arch/ia64/config.in Tue Apr 17 17:19:24 2001 +++ linux/arch/ia64/config.in Sun Jun 3 06:22:33 2001 @@ -281,3 +281,4 @@ bool 'Disable VHPT' CONFIG_DISABLE_VHPT endmenu +source kernel/Config.in diff -urN linux/arch/m68k/config.in linux/arch/m68k/config.in --- linux/arch/m68k/config.in Mon May 21 18:12:09 2001 +++ linux/arch/m68k/config.in Sun Jun 3 06:22:33 2001 @@ -543,3 +543,5 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu + +source kernel/Config.in diff -urN linux/arch/mips/config.in linux/arch/mips/config.in --- linux/arch/mips/config.in Tue Apr 17 17:19:25 2001 +++ linux/arch/mips/config.in Sun Jun 3 06:22:33 2001 @@ -404,3 +404,5 @@ fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu + +source kernel/Config.in diff -urN linux/arch/mips64/config.in linux/arch/mips64/config.in --- linux/arch/mips64/config.in Tue Apr 17 17:19:25 2001 +++ linux/arch/mips64/config.in Sun Jun 3 06:22:33 2001 @@ -269,3 +269,4 @@ bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source kernel/Config.in diff -urN linux/arch/parisc/config.in linux/arch/parisc/config.in --- linux/arch/parisc/config.in Tue Apr 17 17:19:25 2001 +++ linux/arch/parisc/config.in Sun Jun 3 06:22:33 2001 @@ -207,4 +207,5 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source kernel/Config.in diff -urN linux/arch/ppc/config.in linux/arch/ppc/config.in --- linux/arch/ppc/config.in Tue May 22 10:23:16 2001 +++ linux/arch/ppc/config.in Sun Jun 3 06:22:33 2001 @@ -372,3 +372,4 @@ bool 'Include kgdb kernel debugger' CONFIG_KGDB bool 'Include xmon kernel debugger' CONFIG_XMON endmenu +source kernel/Config.in diff -urN linux/arch/s390/config.in linux/arch/s390/config.in --- linux/arch/s390/config.in Tue Apr 17 17:19:25 2001 +++ linux/arch/s390/config.in Sun Jun 3 06:22:33 2001 @@ -70,3 +70,4 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source kernel/Config.in diff -urN linux/arch/sh/config.in linux/arch/sh/config.in --- linux/arch/sh/config.in Tue Apr 17 17:19:25 2001 +++ linux/arch/sh/config.in Sun Jun 3 06:22:33 2001 @@ -268,3 +268,4 @@ bool 'Early printk support' CONFIG_SH_EARLY_PRINTK fi endmenu +source kernel/Config.in diff -urN linux/arch/sparc/config.in linux/arch/sparc/config.in --- linux/arch/sparc/config.in Mon May 21 18:12:09 2001 +++ linux/arch/sparc/config.in Sun Jun 3 06:22:33 2001 @@ -262,3 +262,4 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source kernel/Config.in diff -urN linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- linux/arch/sparc64/config.in Sun May 20 11:32:07 2001 +++ linux/arch/sparc64/config.in Sun Jun 3 06:22:33 2001 @@ -359,3 +359,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ #bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP endmenu + +source kernel/Config.in diff -urN linux/drivers/char/mem.c linux/drivers/char/mem.c --- linux/drivers/char/mem.c Sat May 19 18:11:36 2001 +++ linux/drivers/char/mem.c Sun Jun 3 06:22:33 2001 @@ -205,9 +205,20 @@ /* * Don't dump addresses that are not real memory to a core file. */ +#ifdef CONFIG_GRKERNSEC_PAX + if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) { +#else if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) +#endif vma->vm_flags |= VM_IO; - +#ifdef CONFIG_GRKERNSEC_PAX + /* it turned out to be device memory (eg. video RAM), don't apply PaX */ + if (!(vma->vm_flags & VM_EXEC)) { + vma->vm_flags |= VM_EXEC | VM_MAYEXEC; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f]; + } + } +#endif if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start, vma->vm_page_prot)) return -EAGAIN; @@ -368,8 +379,11 @@ count = size; zap_page_range(mm, addr, count); +#ifdef CONFIG_GRKERNSEC_PAX + zeromap_page_range(addr, count, (vma->vm_flags & VM_EXEC) ? PAGE_COPY_EXEC : PAGE_COPY_NOEXEC); +#else zeromap_page_range(addr, count, PAGE_COPY); - +#endif size -= count; buf += count; addr += count; diff -urN linux/drivers/char/random.c linux/drivers/char/random.c --- linux/drivers/char/random.c Tue May 1 16:05:00 2001 +++ linux/drivers/char/random.c Sun Jun 3 06:22:33 2001 @@ -380,8 +380,13 @@ /* * Static global variables */ +#ifdef CONFIG_GRKERNSEC_RANDPID +struct entropy_store *random_state; /* The default global store */ +struct entropy_store *sec_random_state; /* secondary store */ +#else static struct entropy_store *random_state; /* The default global store */ static struct entropy_store *sec_random_state; /* secondary store */ +#endif static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); diff -urN linux/drivers/char/vt.c linux/drivers/char/vt.c --- linux/drivers/char/vt.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/vt.c Sun Jun 3 06:22:33 2001 @@ -174,7 +174,11 @@ val = (i ? K_HOLE : K_NOSUCHMAP); return put_user(val, &user_kbe->kb_value); case KDSKBENT: +#ifdef CONFIG_GRKERNSEC_KBMAP + if (!perm || !suser()) +#else if (!perm) +#endif return -EPERM; if (!i && v == K_NOSUCHMAP) { /* disallocate map */ @@ -293,7 +297,11 @@ put_user('\0', q); return ((p && *p) ? -EOVERFLOW : 0); case KDSKBSENT: +#ifdef CONFIG_GRKERNSEC_KBMAP + if (!perm || !suser()) +#else if (!perm) +#endif return -EPERM; q = func_table[i]; diff -urN linux/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c --- linux/drivers/ieee1394/video1394.c Thu May 24 14:55:17 2001 +++ linux/drivers/ieee1394/video1394.c Sun Jun 3 06:22:33 2001 @@ -677,7 +677,11 @@ pos=(unsigned long) d->buf; while (size > 0) { page = kvirt_to_pa(pos); +#ifdef CONFIG_GRKERNSEC_PAX + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start+=PAGE_SIZE; pos+=PAGE_SIZE; diff -urN linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c --- linux/drivers/media/video/bttv-driver.c Sat May 19 17:43:06 2001 +++ linux/drivers/media/video/bttv-driver.c Sun Jun 3 06:22:33 2001 @@ -2034,7 +2034,11 @@ pos=(unsigned long) btv->fbuffer; while (size > 0) { page = kvirt_to_pa(pos); +#ifdef CONFIG_GRKERNSEC_PAX + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start+=PAGE_SIZE; pos+=PAGE_SIZE; diff -urN linux/drivers/media/video/buz.c linux/drivers/media/video/buz.c --- linux/drivers/media/video/buz.c Tue Mar 6 19:44:35 2001 +++ linux/drivers/media/video/buz.c Sun Jun 3 06:22:33 2001 @@ -2979,7 +2979,11 @@ todo = fraglen; pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j]; page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ +#ifdef CONFIG_GRKERNSEC_PAX + if (remap_page_range(start, page, todo, PAGE_SHARED_EXEC)) { +#else if (remap_page_range(start, page, todo, PAGE_SHARED)) { +#endif printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); return -EAGAIN; } @@ -3006,7 +3010,11 @@ todo = v4l_bufsize; page = zr->v4l_gbuf[i].fbuffer_phys; DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start)); +#ifdef CONFIG_GRKERNSEC_PAX + if (remap_page_range(start, page, todo, PAGE_SHARED_EXEC)) { +#else if (remap_page_range(start, page, todo, PAGE_SHARED)) { +#endif printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); return -EAGAIN; } diff -urN linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c --- linux/drivers/media/video/cpia.c Sat May 19 17:43:06 2001 +++ linux/drivers/media/video/cpia.c Sun Jun 3 06:22:33 2001 @@ -3004,7 +3004,11 @@ pos = (unsigned long)(cam->frame_buf); while (size > 0) { page = kvirt_to_pa(pos); +#ifdef CONFIG_GRKERNSEC_PAX + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) { +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { +#endif up(&cam->busy_lock); return -EAGAIN; } diff -urN linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c --- linux/drivers/media/video/planb.c Sat May 19 17:43:06 2001 +++ linux/drivers/media/video/planb.c Sun Jun 3 06:22:33 2001 @@ -2027,7 +2027,11 @@ } for (i = 0; i < pb->rawbuf_size; i++) { if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]), +#ifdef CONFIG_GRKERNSEC_PAX + PAGE_SIZE, PAGE_SHARED_EXEC)) +#else PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; if (size <= PAGE_SIZE) diff -urN linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c --- linux/drivers/media/video/zr36120.c Mon May 21 17:06:00 2001 +++ linux/drivers/media/video/zr36120.c Sun Jun 3 06:22:33 2001 @@ -1475,7 +1475,11 @@ pos = (unsigned long)ztv->fbuffer; while (size>0) { unsigned long page = virt_to_phys((void*)pos); +#ifdef CONFIG_GRKERNSEC_PAX + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; diff -urN linux/drivers/usb/ibmcam.c linux/drivers/usb/ibmcam.c --- linux/drivers/usb/ibmcam.c Thu May 24 14:55:51 2001 +++ linux/drivers/usb/ibmcam.c Sun Jun 3 06:22:33 2001 @@ -2841,7 +2841,11 @@ pos = (unsigned long)ibmcam->fbuf; while (size > 0) { page = kvirt_to_pa(pos); +#ifdef CONFIG_GRKERNSEC_PAX + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; diff -urN linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- linux/drivers/usb/ov511.c Thu May 24 15:24:37 2001 +++ linux/drivers/usb/ov511.c Sun Jun 3 06:22:33 2001 @@ -2752,7 +2752,11 @@ pos = (unsigned long)ov511->fbuf; while (size > 0) { page = kvirt_to_pa(pos); +#ifdef CONFIG_GRKERNSEC_PAX + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) +#else if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) +#endif return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; diff -urN linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- linux/fs/binfmt_aout.c Mon Mar 19 12:34:56 2001 +++ linux/fs/binfmt_aout.c Sun Jun 3 06:22:33 2001 @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -305,6 +306,9 @@ current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; +#ifdef CONFIG_GRKERNSEC_STACK + if (N_FLAGS(ex) & F_STACKEXEC) current->flags |= PF_STACKEXEC; +#endif #ifdef __sparc__ if (N_MAGIC(ex) == NMAGIC) { loff_t pos = fd_offset; @@ -391,7 +395,11 @@ down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, +#ifdef CONFIG_GRKERNSEC_PAX + PROT_READ | PROT_WRITE, +#else PROT_READ | PROT_WRITE | PROT_EXEC, +#endif MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); up_write(¤t->mm->mmap_sem); diff -urN linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- linux/fs/binfmt_elf.c Sat May 19 18:09:15 2001 +++ linux/fs/binfmt_elf.c Sun Jun 3 06:22:33 2001 @@ -10,7 +10,7 @@ */ #include - +#include #include #include #include @@ -71,7 +71,10 @@ #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) -static struct linux_binfmt elf_format = { +#ifndef CONFIG_GRKERNSEC_STACK +static +#endif +struct linux_binfmt elf_format = { NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE }; @@ -583,6 +586,9 @@ current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; +#ifdef CONFIG_GRKERNSEC_STACK + if (elf_ex.e_flags & EF_STACKEXEC) current->flags |= PF_STACKEXEC; +#endif elf_entry = (unsigned long) elf_ex.e_entry; /* Do this immediately, since STACK_TOP as used in setup_arg_pages diff -urN linux/fs/buffer.c linux/fs/buffer.c --- linux/fs/buffer.c Fri May 25 17:57:46 2001 +++ linux/fs/buffer.c Sun Jun 3 06:22:34 2001 @@ -45,6 +45,9 @@ #include #include #include +#ifdef CONFIG_LIDS +#include +#endif #include #include @@ -2617,8 +2620,12 @@ asmlinkage long sys_bdflush(int func, long data) { - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { +#ifdef CONFIG_LIDS + lids_security_alert("CAP_SYS_ADMIN violation: Try to use sys_bdflush"); +#endif return -EPERM; + } if (func == 1) { /* do_exit directly and let kupdate to do its work alone. */ diff -urN linux/fs/dcache.c linux/fs/dcache.c --- linux/fs/dcache.c Tue May 22 09:35:42 2001 +++ linux/fs/dcache.c Sun Jun 3 06:22:34 2001 @@ -71,6 +71,7 @@ * d_iput() operation if defined. * Called with dcache_lock held, drops it. */ + static inline void dentry_iput(struct dentry * dentry) { struct inode *inode = dentry->d_inode; diff -urN linux/fs/exec.c linux/fs/exec.c --- linux/fs/exec.c Thu Apr 26 14:11:29 2001 +++ linux/fs/exec.c Sun Jun 3 06:22:34 2001 @@ -45,6 +45,18 @@ #include #endif +#ifdef CONFIG_GRKERNSEC_FD +#include +#endif + +#ifdef CONFIG_GRKERNSEC_CHROOT +extern struct task_struct *child_reaper; +#endif + +#ifdef CONFIG_LIDS +#include +#endif + static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; @@ -276,7 +288,11 @@ goto out; flush_dcache_page(page); flush_page_to_ram(page); +#ifdef CONFIG_GRKERNSEC_PAX + set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY_NOEXEC)))); +#else set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY)))); +#endif tsk->mm->rss++; spin_unlock(&tsk->mm->page_table_lock); @@ -311,7 +327,11 @@ mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = STACK_TOP; +#ifdef CONFIG_GRKERNSEC_PAX + mpnt->vm_page_prot = PAGE_COPY_NOEXEC; +#else mpnt->vm_page_prot = PAGE_COPY; +#endif mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_ops = NULL; mpnt->vm_pgoff = 0; @@ -468,6 +488,65 @@ if (atomic_dec_and_test(&oldsig->count)) kmem_cache_free(sigact_cachep, oldsig); } +#ifdef CONFIG_GRKERNSEC_FD +static inline int tweak_fd_open_null(struct linux_binprm *bprm) +{ + struct inode *i; + struct dentry *d; + struct file *f; + + if(!(i = get_empty_inode())) + return -ENOMEM; + if(!(d = dget(d_alloc_root(i)))){ + iput(i); + return -ENOMEM; + } + if(!(f = get_empty_filp())){ + dput(d); + iput(i); + return -ENFILE; + } + i->i_mode = S_IFCHR | S_IRUGO | S_IWUGO; + i->i_uid = current->fsuid; + i->i_gid = current->fsgid; + i->i_rdev = MKDEV(MEM_MAJOR,3); + i->i_blksize = PAGE_SIZE; + i->i_blocks = 0; + i->i_atime = i->i_mtime = i->i_ctime = CURRENT_TIME; + i->i_op = &page_symlink_inode_operations; + i->i_state = I_DIRTY; + f->f_flags = O_RDWR; + f->f_mode = FMODE_READ | FMODE_WRITE; + f->f_dentry = d; + f->f_pos = 0; + f->f_reada = 0; + chrdev_open(i,f); + bprm->tweak_fd_null = f; + return 0; +} + +static int tweak_fd_0_1_2(struct linux_binprm *bprm) +{ + int fd,new,retval; + struct file *f; + f = bprm->tweak_fd_null; + for(fd=0;fd<=2;fd++){ + if(current->files->fd[fd]) continue; + if((new = get_unused_fd()) != fd) { + if(new >= 0) put_unused_fd(new); + return -EMFILE; + } + if(f) + atomic_inc(&f->f_count); + else + if((retval = tweak_fd_open_null(bprm))) + return retval; + fd_install(fd,bprm->tweak_fd_null); + bprm->tweak_fd_mask |= 1 << fd; + } + return 0; +} +#endif /* * These functions flushes out all traces of the currently running executable @@ -558,14 +637,16 @@ current->comm[i++] = ch; } current->comm[i] = '\0'; - +#ifdef CONFIG_GRKERNSEC_STACK + current->flags &= ~PF_STACKEXEC; +#endif flush_thread(); de_thread(current); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->file->f_dentry->d_inode,MAY_READ)) - current->dumpable = 0; + current->dumpable = 0; /* An exec changes our domain. We are no longer part of the thread group */ @@ -574,7 +655,10 @@ flush_signal_handlers(current); flush_old_files(current->files); - +#ifdef CONFIG_GRKERNSEC_FD + if(bprm->priv_change) + return tweak_fd_0_1_2(bprm); +#endif return 0; mmap_failed: @@ -604,6 +688,9 @@ { int mode; struct inode * inode = bprm->file->f_dentry->d_inode; +#ifdef CONFIG_GRKERNSEC_FD + bprm->priv_change = 0; +#endif mode = inode->i_mode; /* Huh? We had already checked for MAY_EXEC, WTF do we check this? */ @@ -617,8 +704,16 @@ if(!IS_NOSUID(inode)) { /* Set-uid? */ - if (mode & S_ISUID) - bprm->e_uid = inode->i_uid; +#ifdef CONFIG_GRKERNSEC_FD + if (mode & S_ISUID){ + bprm->e_uid = inode->i_uid; + if(bprm->e_uid != current->euid) + bprm->priv_change = 1; + } +#else + if (mode & S_ISUID) + bprm->e_uid = inode->i_uid; +#endif /* Set-gid? */ /* @@ -626,9 +721,17 @@ * is a candidate for mandatory locking, not a setgid * executable. */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) - bprm->e_gid = inode->i_gid; - } +#ifdef CONFIG_GRKERNSEC_FD + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)){ + bprm->e_gid = inode->i_gid; + if(!in_group_p(bprm->e_gid)) + bprm->priv_change = 1; + } +#else + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) + bprm->e_gid = inode->i_gid; +#endif +} /* We don't have VFS support for capabilities yet */ cap_clear(bprm->cap_inheritable); @@ -648,10 +751,10 @@ cap_set_full(bprm->cap_inheritable); cap_set_full(bprm->cap_permitted); } - if (bprm->e_uid == 0) + + if (bprm->e_uid == 0) cap_set_full(bprm->cap_effective); } - memset(bprm->buf,0,BINPRM_BUF_SIZE); return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); } @@ -684,7 +787,6 @@ if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || !cap_issubset(new_permitted, current->cap_permitted)) { current->dumpable = 0; - lock_kernel(); if (must_not_trace_exec(current) || atomic_read(¤t->fs->count) > 1 @@ -699,6 +801,9 @@ current->cap_permitted); } } +#ifdef CONFIG_GRKERNSEC_FD + tweak_fd_0_1_2(bprm); +#endif do_unlock = 1; } @@ -847,6 +952,37 @@ struct file *file; int retval; int i; +#ifdef CONFIG_LIDS + struct dentry *dentry; +#endif +#ifdef CONFIG_GRKERNSEC_EXECLOG + int x; + char *grargs; + char grarg[68]; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_EXECLOG + if(!( (current->fs->root->d_inode->i_dev == + child_reaper->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child_reaper->fs->root->d_inode->i_ino) ) ) { + security_alert("exec of %.64s within chroot() jail (%.32s:%lu) by process (%.16s:%d), " + "UID (%d), EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d)", + "execs from chroot()",filename,kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + } +#endif +#ifdef CONFIG_GRKERNSEC_EXECVE + if(current->user) + if(atomic_read(¤t->user->processes) > current->rlim[RLIMIT_NPROC].rlim_cur) + { + security_alert("Attempt to overstep process limit by (%.16s:%d), UID(%d), EUID(%d), parent (%.16s:%d), UID(%d), EUID(%d)", + "proc limit overstep", + current->comm,current->pid,current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid,current->p_pptr->euid); + return -EAGAIN; + } +#endif file = open_exec(filename); @@ -854,6 +990,166 @@ if (IS_ERR(file)) return retval; +#ifdef CONFIG_GRKERNSEC_TPE +#ifdef CONFIG_GRKERNSEC_TPE_GLIBC +#ifdef CONFIG_GRKERNSEC_TPE_ALL +if(current->uid){ +#else +if(in_group_p(CONFIG_GRKERNSEC_TPE_GID)){ +#endif + char **envpp=envp,*envpt; + while(*envpp){ + envpt=*envpp; + if((*envpt == 'L') && (*(envpt + 1) == 'D') && + (*(envpt + 2) == '_') && strchr(envpt,'=')){ + security_alert("denied exec of %.32s by (%.16s:%d), UID (%d), " + "EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d) reason: " + "malicious environment","denied execs", + filename,current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + dput(file->f_dentry); + return -EACCES; + } + *envpp=*++envpp; + } + if(!strncmp(file->f_dentry->d_name.name,"ld-2.",5) && + !strncmp(file->f_dentry->d_parent->d_name.name,"lib",3)){ + security_alert("denied exec of %.32s by (%.16s:%d), UID (%d), " + "EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d) reason: " + "tried to bypass via ld","denied execs", + filename,current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + dput(file->f_dentry); + return -EACCES; + } +} +#endif +if((current->uid) && + ((file->f_dentry->d_parent->d_inode->i_uid) || + (!(file->f_dentry->d_parent->d_inode->i_uid) && + ((file->f_dentry->d_parent->d_inode->i_mode & S_IWGRP) || + (file->f_dentry->d_parent->d_inode->i_mode & S_IWOTH)))) && + (in_group_p(CONFIG_GRKERNSEC_TPE_GID))){ +security_alert("denied exec of %.32s by (%.16s:%d), UID (%d), " + "EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d) reason: " + "untrusted","denied execs", + filename,current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + dput(file->f_dentry); + return -EACCES; +} +#ifdef CONFIG_GRKERNSEC_TPE_ALL +else if((current->uid) && !(((!(file->f_dentry->d_parent->d_inode->i_uid) && + !(file->f_dentry->d_parent->d_inode->i_mode & S_IWGRP) && + !(file->f_dentry->d_parent->d_inode->i_mode & S_IWOTH)) || + ((file->f_dentry->d_parent->d_inode->i_uid == current->uid) && + !(file->f_dentry->d_parent->d_inode->i_mode & S_IWGRP) && + !(file->f_dentry->d_parent->d_inode->i_mode & S_IWOTH))))){ +security_alert("denied exec of %.32s by (%.16s:%d), UID (%d), " + "EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d) reason:" + " untrusted","denied execs", + filename,current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + dput(file->f_dentry); + return -EACCES; +} +#endif +#endif +#ifdef CONFIG_GRKERNSEC_NOEXEC + if(in_group_p(CONFIG_GRKERNSEC_NOEXEC_GID) && + (file->f_dentry->d_inode->i_gid != CONFIG_GRKERNSEC_NOEXEC_GID)) { + security_alert("denied exec of %.32s by (%.16s:%d), UID(%d), " + "EUID(%d), parent (%.16s:%d), UID(%d), EUID(%d) reason: in " + "noexec group","denied noexec execs",filename,current->comm, + current->pid,current->uid,current->euid,current->p_pptr->comm, + current->p_pptr->pid,current->p_pptr->uid,current->p_pptr->euid); + dput(file->f_dentry); + return -EACCES; + } else if(in_group_p(CONFIG_GRKERNSEC_NOEXEC_GID)){ +#ifdef CONFIG_GRKERNSEC_NOEXEC_GLIBC + char **envpp=envp,*envpt; + while(*envpp){ + envpt=*envpp; + if((*envpt == 'L') && (*(envpt + 1) == 'D') && + (*(envpt + 2) == '_') && strchr(envpt,'=')){ + security_alert("denied exec of %.32s by (%.16s:%d), UID (%d), " + "EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d) reason: " + "malicious environment","denied execs", + filename,current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + dput(file->f_dentry); + return -EACCES; + } + *envpp=*++envpp; + } + if(!strncmp(file->f_dentry->d_name.name,"ld-2.",5) && + !strncmp(file->f_dentry->d_parent->d_name.name,"lib",3)){ + security_alert("denied exec of %.32s by (%.16s:%d), UID (%d), " + "EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d) reason: " + "tried to bypass via libs","denied execs", + filename,current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + dput(file->f_dentry); + return -EACCES; + } +#endif + +#ifdef CONFIG_GRKERNSEC_NOEXEC_CAPS + cap_lower(current->cap_permitted,CAP_SETGID + & CAP_SETPCAP & CAP_SYS_RAWIO & CAP_SYS_MODULE & CAP_SYS_ADMIN & + CAP_NET_ADMIN & CAP_SYS_BOOT & CAP_LINUX_IMMUTABLE & CAP_SYS_PTRACE); + cap_lower(current->cap_effective,CAP_SETGID + & CAP_SETPCAP & CAP_SYS_RAWIO & CAP_SYS_MODULE & CAP_SYS_ADMIN & + CAP_NET_ADMIN & CAP_SYS_BOOT & CAP_LINUX_IMMUTABLE & CAP_SYS_PTRACE); + cap_lower(current->cap_inheritable,CAP_SETGID + & CAP_SETPCAP & CAP_SYS_RAWIO & CAP_SYS_MODULE & CAP_SYS_ADMIN & + CAP_NET_ADMIN & CAP_SYS_BOOT & CAP_LINUX_IMMUTABLE & CAP_SYS_PTRACE); +#else + cap_lower(current->cap_permitted,CAP_SETGID); + cap_lower(current->cap_effective,CAP_SETGID); + cap_lower(current->cap_inheritable,CAP_SETGID); +#endif + } +#endif +#ifdef CONFIG_GRKERNSEC_SIDCAPS + if(((file->f_dentry->d_inode->i_mode & S_ISUID) && + !(file->f_dentry->d_inode->i_uid)) || + ((file->f_dentry->d_inode->i_mode & S_ISGID) && + !(file->f_dentry->d_inode->i_gid))){ + cap_lower(current->cap_permitted, + CAP_SETPCAP & CAP_SYS_RAWIO & CAP_SYS_MODULE & + CAP_SYS_BOOT & CAP_LINUX_IMMUTABLE & CAP_SYS_PTRACE); + cap_lower(current->cap_effective, + CAP_SETPCAP & CAP_SYS_RAWIO & CAP_SYS_MODULE & + CAP_SYS_BOOT & CAP_LINUX_IMMUTABLE & CAP_SYS_PTRACE); + cap_lower(current->cap_inheritable, + CAP_SETPCAP & CAP_SYS_RAWIO & CAP_SYS_MODULE & + CAP_SYS_BOOT & CAP_LINUX_IMMUTABLE & CAP_SYS_PTRACE); + } +#endif +#ifdef CONFIG_LIDS + dentry = file->f_dentry; +#endif +#ifdef CONFIG_LIDS_SA_EXEC_UP + if (lids_first_time && lids_load) { + if (lids_check_base(file->f_dentry,LIDS_APPEND) == 0) { +#ifdef CONFIG_LIDS_NO_EXEC_UP + lids_security_alert("Try to exec unprotected program %s before sealing LIDS",filename); + if (file->f_dentry) + dput(file->f_dentry); + return -EPERM; +#else + lids_security_alert("Exec'ed unprotected program %s before sealing LIDS",filename); +#endif + } + } +#endif bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); @@ -867,13 +1163,30 @@ fput(file); return bprm.argc; } +#ifdef CONFIG_GRKERNSEC_EXECLOG + for(x=0;xpid,current->uid,current->euid,current->comm, + current->pid,current->p_pptr->comm,current->p_pptr->pid,current->uid,current->euid); +#endif if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) { allow_write_access(file); fput(file); return bprm.envc; } - +#ifdef CONFIG_GRKERNSEC_FD + bprm.tweak_fd_mask = 0; + bprm.tweak_fd_null = NULL; +#endif retval = prepare_binprm(&bprm); if (retval < 0) goto out; @@ -892,9 +1205,20 @@ goto out; retval = search_binary_handler(&bprm,regs); - if (retval >= 0) + if (retval >= 0) { +#ifdef CONFIG_LIDS + if(dentry) if (dentry->d_inode) { + struct lids_sys_acl *this_sys_acl; + + this_sys_acl = lids_search_acl(dentry->d_inode->i_ino,dentry->d_inode->i_dev,lids_current); + /* set the ACLs */ + if( (retval=lids_set_acls(this_sys_acl)) < 0 ) + goto out; + } +#endif /* execve success */ return retval; + } out: /* Something went wrong, return the inode and free the argument pages*/ @@ -907,7 +1231,13 @@ if (page) __free_page(page); } - +#ifdef CONFIG_GRKERNSEC_FD + if(bprm.tweak_fd_mask) { + for(i=0;i<=2;i++) + if(bprm.tweak_fd_mask & (1 << i)) + (void)sys_close(i); + } +#endif return retval; } @@ -939,7 +1269,7 @@ goto fail; memcpy(corename,"core.", 5); -#if 0 +#ifdef CONFIG_GRKERNSEC_COREDUMP memcpy(corename+5,current->comm,sizeof(current->comm)); #else corename[4] = '\0'; diff -urN linux/fs/namei.c linux/fs/namei.c --- linux/fs/namei.c Sat May 19 18:02:45 2001 +++ linux/fs/namei.c Sun Jun 3 06:22:34 2001 @@ -31,8 +31,16 @@ #include +#ifdef CONFIG_LIDS +#include +#endif + #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) +#ifdef CONFIG_GRKERNSEC_CHROOT +extern struct task_struct *child_reaper; +#endif + /* [Feb-1997 T. Schoebel-Theuer] * Fundamental changes in the pathname lookup mechanisms (namei) * were necessary because of omirr. The reason is that omirr needs @@ -315,6 +323,27 @@ if (current->link_count >= 8) goto loop; current->link_count++; +#ifdef CONFIG_GRKERNSEC_LINK + if(S_ISLNK(dentry->d_inode->i_mode) && + (dentry->d_parent->d_inode->i_mode & S_ISVTX) && + dentry->d_parent->d_inode->i_uid != dentry->d_inode->i_uid && + (dentry->d_parent->d_inode->i_mode & S_IWOTH) && + current->fsuid != dentry->d_inode->i_uid) { + security_alert("not following symlink (%.30s/%.30s) of [%.32s]:%lu owned by %d.%d " + "by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), " + "UID (%d), EUID (%d)","symlinks not followed", + dentry->d_parent->d_name.name, + dentry->d_name.name, + kdevname(dentry->d_inode->i_dev), + dentry->d_inode->i_ino, + dentry->d_inode->i_uid, + dentry->d_inode->i_gid,current->comm, + current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + return -EACCES; + } +#endif UPDATE_ATIME(dentry->d_inode); err = dentry->d_inode->i_op->follow_link(dentry, nd); current->link_count--; @@ -425,7 +454,10 @@ struct inode *inode; int err; unsigned int lookup_flags = nd->flags; - +#ifdef CONFIG_LIDS + char *lids_file_name; + lids_file_name = (char *)name; +#endif while (*name=='/') name++; if (!*name) @@ -600,6 +632,19 @@ else if (this.len == 2 && this.name[1] == '.') nd->last_type = LAST_DOTDOT; return_base: +#ifdef CONFIG_LIDS + if (lids_load && lids_local_load) { + if (lids_check_base(nd->dentry,LIDS_READONLY) < 0) { +#ifdef CONFIG_LIDS_HANGUP + if(current->tty!=NULL) + set_bit(TTY_LIDS_NO_HANGUP, &(current->tty->flags)); +#endif + lids_security_alert("access hidden file %s",lids_file_name); + err = -ENOENT; + break; + } + } +#endif return 0; out_dput: dput(dentry); @@ -625,6 +670,7 @@ nd_root.mnt = mntget(current->fs->rootmnt); nd_root.dentry = dget(current->fs->root); read_unlock(¤t->fs->lock); + if (path_walk(name, &nd_root)) return 1; if (nd_root.dentry->d_inode) { @@ -942,12 +988,42 @@ struct dentry *dir; int count = 0; +#ifdef CONFIG_LIDS + /* search the dentry */ + if(lids_load && lids_local_load) { + if (path_init(pathname, lookup_flags(flag), nd)) + error = path_walk(pathname, nd); + if (error) + return error; + dentry = nd->dentry; + + /*FIXME: if the dentry need IS_ERR(dentry) */ + if( (flag&O_ACCMODE) >1) { + if(flag & O_APPEND) { + error = lids_check_base(dentry,LIDS_APPEND); + if(error) + lids_security_alert("Try to open %.1024s for appending,flag=%d",pathname,flag); + } + else { + error = lids_check_base(dentry,LIDS_WRITE); + if(error) + lids_security_alert("Try to open %.1024s for writing,flag=%d",pathname,flag); + } + if(error < 0 ) { + error=-EPERM; + goto exit; + } + } + /* try to release the allocated lids_nd*/ + //dput(dentry); + path_release(nd); + } +#endif acc_mode = ACC_MODE(flag); - /* * The simplest case - just a plain lookup. */ - if (!(flag & O_CREAT)) { + if (!(flag & O_CREAT)) { if (path_init(pathname, lookup_flags(flag), nd)) error = path_walk(pathname, nd); if (error) @@ -1041,12 +1117,31 @@ error = permission(inode,acc_mode); if (error) goto exit; - /* * FIFO's, sockets and device files are special: they don't * actually live on the filesystem itself, and as such you * can write to them even if the filesystem is read-only. */ +#ifdef CONFIG_GRKERNSEC_FIFO + if (S_ISFIFO(inode->i_mode) && !(flag & O_EXCL) && + (dentry->d_parent->d_inode->i_mode & S_ISVTX) && + inode->i_uid != dentry->d_parent->d_inode->i_uid && + current->fsuid != inode->i_uid) { + if (!permission(inode, acc_mode)) + security_alert("denied writing FIFO (%.32s/%.32s) of %d.%d " + "by (%.16s:%d), UID(%d), EUID(%d), parent " + "(%.16s:%d), UID(%d), EUID(%d)", + "writes into a FIFO denied",dentry->d_parent->d_name.name,dentry->d_name.name, + inode->i_uid, inode->i_gid, + current->comm,current->pid, + current->uid, current->euid, + current->p_pptr->comm, + current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + error = -EACCES; + goto exit; + } +#endif if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { flag &= ~O_TRUNC; } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { @@ -1121,6 +1216,29 @@ * stored in nd->last.name and we will have to putname() it when we * are done. Procfs-like symlinks just set LAST_BIND. */ +#ifdef CONFIG_GRKERNSEC_LINK + if(S_ISLNK(dentry->d_inode->i_mode) && + (dentry->d_parent->d_inode->i_mode & S_ISVTX) && + dentry->d_parent->d_inode->i_uid != dentry->d_inode->i_uid && + (dentry->d_parent->d_inode->i_mode & S_IWOTH) && + current->fsuid != dentry->d_inode->i_uid) { + security_alert("not following symlink (%.30s/%.30s) [%.32s]:%lu of %d.%d " + "by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), " + "UID (%d), EUID (%d)","symlinks not followed", + dentry->d_parent->d_name.name, + dentry->d_name.name, + kdevname(dentry->d_inode->i_dev), + dentry->d_inode->i_ino, + dentry->d_inode->i_uid, + dentry->d_inode->i_gid,current->comm, + current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + error = -EACCES; + goto exit; + } +#endif + UPDATE_ATIME(dentry->d_inode); error = dentry->d_inode->i_op->follow_link(dentry, nd); dput(dentry); @@ -1206,7 +1324,9 @@ char * tmp; struct dentry * dentry; struct nameidata nd; - +#ifdef CONFIG_GRKERNSEC_CHROOT + char grdevmode; +#endif if (S_ISDIR(mode)) return -EPERM; tmp = getname(filename); @@ -1220,6 +1340,43 @@ dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { +#ifdef CONFIG_GRKERNSEC_CHROOT + if (!S_ISFIFO(mode)) { + if(!( (current->fs->root->d_inode->i_dev == + child_reaper->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child_reaper->fs->root->d_inode->i_ino) ) ) { + switch (mode & S_IFMT) { + case S_IFREG: grdevmode = 'r'; break; + case S_IFCHR: grdevmode = 'c'; break; + case S_IFBLK: grdevmode = 'b'; break; + case S_IFSOCK: grdevmode = 's'; break; + default: grdevmode = 'u'; + } + security_alert("refused attempt to mknod(%c:%.32s) (%.30s) from chroot() jail (%s:%lu) " + "owned by %d %d by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), UID " + "(%d), EUID (%d)","chroot() mknods denied",grdevmode,kdevname(dev),tmp, + kdevname(current->fs->root->d_inode->i_dev),current->fs->root->d_inode->i_ino, + current->fs->root->d_inode->i_uid,current->fs->root->d_inode->i_gid, + current->comm,current->pid,current->uid,current->euid,current->p_pptr->comm, + current->p_pptr->pid,current->p_pptr->uid,current->p_pptr->euid); + dput(dentry); + error = -EPERM; + goto out; + } + } +#endif +#ifdef CONFIG_LIDS + if (lids_load && lids_local_load) { + if (lids_check_base(dentry,LIDS_WRITE)) { + lids_security_alert("Try to mknod %.1024s (%d %d)", + filename,MAJOR(dev),MINOR(dev)); + dput(dentry); + error = -EPERM; + goto out; + } + } +#endif switch (mode & S_IFMT) { case 0: case S_IFREG: error = vfs_create(nd.dentry->d_inode,dentry,mode); @@ -1287,6 +1444,16 @@ dentry = lookup_create(&nd, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { +#ifdef CONFIG_LIDS + error = 0; /* FIXME, do we need this? */ + if (lids_load && lids_local_load) { + if (lids_check_base(dentry,LIDS_WRITE)) { + lids_security_alert("Try to mkdir %.1024s",pathname); + error = -EPERM; + } + } + if(!error) +#endif error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); dput(dentry); } @@ -1394,6 +1561,17 @@ dentry = lookup_hash(&nd.last, nd.dentry); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { + +#ifdef CONFIG_LIDS + error = 0; /* FIXME, do we actually need this ?*/ + if (lids_load && lids_local_load) { + if (lids_check_base(dentry,LIDS_WRITE)) { + lids_security_alert("Try to rmdir %.1024s",name); + error = -EPERM; + } + } + if(!error) +#endif error = vfs_rmdir(nd.dentry->d_inode, dentry); dput(dentry); } @@ -1457,6 +1635,16 @@ /* Why not before? Because we want correct error value */ if (nd.last.name[nd.last.len]) goto slashes; +#ifdef CONFIG_LIDS + error = 0; /* FIXME, do we actually need this ?*/ + if (lids_load && lids_local_load) { + if (lids_check_base(dentry,LIDS_WRITE)) { + lids_security_alert("Try to unlink %.1024s",pathname); + error = -EPERM; + } + } + if(!error) +#endif error = vfs_unlink(nd.dentry->d_inode, dentry); exit2: dput(dentry); @@ -1522,6 +1710,16 @@ dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { +#ifdef CONFIG_LIDS + error = 0; /* FIXME, do we actually need this ?*/ + if (lids_load && lids_local_load) { + if (lids_check_base(dentry,LIDS_WRITE)) { + lids_security_alert("Try to symlink %.1024s to %.1024s", oldname,newname); + error = -EPERM; + } + } + if(!error) +#endif error = vfs_symlink(nd.dentry->d_inode, dentry, from); dput(dentry); } @@ -1613,6 +1811,33 @@ new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { +#ifdef CONFIG_GRKERNSEC_LINK + error = -EPERM; + if(current->fsuid != old_nd.dentry->d_inode->i_uid && + (!S_ISREG(old_nd.dentry->d_inode->i_mode) || + (old_nd.dentry->d_inode->i_mode & S_ISUID) || + ((old_nd.dentry->d_inode->i_mode & (S_ISGID | S_IXGRP)) == + (S_ISGID | S_IXGRP)) || (error = permission(old_nd.dentry->d_inode, + MAY_READ | MAY_WRITE))) && !capable(CAP_FOWNER) && current->uid) { + security_alert("denied hardlink of (%.30s to %.30s) to %d.%d for (%.16s:%d)," + " UID(%d), EUID(%d), parent (%.16s:%d), UID(%d), EUID(%d)", + "denied hardlinks",oldname,newname,old_nd.dentry->d_inode->i_uid, + old_nd.dentry->d_inode->i_gid,current->comm,current->pid,current->uid, + current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + goto exit; + } +#endif +#ifdef CONFIG_LIDS + error = 0; /* FIXME, do we actually need this ?*/ + if (lids_load && lids_local_load) { + if (lids_check_base(old_nd.dentry,LIDS_WRITE) || lids_check_base(new_dentry,LIDS_WRITE)) { + lids_security_alert("Try to link %.1024s to %.1024s", oldname,newname); + error = -EPERM; + } + } + if(!error) +#endif error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); dput(new_dentry); } @@ -1847,11 +2072,25 @@ if (IS_ERR(new_dentry)) goto exit4; +#ifdef CONFIG_LIDS + error = 0; + if (lids_load && lids_local_load) { + if (lids_check_base(old_dentry,LIDS_WRITE) || + lids_check_base(new_dentry,LIDS_WRITE)) { + lids_security_alert("Try to rename %.1024s to %.1024s", oldname,newname); + error = -EPERM; + goto exit_new; + } + } + if(!error) +#endif + { lock_kernel(); error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); unlock_kernel(); - + } +exit_new: dput(new_dentry); exit4: dput(old_dentry); diff -urN linux/fs/open.c linux/fs/open.c --- linux/fs/open.c Fri Feb 9 11:29:44 2001 +++ linux/fs/open.c Sun Jun 3 06:22:34 2001 @@ -19,6 +19,14 @@ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) +#ifdef CONFIG_GRKERNSEC_CHROOT +extern struct task_struct *child_reaper; +#endif + +#ifdef CONFIG_LIDS +#include +#endif + int vfs_statfs(struct super_block *sb, struct statfs *buf) { int retval = -ENODEV; @@ -80,6 +88,17 @@ if (length < 0) return -EINVAL; +#ifdef CONFIG_LIDS + if (lids_load && lids_local_load) { + if (lids_check_base(dentry,LIDS_WRITE) < 0) { + lids_security_alert("Try to truncate a protected file (dev %d %d,inode %ld)", + MAJOR(dentry->d_inode->i_dev), + MINOR(dentry->d_inode->i_dev), + dentry->d_inode->i_ino); + return -EPERM; + } + } +#endif down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; @@ -226,7 +245,15 @@ error = -EROFS; if (IS_RDONLY(inode)) goto dput_and_out; - +#ifdef CONFIG_LIDS + if(lids_load && lids_local_load) { + if (lids_check_base(nd.dentry,LIDS_WRITE)) { + lids_security_alert("Try to change utime of %s",filename); + error = -EPERM; + goto dput_and_out; + } + } +#endif /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { @@ -242,6 +269,7 @@ (error = permission(inode,MAY_WRITE)) != 0) goto dput_and_out; } + error = notify_change(nd.dentry, &newattrs); dput_and_out: path_release(&nd); @@ -328,6 +356,14 @@ if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) && !special_file(nd.dentry->d_inode->i_mode)) res = -EROFS; +#ifdef CONFIG_LIDS + if(!res && (mode & S_IWOTH ) && lids_load && lids_local_load) { + if (lids_check_base(nd.dentry,LIDS_WRITE)) { + lids_security_alert("Try to access %s",filename); + res=-EPERM; + } + } +#endif path_release(&nd); } @@ -421,11 +457,49 @@ goto dput_and_out; error = -EPERM; - if (!capable(CAP_SYS_CHROOT)) - goto dput_and_out; + if (!capable(CAP_SYS_CHROOT)) { +#ifdef CONFIG_LIDS + lids_security_alert("CAP_SYS_CHROOT violation: Try to chroot %s",filename); +#endif + goto dput_and_out; + } +#ifdef CONFIG_GRKERNSEC_CHROOT + if(!( (current->fs->root->d_inode->i_dev == + child_reaper->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child_reaper->fs->root->d_inode->i_ino) ) ) { + security_alert("denied attempt to chroot() from (%.32s:%lu) to (%.30s)" + ", process (%.16s:%d), UID (%d), EUID (%d), parent " + "(%16s:%d), UID (%d), EUID (%d)", "double chroot() denied", + kdevname(current->fs->root->d_inode->i_dev),current->fs->root->d_inode->i_ino,name, + current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + goto dput_and_out; + } +#endif set_fs_root(current->fs, nd.mnt, nd.dentry); set_fs_altroot(); +#ifdef CONFIG_GRKERNSEC_CHROOT_CAPS + if(current->pid && current->pid > 1) { + cap_lower(current->cap_permitted,CAP_FOWNER & CAP_SETPCAP & CAP_LINUX_IMMUTABLE & + CAP_NET_ADMIN & CAP_SYS_MODULE & CAP_SYS_RAWIO & CAP_SYS_PACCT & + CAP_SYS_ADMIN & CAP_SYS_BOOT & CAP_SYS_RESOURCE & CAP_SYS_TIME & + CAP_SYS_TTY_CONFIG); + cap_lower(current->cap_inheritable,CAP_FOWNER & CAP_SETPCAP & CAP_LINUX_IMMUTABLE & + CAP_NET_ADMIN & CAP_SYS_MODULE & CAP_SYS_RAWIO & CAP_SYS_PACCT & + CAP_SYS_ADMIN & CAP_SYS_BOOT & CAP_SYS_RESOURCE & CAP_SYS_TIME & + CAP_SYS_TTY_CONFIG); + cap_lower(current->cap_effective,CAP_FOWNER & CAP_SETPCAP & CAP_LINUX_IMMUTABLE & + CAP_NET_ADMIN & CAP_SYS_MODULE & CAP_SYS_RAWIO & CAP_SYS_PACCT & + CAP_SYS_ADMIN & CAP_SYS_BOOT & CAP_SYS_RESOURCE & CAP_SYS_TIME & + CAP_SYS_TTY_CONFIG); + } +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT + sys_chdir("/"); +#endif error = 0; dput_and_out: path_release(&nd); @@ -451,11 +525,41 @@ err = -EROFS; if (IS_RDONLY(inode)) goto out_putf; +#ifdef CONFIG_LIDS + if( lids_load && lids_local_load) { + if (lids_check_base(dentry,LIDS_WRITE)) { + lids_security_alert("Try to fchmod a file to mode %o",mode); + err=-EPERM; + goto out_putf; + } + } +#endif err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out_putf; if (mode == (mode_t) -1) mode = inode->i_mode; +#ifdef CONFIG_GRKERNSEC_CHROOT + if((mode & S_ISUID) || (mode & S_ISGID)) { + if(!( (current->fs->root->d_inode->i_dev == + child_reaper->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child_reaper->fs->root->d_inode->i_ino) ) ) { + + security_alert("denied attempt to fchmod() +s (%.32s:%lu) owned by %d.%d to mode 0%07o " + "from chroot() jail (%.32s:%lu) of %d.%d by (%.16s:%d), UID (%d), " + "EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d)","denied fchmod() +s in chroot()", + kdevname(inode->i_dev),inode->i_ino,inode->i_uid,inode->i_gid,mode, + kdevname(current->fs->root->d_inode->i_dev),current->fs->root->d_inode->i_ino, + current->fs->root->d_inode->i_uid,current->fs->root->d_inode->i_gid, + current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + err = -EPERM; + goto out_putf; + } + } +#endif newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); @@ -482,12 +586,42 @@ if (IS_RDONLY(inode)) goto dput_and_out; +#ifdef CONFIG_LIDS + if( lids_load && (nd.dentry != NULL) && lids_local_load) { + if (lids_check_base(nd.dentry,LIDS_WRITE)) { + lids_security_alert("Try to chmod %.1024s to mode %o", + filename,mode); + error=-EPERM; + goto dput_and_out; + } + } +#endif error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; if (mode == (mode_t) -1) mode = inode->i_mode; +#ifdef CONFIG_GRKERNSEC_CHROOT + if ((mode & S_ISUID) || (mode & S_ISGID)) { + if(!( (current->fs->root->d_inode->i_dev == + child_reaper->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child_reaper->fs->root->d_inode->i_ino) ) ) { + security_alert("denied attempt to chmod() +s (%.32s:%lu) (%.30s) owned by %d.%d to mode 0%07o " + "from chroot() jail (%.32s:%lu) of %d.%d by (%.16s:%d), UID (%d), " + "EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d)","denied fchmod() +s in chroot()", + kdevname(inode->i_dev),inode->i_ino,filename,inode->i_uid,inode->i_gid, + mode,kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino,current->fs->root->d_inode->i_uid, + current->fs->root->d_inode->i_gid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + error = -EPERM; + goto dput_and_out; + } + } +#endif newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(nd.dentry, &newattrs); @@ -512,6 +646,27 @@ error = -EROFS; if (IS_RDONLY(inode)) goto out; +#ifdef CONFIG_GRKERNSEC_NOEXEC + if(in_group_p(CONFIG_GRKERNSEC_NOEXEC_GID) && + (group == CONFIG_GRKERNSEC_NOEXEC_GID)){ + security_alert("denied chown of %.32s by (%.16s:%d), UID(%d), " + "EUID(%d), parent (%.16s:%d), UID(%d), EUID(%d) reason: tried to " + "bypass noexec","denied noexec chowns",dentry->d_name.name,current->comm, + current->pid,current->uid,current->euid,current->p_pptr->comm, + current->p_pptr->pid,current->p_pptr->uid,current->p_pptr->euid); + return -EPERM; + } +#endif + +#ifdef CONFIG_LIDS + if( lids_load && (dentry != NULL) && lids_local_load) { + if (lids_check_base(dentry,LIDS_WRITE) < 0) { + lids_security_alert("Try to chown"); + error=-EPERM; + goto out; + } + } +#endif error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; @@ -845,5 +1000,8 @@ tty_vhangup(current->tty); return 0; } +#ifdef CONFIG_LIDS + lids_security_alert("CAP_SYS_TTY_CONFIG violation: Try to hangup tty"); +#endif return -EPERM; } diff -urN linux/fs/proc/base.c linux/fs/proc/base.c --- linux/fs/proc/base.c Fri May 4 14:44:06 2001 +++ linux/fs/proc/base.c Sun Jun 3 06:22:34 2001 @@ -502,6 +502,16 @@ static struct pid_entry base_stuff[] = { E(PROC_PID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR), E(PROC_PID_ENVIRON, "environ", S_IFREG|S_IRUSR), +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + E(PROC_PID_STATUS, "status", S_IFREG|S_IRUSR), + E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUSR), + E(PROC_PID_STAT, "stat", S_IFREG|S_IRUSR), + E(PROC_PID_STATM, "statm", S_IFREG|S_IRUSR), +#ifdef CONFIG_SMP + E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUSR), +#endif + E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUSR), +#else E(PROC_PID_STATUS, "status", S_IFREG|S_IRUGO), E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO), @@ -510,6 +520,7 @@ E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO), #endif E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO), +#endif E(PROC_PID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), E(PROC_PID_CWD, "cwd", S_IFLNK|S_IRWXUGO), E(PROC_PID_ROOT, "root", S_IFLNK|S_IRWXUGO), @@ -648,7 +659,9 @@ inode->i_gid = 0; if (ino == PROC_PID_INO || task->dumpable) { inode->i_uid = task->euid; +#ifndef CONFIG_GRKERNSEC_PROC_USERGROUP inode->i_gid = task->egid; +#endif } out: @@ -950,6 +963,10 @@ read_unlock(&tasklist_lock); if (!task) goto out; +#ifdef CONFIG_LIDS + if (cap_raised(task->lids_cap,CAP_HIDDEN) && lids_load && lids_local_load) + goto out; +#endif inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO); @@ -957,7 +974,11 @@ if (!inode) goto out; +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR; +#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; @@ -997,6 +1018,10 @@ int pid = p->pid; if (!pid) continue; +#ifdef CONFIG_LIDS + if ( cap_raised(p->lids_cap,CAP_HIDDEN) && lids_load && lids_local_load) + continue; +#endif if (--index >= 0) continue; pids[nr_pids] = pid; diff -urN linux/fs/proc/inode.c linux/fs/proc/inode.c --- linux/fs/proc/inode.c Tue Apr 17 23:16:39 2001 +++ linux/fs/proc/inode.c Sun Jun 3 06:22:34 2001 @@ -152,7 +152,11 @@ if (de->mode) { inode->i_mode = de->mode; inode->i_uid = de->uid; +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#else inode->i_gid = de->gid; +#endif } if (de->size) inode->i_size = de->size; diff -urN linux/fs/proc/root.c linux/fs/proc/root.c --- linux/fs/proc/root.c Wed May 16 18:05:34 2001 +++ linux/fs/proc/root.c Sun Jun 3 06:22:34 2001 @@ -17,6 +17,10 @@ #include #include +#ifdef CONFIG_LIDS_HIDE_PROC +#include +#endif + struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; #ifdef CONFIG_SYSCTL diff -urN linux/fs/read_write.c linux/fs/read_write.c --- linux/fs/read_write.c Tue Apr 17 14:36:44 2001 +++ linux/fs/read_write.c Sun Jun 3 06:22:34 2001 @@ -14,6 +14,10 @@ #include +#ifdef CONFIG_LIDS +#include +#endif + struct file_operations generic_ro_fops = { read: generic_file_read, mmap: generic_file_mmap, @@ -124,6 +128,16 @@ file = fget(fd); if (file) { if (file->f_mode & FMODE_READ) { +#ifdef CONFIG_LIDS + struct inode *inode; + inode = file->f_dentry->d_inode; + if (inode && S_ISBLK(inode->i_mode) && (!capable(CAP_SYS_RAWIO))) + if ( (lids_load) && lids_local_load) { + lids_security_alert("CAP_SYS_RAWIO violation: Try to read to raw device %d:%d", MAJOR(inode->i_dev),MINOR(inode->i_dev)); + fput(file); + return ret; + } +#endif ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode, file, file->f_pos, count); if (!ret) { @@ -156,8 +170,16 @@ if (!ret) { ssize_t (*write)(struct file *, const char *, size_t, loff_t *); ret = -EINVAL; - if (file->f_op && (write = file->f_op->write) != NULL) + if (file->f_op && (write = file->f_op->write) != NULL) { +#ifdef CONFIG_LIDS + if (inode && S_ISBLK(inode->i_mode) && (!capable(CAP_SYS_RAWIO))) { + lids_security_alert("CAP_SYS_RAWIO violation: Try to write to raw device %d:%d", MAJOR(inode->i_dev),MINOR(inode->i_dev)); + } + else +#endif + ret = write(file, buf, count, &file->f_pos); + } } } if (ret > 0) diff -urN linux/fs/readdir.c linux/fs/readdir.c --- linux/fs/readdir.c Mon Dec 11 13:45:42 2000 +++ linux/fs/readdir.c Sun Jun 3 06:22:34 2001 @@ -13,10 +13,15 @@ #include +#ifdef CONFIG_LIDS +#include +#endif + int vfs_readdir(struct file *file, filldir_t filler, void *buf) { struct inode *inode = file->f_dentry->d_inode; int res = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) goto out; down(&inode->i_sem); @@ -120,6 +125,9 @@ struct readdir_callback { struct old_linux_dirent * dirent; int count; +#ifdef CONFIG_LIDS + kdev_t dev; +#endif }; static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, @@ -130,6 +138,13 @@ if (buf->count) return -EINVAL; +#ifdef CONFIG_LIDS + if(lids_load && lids_local_load) { + if(lids_check_hidden_inode(ino,buf->dev) < 0 ) { + return 0; + } + } +#endif buf->count++; dirent = buf->dirent; put_user(ino, &dirent->d_ino); @@ -153,7 +168,13 @@ buf.count = 0; buf.dirent = dirent; - +#ifdef CONFIG_LIDS + /* FIXME, may be a member of dentry will be good*/ + buf.dev = 0; + if(file->f_dentry) if (file->f_dentry->d_inode) + buf.dev = file->f_dentry->d_inode->i_dev; + else printk(__FUNCTION__":bug!!\n"); +#endif error = vfs_readdir(file, fillonedir, &buf); if (error >= 0) error = buf.count; @@ -181,6 +202,9 @@ struct linux_dirent * previous; int count; int error; +#ifdef CONFIG_LIDS + kdev_t dev; +#endif }; static int filldir(void * __buf, const char * name, int namlen, off_t offset, @@ -194,6 +218,14 @@ if (reclen > buf->count) return -EINVAL; dirent = buf->previous; +#ifdef CONFIG_LIDS + /* added by xhg at 2000-4-14 */ + if(lids_load && lids_local_load) { + if(lids_check_hidden_inode(ino,buf->dev) < 0 ) { + return 0; + } + } +#endif if (dirent) put_user(offset, &dirent->d_off); dirent = buf->current_dir; @@ -224,7 +256,13 @@ buf.previous = NULL; buf.count = count; buf.error = 0; - +#ifdef CONFIG_LIDS +/* FIXME, may be a member of dentry will be good*/ + buf.dev = 0; + if(file->f_dentry) if(file->f_dentry->d_inode) + buf.dev = file->f_dentry->d_inode->i_dev; + else printk(__FUNCTION__":BUG!!"); +#endif error = vfs_readdir(file, filldir, &buf); if (error < 0) goto out_putf; diff -urN linux/fs/super.c linux/fs/super.c --- linux/fs/super.c Fri May 25 12:38:52 2001 +++ linux/fs/super.c Sun Jun 3 06:22:34 2001 @@ -42,6 +42,15 @@ #define __NO_VERSION__ #include +#ifdef CONFIG_GRKERNSEC_CHROOT +#include +extern struct task_struct *child_reaper; +#endif + +#ifdef CONFIG_LIDS +#include +#endif + /* * We use a semaphore to synchronize all mount/umount * activity - imagine the mess if we have a race between @@ -1097,8 +1106,12 @@ goto dput_and_out; retval = -EPERM; - if (!capable(CAP_SYS_ADMIN) && current->uid!=nd.mnt->mnt_owner) + if (!capable(CAP_SYS_ADMIN) && current->uid!=nd.mnt->mnt_owner) { +#ifdef CONFIG_LIDS + lids_security_alert("CAP_SYS_ADMIN violation: try to umount %s",name); +#endif goto dput_and_out; + } down(&mount_sem); lock_kernel(); @@ -1124,8 +1137,11 @@ static int mount_is_safe(struct nameidata *nd) { - if (capable(CAP_SYS_ADMIN)) + if (capable(CAP_SYS_ADMIN)) return 0; +#ifdef CONFIG_LIDS + lids_security_alert("CAP_SYS_ADMIN violation: mount_is_safe\n"); +#endif return -EPERM; #ifdef notyet if (S_ISLNK(nd->dentry->d_inode->i_mode)) @@ -1195,8 +1211,12 @@ struct nameidata nd; int retval = 0; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { +#ifdef CONFIG_LIDS + lids_security_alert("CAP_SYS_ADMIN violation: Try to remount %s ",dir); +#endif return -EPERM; + } if (path_init(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) retval = path_walk(dir, &nd); @@ -1308,7 +1328,24 @@ /* for the rest we _really_ need capabilities... */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - +#ifdef CONFIG_GRKERNSEC_CHROOT + if (!( (current->fs->root->d_inode->i_dev == + child_reaper->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child_reaper->fs->root->d_inode->i_ino) ) ) { + + security_alert("denied attempt to mount (%.30s) as %.64s from chroot() jail (%.32s:%lu) " + "of %d.%d by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), " + "UID (%d), EUID (%d)","denied mounts in chroot()",dev_name,dir_name, + kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino,current->fs->root->d_inode->i_uid, + current->fs->root->d_inode->i_gid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + retval = -EPERM; + goto fs_out; + } +#endif /* ... filesystem driver... */ fstype = get_fs_type(type_page); if (!fstype) diff -urN linux/grkernsec/Config.in linux/grkernsec/Config.in --- linux/grkernsec/Config.in Wed Dec 31 16:00:00 1969 +++ linux/grkernsec/Config.in Sun Jun 3 06:22:34 2001 @@ -0,0 +1,75 @@ +if [ "$CONFIG_GRKERNSEC_PAX" != "y" ]; then +bool ' Openwall non-executable stack' CONFIG_GRKERNSEC_STACK +if [ "$CONFIG_GRKERNSEC_STACK" != "n" ]; then +bool ' Gcc trampoline support' CONFIG_GRKERNSEC_STACK_GCC +fi +fi +if [ "$CONFIG_GRKERNSEC_STACK" != "y" ]; then +bool ' PaX protection' CONFIG_GRKERNSEC_PAX +fi +bool ' Proc restrictions' CONFIG_GRKERNSEC_PROC +if [ "$CONFIG_GRKERNSEC_PROC" != "n" ]; then +bool ' Restrict to user only' CONFIG_GRKERNSEC_PROC_USER +if [ "$CONFIG_GRKERNSEC_PROC_USER" != "y" ]; then +bool ' Allow special group' CONFIG_GRKERNSEC_PROC_USERGROUP +if [ "$CONFIG_GRKERNSEC_PROC_USERGROUP" != "n" ]; then +int ' GID for special group' CONFIG_GRKERNSEC_PROC_GID 1001 +fi +fi +fi +bool ' Linking restrictions' CONFIG_GRKERNSEC_LINK +bool ' FIFO restrictions' CONFIG_GRKERNSEC_FIFO +bool ' Secure file descriptors' CONFIG_GRKERNSEC_FD +bool ' Exec process limiting' CONFIG_GRKERNSEC_EXECVE +bool ' Exec logging' CONFIG_GRKERNSEC_EXECLOG +bool ' Set*id logging' CONFIG_GRKERNSEC_SUID +bool ' Signal logging' CONFIG_GRKERNSEC_SIGNAL +bool ' Fork failure logging' CONFIG_GRKERNSEC_FORKFAIL +bool ' Time change logging' CONFIG_GRKERNSEC_TIME +bool ' BSD-style coredumps' CONFIG_GRKERNSEC_COREDUMP +bool ' Chroot jail restrictions' CONFIG_GRKERNSEC_CHROOT +if [ "$CONFIG_GRKERNSEC_CHROOT" != "n" ]; then +bool ' Log execs within jail' CONFIG_GRKERNSEC_CHROOT_EXECLOG +bool ' Capability restrictions' CONFIG_GRKERNSEC_CHROOT_CAPS +fi +bool ' Exec protection' CONFIG_GRKERNSEC_NOEXEC +if [ "$CONFIG_GRKERNSEC_NOEXEC" != "n" ]; then +bool ' Glibc protection' CONFIG_GRKERNSEC_NOEXEC_GLIBC +bool ' Capability restrictions' CONFIG_GRKERNSEC_NOEXEC_CAPS +int ' GID for protected processes:' CONFIG_GRKERNSEC_NOEXEC_GID 1006 +fi +bool ' Suid/sgid root executable restrictions' CONFIG_GRKERNSEC_SIDCAPS +bool ' Trusted path execution' CONFIG_GRKERNSEC_TPE +if [ "$CONFIG_GRKERNSEC_TPE" != "n" ]; then +bool ' Glibc protection' CONFIG_GRKERNSEC_TPE_GLIBC +bool ' Partially restrict non-root users' CONFIG_GRKERNSEC_TPE_ALL +int ' GID for untrusted users:' CONFIG_GRKERNSEC_TPE_GID 1005 +fi +bool ' Secure keymap loading' CONFIG_GRKERNSEC_KBMAP +bool ' Randomized PIDs' CONFIG_GRKERNSEC_RANDPID +bool ' Randomized IP IDs' CONFIG_GRKERNSEC_RANDID +bool ' Randomized TCP source ports' CONFIG_GRKERNSEC_RANDSRC +bool ' Enhanced network randomness' CONFIG_GRKERNSEC_RANDNET +bool ' Socket restrictions' CONFIG_GRKERNSEC_SOCKET +if [ "$CONFIG_GRKERNSEC_SOCKET" != "n" ]; then +bool ' Deny any sockets to group' CONFIG_GRKERNSEC_SOCKET_ALL +if [ "$CONFIG_GRKERNSEC_SOCKET_ALL" != "n" ]; then +int ' GID to deny all sockets for:' CONFIG_GRKERNSEC_ALL_GID 1004 +fi +bool ' Deny client sockets to group' CONFIG_GRKERNSEC_SOCKET_CLIENT +if [ "$CONFIG_GRKERNSEC_SOCKET_CLIENT" != "n" ]; then +int ' GID to deny client sockets for:' CONFIG_GRKERNSEC_CLIENT_GID 1003 +fi +bool ' Deny server sockets to group' CONFIG_GRKERNSEC_SOCKET_SERVER +if [ "$CONFIG_GRKERNSEC_SOCKET_SERVER" != "n" ]; then +int ' GID to deny server sockets for:' CONFIG_GRKERNSEC_SERVER_GID 1002 +fi +fi +bool ' Stealth networking' CONFIG_GRKERNSEC_STEALTH +if [ "$CONFIG_GRKERNSEC_STEALTH" != "n" ]; then +bool ' Do not send Connection Resets' CONFIG_GRKERNSEC_STEALTH_RST +bool ' Do not reply to UDP with ICMP unreachables' CONFIG_GRKERNSEC_STEALTH_UDP +bool ' Do not reply to ICMP requests' CONFIG_GRKERNSEC_STEALTH_ICMP +bool ' Do not reply to IGMP requests' CONFIG_GRKERNSEC_STEALTH_IGMP +bool ' Drop packets with illegitimate flags' CONFIG_GRKERNSEC_FLAGS +fi diff -urN linux/include/asm-i386/a.out.h linux/include/asm-i386/a.out.h --- linux/include/asm-i386/a.out.h Fri Jun 16 11:33:06 1995 +++ linux/include/asm-i386/a.out.h Sun Jun 3 06:22:34 2001 @@ -18,9 +18,11 @@ #define N_SYMSIZE(a) ((a).a_syms) #ifdef __KERNEL__ - +#ifdef CONFIG_GRKERNSEC_STACK +#define STACK_TOP ((current->flags & PF_STACKEXEC) ? TASK_SIZE - _STK_LIM : TASK_SIZE) +#else #define STACK_TOP TASK_SIZE - +#endif #endif #endif /* __A_OUT_GNU_H__ */ diff -urN linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- linux/include/asm-i386/pgtable.h Fri May 25 18:01:26 2001 +++ linux/include/asm-i386/pgtable.h Sun Jun 3 06:22:34 2001 @@ -180,9 +180,19 @@ #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) +#ifdef CONFIG_GRKERNSEC_PAX +#define PAGE_SHARED_EXEC __pgprot(_PAGE_PRESENT | _PAGE_RW |_PAGE_USER |_PAGE_ACCESSED) +#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) + +#define PAGE_SHARED_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED) +#define PAGE_COPY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) +#define PAGE_READONLY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) +#else #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#endif #define __PAGE_KERNEL \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) @@ -216,6 +226,15 @@ * This is the closest we can get.. */ #define __P000 PAGE_NONE +#ifdef CONFIG_GRKERNSEC_PAX +#define __P001 PAGE_READONLY_NOEXEC +#define __P010 PAGE_COPY_NOEXEC +#define __P011 PAGE_COPY_NOEXEC +#define __P100 PAGE_READONLY_EXEC +#define __P101 PAGE_READONLY_EXEC +#define __P110 PAGE_COPY_EXEC +#define __P111 PAGE_COPY_EXEC +#else #define __P001 PAGE_READONLY #define __P010 PAGE_COPY #define __P011 PAGE_COPY @@ -223,8 +242,18 @@ #define __P101 PAGE_READONLY #define __P110 PAGE_COPY #define __P111 PAGE_COPY +#endif #define __S000 PAGE_NONE +#ifdef CONFIG_GRKERNSEC_PAX +#define __S001 PAGE_READONLY_NOEXEC +#define __S010 PAGE_SHARED_NOEXEC +#define __S011 PAGE_SHARED_NOEXEC +#define __S100 PAGE_READONLY_EXEC +#define __S101 PAGE_READONLY_EXEC +#define __S110 PAGE_SHARED_EXEC +#define __S111 PAGE_SHARED_EXEC +#else #define __S001 PAGE_READONLY #define __S010 PAGE_SHARED #define __S011 PAGE_SHARED @@ -232,6 +261,7 @@ #define __S101 PAGE_READONLY #define __S110 PAGE_SHARED #define __S111 PAGE_SHARED +#endif /* * Define this if things work differently on an i386 and an i486: diff -urN linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h --- linux/include/asm-i386/processor.h Fri May 25 18:01:26 2001 +++ linux/include/asm-i386/processor.h Sun Jun 3 06:22:34 2001 @@ -259,12 +259,24 @@ * User space process size: 3GB (default). */ #define TASK_SIZE (PAGE_OFFSET) - +#ifdef CONFIG_GRKERNSEC_STACK +#define MAGIC_SIGRETURN (PAGE_OFFSET + 0xDE0000) +#define MAGIC_RT_SIGRETURN (PAGE_OFFSET + 0xDE0001) +#endif /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ +#ifdef CONFIG_GRKERNSEC_STACK +extern struct linux_binfmt elf_format; +#define TASK_UNMAPPED_BASE(size) ( \ + current->binfmt == &elf_format && \ + !(current->flags & PF_STACKEXEC) && \ + (size) < 0x00ef0000UL \ + ? 0x00110000UL \ + : TASK_SIZE / 3 ) +#else #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) - +#endif /* * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. */ @@ -355,6 +367,14 @@ unsigned long __cacheline_filler[5]; }; +#ifdef CONFIG_GRKERNSEC_PAX +struct pax_fault_info { + unsigned long eip; + unsigned long addresses[4]; + unsigned long count; +}; +#endif + struct thread_struct { unsigned long esp0; unsigned long eip; @@ -365,6 +385,11 @@ unsigned long debugreg[8]; /* %%db0-7 debug registers */ /* fault info */ unsigned long cr2, trap_no, error_code; +#ifdef CONFIG_GRKERNSEC_PAX +/* PaX fault info */ + struct pax_fault_info pax_faults; +#endif + /* floating point info */ union i387_union i387; /* virtual 86 mode info */ @@ -376,18 +401,36 @@ unsigned long io_bitmap[IO_BITMAP_SIZE+1]; }; +#ifdef CONFIG_GRKERNSEC_PAX #define INIT_THREAD { \ 0, \ 0, 0, 0, 0, \ { [0 ... 7] = 0 }, /* debugging registers */ \ 0, 0, 0, \ + {0, {0}, 0}, /* PaX fault info */ \ { { 0, }, }, /* 387 state */ \ 0,0,0,0,0,0, \ 0,{~0,} /* io permissions */ \ } +#else +#define INIT_THREAD { \ + 0, \ + 0, 0, 0, 0, \ + { [0 ... 7] = 0 }, /* debugging registers */ \ + 0, 0, 0, \ + { { 0, }, }, /* 387 state */ \ + 0,0,0,0,0,0, \ + 0,{~0,} /* io permissions */ \ +} +#endif +#ifdef CONFIG_GRKERNSEC_PAX +#define INIT_MMAP \ +{ &init_mm, 0, 0, NULL, PAGE_SHARED_EXEC, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } +#else #define INIT_MMAP \ { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } +#endif #define INIT_TSS { \ 0,0, /* back_link, __blh */ \ diff -urN linux/include/linux/a.out.h linux/include/linux/a.out.h --- linux/include/linux/a.out.h Fri May 25 18:01:26 2001 +++ linux/include/linux/a.out.h Sun Jun 3 06:22:34 2001 @@ -56,7 +56,9 @@ #define N_SET_FLAGS(exec, flags) \ ((exec).a_info = \ ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) - +#ifdef CONFIG_GRKERNSEC_STACK +#define F_STACKEXEC 1 +#endif /* Code indicating object file or impure executable. */ #define OMAGIC 0407 /* Code indicating pure executable. */ diff -urN linux/include/linux/binfmts.h linux/include/linux/binfmts.h --- linux/include/linux/binfmts.h Fri May 25 18:01:28 2001 +++ linux/include/linux/binfmts.h Sun Jun 3 06:22:34 2001 @@ -1,6 +1,7 @@ #ifndef _LINUX_BINFMTS_H #define _LINUX_BINFMTS_H +#include #include #include @@ -30,6 +31,11 @@ int argc, envc; char * filename; /* Name of binary */ unsigned long loader, exec; +#ifdef CONFIG_GRKERNSEC_FD + int priv_change; + int tweak_fd_mask; + struct file *tweak_fd_null; +#endif }; /* diff -urN linux/include/linux/capability.h linux/include/linux/capability.h --- linux/include/linux/capability.h Fri May 25 18:01:28 2001 +++ linux/include/linux/capability.h Sun Jun 3 06:22:34 2001 @@ -277,6 +277,15 @@ #define CAP_LEASE 28 +#ifdef CONFIG_LIDS +/* Allow to hide the proceed from the system */ +#define CAP_HIDDEN 29 + +/* Allow the process to KILL the init children */ +#define CAP_INIT_KILL 30 +#endif + + #ifdef __KERNEL__ /* * Bounding set diff -urN linux/include/linux/elf.h linux/include/linux/elf.h --- linux/include/linux/elf.h Fri May 25 18:03:14 2001 +++ linux/include/linux/elf.h Sun Jun 3 06:22:34 2001 @@ -83,7 +83,9 @@ * up with a final number. */ #define EM_ALPHA 0x9026 - +#ifdef CONFIG_GRKERNSEC_STACK +#define EF_STACKEXEC 1 +#endif /* * This is the old interim value for S/390 architecture */ diff -urN linux/include/linux/kernel.h linux/include/linux/kernel.h --- linux/include/linux/kernel.h Sun May 20 12:11:39 2001 +++ linux/include/linux/kernel.h Sun Jun 3 06:22:34 2001 @@ -59,8 +59,12 @@ extern long simple_strtol(const char *,char **,unsigned int); extern unsigned long long simple_strtoull(const char *,char **,unsigned int); extern long long simple_strtoll(const char *,char **,unsigned int); -extern int sprintf(char * buf, const char * fmt, ...); -extern int vsprintf(char *buf, const char *, va_list); +extern int sprintf(char * buf, const char * fmt, ...) + __attribute__ ((format (printf,2,3))); +extern int vsprintf(char *buf, const char *, va_list) + __attribute__ ((format (printf,2,0))); +extern int _vsnprintf(char *buf, int n, const char *, va_list) + __attribute__ ((format (printf,3,0))); extern int get_option(char **str, int *pint); extern char *get_options(char *str, int nints, int *ints); extern unsigned long long memparse(char *ptr, char **retptr); @@ -105,6 +109,23 @@ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3] +#define security_alert(normal_msg,flood_msg,args...) \ +({ \ + static unsigned long warning_time = 0, no_flood_yet = 0; \ + static spinlock_t security_alert_lock = SPIN_LOCK_UNLOCKED; \ + \ + spin_lock(&security_alert_lock); \ + if(!warning_time || jiffies - warning_time > 30 * HZ) { \ + warning_time = jiffies; no_flood_yet = 1; \ + printk(KERN_ALERT "GETREWTED ALERT: " normal_msg "\n", ## args); \ + } else if (no_flood_yet) { \ + warning_time = jiffies; no_flood_yet = 0; \ + printk(KERN_ALERT "GETREWTED ALERT: more " flood_msg \ + ", logging disabled for 30 seconds\n"); \ + } \ + \ + spin_unlock(&security_alert_lock); \ +}) #define HIPQUAD(addr) \ ((unsigned char *)&addr)[3], \ diff -urN linux/include/linux/lids.h linux/include/linux/lids.h --- linux/include/linux/lids.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/lids.h Sun Jun 3 06:33:46 2001 @@ -0,0 +1,114 @@ +#ifndef LIDS_H +#define LIDS_H + +#include +#include +#include +#include +#include + +#define LIDS_VERSION "1.0.9 for 2.4.5" + +#define LIDS_FLAGS_LIDS_ON 1 +#define LIDS_FLAGS_RELOAD_CONF 4 +#define LIDS_FLAGS_LIDS_LOCAL_ON 8 + +#define LIDS_MAX_DOMAIN 64 +/* + * ACL target. + */ + +#define LIDS_DENY 0 /* DENY ACCESS*/ +#define LIDS_READONLY 1 /* Read Only File */ +#define LIDS_APPEND 2 /* APPEND ONLY FILE */ +#define LIDS_WRITE 4 /* Protect Writing to device */ +#define LIDS_IGNORE 8 /* Ignore the protection */ +#define LIDS_CAP 16 /* acl type is capability */ + +/* + * Me ? Paranoiac !? + * + * The magic numbers are all around the encrypted password. + * They have a null byte to bother ASCIIZ functions. + */ + +#define LIDS_MAGIC_1 0x004e6748 +#define LIDS_MAGIC_2 0x68002d68 +#define LIDS_MAGIC_3 0xe68400c6 +#define LIDS_MAGIC_4 0xd94aac00 + +#define LIDS_FISSET(fs,f) ((fs & f) != 0) +#define LIDS_FISCLR(fs,f) (!(fs & f)) +#define LIDS_FSET(fs,f) (fs |= f) +#define LIDS_FCLR(fs,f) (fs &= ~f) + +typedef char passwd_t[64]; + +typedef struct lids_locks_s { + int magic1; + kernel_cap_t cap_bset; + int magic2; + lids_flags_t flags; + int magic3; + passwd_t passwd; + int magic4; +} lids_locks_t; + +struct secure_ino { + unsigned long int ino; /* the inode number */ + kdev_t dev; /* the dev number */ + int type; /* the file type */ +}; + +struct allowed_ino { + unsigned long int ino; /* the inode number */ + kdev_t dev; /* the dev number */ +}; +/* use in task struct to represent the acl */ +struct lids_acl { + struct lids_acl *next; + unsigned long int ino; + kdev_t dev; + int type; /* READ WRITE APPEND DENY */ + int inherit; /* the inherit level */ +}; + +/* lids_domain define the process's execute domain */ +struct lids_domain { + int counter; + struct dentry dentry[LIDS_MAX_DOMAIN]; +}; + +/* save all the system defined acl here */ +struct lids_sys_acl { + unsigned long int ino; /* the subject node number */ + unsigned long flags; /* capability flags */ + int cap_inherit[32]; /* inheritable array*/ + int forked; /* fork tags */ + struct lids_acl *lids_acl; /* object acl */ + struct lids_acl *lids_domain; + kdev_t dev; /* the subject dev number */ +}; + +/* FIXME: some more externals in kernel/signal.c and kernel/sysctl.c */ + +extern int lids_load; /* 1 = load ids protection , 0 = don't load */ +extern lids_flags_t lids_flags; /* 1 = load ids protection , 0 = don't load */ +extern int lids_local_on; +extern unsigned long lids_current; + +extern int lids_proc_locks_sysctl(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp, int conv, int op); +extern int lids_init(void); +extern struct lids_sys_acl * lids_search_acl(unsigned long int ino,kdev_t dev,unsigned long lids_curr); +extern int lids_check_base(struct dentry *base, int flag); +extern int lids_set_flags(struct lids_sys_acl *); +extern int lids_check_hidden_inode(unsigned long int ino,kdev_t dev); +extern int lids_local_off(void); +#ifdef CONFIG_LIDS_SA_THROUGH_NET +extern int lids_klids_init(void); +#endif +#ifdef CONFIG_LIDS_PORT_SCAN_DETECTOR +extern void lids_port_scanner_detector_init(void); +#endif + +#endif /* LIDS_H */ diff -urN linux/include/linux/lidsext.h linux/include/linux/lidsext.h --- linux/include/linux/lidsext.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/lidsext.h Sun Jun 3 06:34:33 2001 @@ -0,0 +1,172 @@ +#ifndef LIDSEXT_H +#define LIDSEXT_H + +#ifdef CONFIG_LIDS_DEBUG +#define LIDS_DEBUG +#endif + +#ifdef LIDS_DEBUG +#define LIDS_DBG(msg...) printk(KERN_DEBUG "LIDS." __FUNCTION__ ": " ##msg) +#else +#define LIDS_DBG(msg...) +#endif +extern void lids_cap_log(int ); +#define lids_get_current_dentry(dentry) \ + { \ + struct vm_area_struct * vma; \ + dentry = NULL; \ + if (current->mm) { \ + vma = current->mm->mmap; \ + while (vma) { \ + if ((vma->vm_flags & VM_EXECUTABLE) && \ + vma->vm_file) { \ + dentry=vma->vm_file->f_dentry; \ + break; \ + } \ + vma = vma->vm_next; \ + } \ + } \ + } + + +#define lids_info_params1 f_dentry->d_iname, \ + MAJOR(f_dentry->d_inode->i_dev), \ + MINOR(f_dentry->d_inode->i_dev), \ + f_dentry->d_inode->i_ino, \ + current->pid, \ + current->p_pptr->pid, \ + current->uid, \ + current->gid + +#define lids_info_params2 current->pid, \ + current->p_pptr->pid, \ + current->uid, \ + current->gid + +#ifdef CONFIG_LIDS_HANGUP +#define lids_hangup_console() \ +do{ \ + if(current->tty != NULL && !lids_first_time ) { \ + if (!test_bit(TTY_LIDS_NO_HANGUP,¤t->tty->flags) ) \ + tty_vhangup(current->tty); \ + } \ +}while(0) +#else +#define lids_hangup_console() do {} while (0) +#endif + + +#ifdef CONFIG_LIDS_SA_THROUGH_NET +#define lids_print(message, args...) sprintf(p, message , ## args) +#else +#define lids_print(message, args...) printk(KERN_ALERT message , ## args) +#endif + + +#define lids_make_alert(message, args...) \ +do{ \ + (tty_name(current->tty,buf)); \ + if (f_dentry && f_dentry->d_inode) { \ + if (current->tty) { \ + /* lids_print("LIDS: %s (%d %d inode %ld) pid %d user (%d/%d) on %s: " message "\n", \ + lids_info_params1, \ + buf, \ + ##args); */ \ + lids_print( "LIDS: %s (%d %d inode %ld) pid %d ppid %d user (%d/%d) on(%s) : " message "\n", \ + lids_info_params1 ,buf , \ + ## args); \ + } \ + else { \ + lids_print( "LIDS: %s (%d %d inode %ld) pid %d ppid %d user (%d/%d) on NULL tty: " message "\n", \ + lids_info_params1 , \ + ## args); \ + } \ + } \ + else { \ + if (current->tty) { \ + lids_print( "LIDS: (undetermined program) pid %d ppid %d user (%d/%d) on(%s): " message "\n", \ + lids_info_params2, buf , \ + ## args); \ + } \ + else { \ + lids_print( "LIDS: (undetermined program) pid %d ppid %d user (%d/%d) on NULL tty: " message "\n", \ + lids_info_params2 , \ + ## args); \ + } \ + } \ +}while(0) +extern void lids_send_message(char *msg,int len); + + +#ifdef CONFIG_LIDS_SA_THROUGH_NET +#define lids_log(message, args...) ({ \ + char *p; \ + p=(char *)kmalloc(2048,GFP_KERNEL); \ + lids_make_alert(message , ## args); \ + printk(KERN_ALERT "%s",p); \ + lids_send_message(p,strlen(p)); \ + }) +#else +#define lids_log(message, args...) lids_make_alert(message , ## args) +#endif + + +#ifdef CONFIG_LIDS_NO_FLOOD_LOG + +#define lids_security_alert(message, args...) \ +do{ \ + static unsigned long warning_time = 0, no_flood_yet = 0; \ + static spinlock_t lids_security_alert_lock = SPIN_LOCK_UNLOCKED; \ + struct dentry *f_dentry; \ + static char buf[64]; \ + \ + lids_get_current_dentry(f_dentry); \ + spin_lock(&lids_security_alert_lock); \ + \ +/* Make sure at least CONFIG_LIDS_TIMEOUT_AFTER_FLOOD passed since the last warning logged */ \ + if (!warning_time || jiffies - warning_time > CONFIG_LIDS_TIMEOUT_AFTER_FLOOD * HZ) { \ + warning_time = jiffies; no_flood_yet = 1; \ + lids_log(message , ##args); \ + } else if (no_flood_yet) { \ + warning_time = jiffies; no_flood_yet = 0; \ + lids_log("more " message \ + ",logging disabled for %i seconds" , \ + ## args , \ + CONFIG_LIDS_TIMEOUT_AFTER_FLOOD); \ + } \ + spin_unlock(&lids_security_alert_lock); \ + lids_hangup_console(); \ +}while(0) +#else /* CONFIG_LIDS_NO_FLOOD_LOG */ +#define lids_security_alert(message, args...) \ +do{ \ + struct dentry *f_dentry; \ + static spinlock_t lids_security_alert_lock = SPIN_LOCK_UNLOCKED; \ + static char buf[64]; \ + \ + spin_lock(&lids_security_alert_lock); \ + lids_get_current_dentry(f_dentry); \ + lids_log(message , ## args); \ + spin_unlock(&lids_security_alert_lock); \ + lids_hangup_console(); \ +}while(0) +#endif /* CONFIG_LIDS_NO_FLOOD_LOG */ + +#ifdef CONFIG_LIDS_ALLOW_SWITCH +#define lids_local_load ( lids_local_on || (!lids_local_off()) ) +#else +#define lids_local_load 1 +#endif /* CONFIG_LIDS_ALLOW_SWITCH */ + +typedef int lids_flags_t; + + +extern int lids_local_off(void); +extern int lids_reload_conf; +extern int lids_load; +extern int lids_local_on; +extern int lids_local_pid; +extern int lids_first_time; +extern lids_flags_t lids_flags; + +#endif /* LIDSEXT_H */ diff -urN linux/include/linux/mm.h linux/include/linux/mm.h --- linux/include/linux/mm.h Fri May 25 18:01:28 2001 +++ linux/include/linux/mm.h Sun Jun 3 06:22:34 2001 @@ -97,7 +97,11 @@ #define VM_DONTEXPAND 0x00040000 /* Cannot expand with mremap() */ #define VM_RESERVED 0x00080000 /* Don't unmap it from swap_out */ +#ifdef CONFIG_GRKERNSEC_PAX +#define VM_STACK_FLAGS 0x00000133 +#else #define VM_STACK_FLAGS 0x00000177 +#endif #define VM_READHINTMASK (VM_SEQ_READ | VM_RAND_READ) #define VM_ClearReadHint(v) (v)->vm_flags &= ~VM_READHINTMASK diff -urN linux/include/linux/netfilter.h linux/include/linux/netfilter.h --- linux/include/linux/netfilter.h Fri May 25 18:03:37 2001 +++ linux/include/linux/netfilter.h Sun Jun 3 06:22:34 2001 @@ -41,6 +41,13 @@ const struct net_device *out, int (*okfn)(struct sk_buff *)); +/* Simple drop the packet fn for NF_HOOK(). */ +extern inline int nf_drop_okfn(struct sk_buff *skb) +{ + kfree_skb(skb); + return 0; +} + struct nf_hook_ops { struct list_head list; diff -urN linux/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h --- linux/include/linux/netfilter_ipv4/ip_conntrack.h Fri Apr 27 14:15:01 2001 +++ linux/include/linux/netfilter_ipv4/ip_conntrack.h Sun Jun 3 06:22:34 2001 @@ -83,6 +83,10 @@ #include +#if defined(CONFIG_IP_NF_IRC) || defined(CONFIG_IP_NF_IRC_MODULE) +#include +#endif + struct ip_conntrack { /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, @@ -121,6 +125,7 @@ union { struct ip_ct_ftp ct_ftp_info; + struct ip_ct_irc ct_irc_info; } help; #ifdef CONFIG_IP_NF_NAT_NEEDED diff -urN linux/include/linux/netfilter_ipv4/ip_conntrack_irc.h linux/include/linux/netfilter_ipv4/ip_conntrack_irc.h --- linux/include/linux/netfilter_ipv4/ip_conntrack_irc.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ip_conntrack_irc.h Sun Jun 3 06:22:34 2001 @@ -0,0 +1,47 @@ +/* IRC extension for IP connection tracking. + * (C) 2000 by Harald Welte + * based on RR's ip_conntrack_ftp.h + * + * ip_conntrack_irc.h,v 1.6 2000/11/07 18:26:42 laforge Exp + * + * 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. + * + * + */ +#ifndef _IP_CONNTRACK_IRC_H +#define _IP_CONNTRACK_IRC_H + +#ifndef __KERNEL__ +#error Only in kernel. +#endif + +#include + +#define IP_CONNTR_IRC 2 + +struct dccproto { + char* match; + int matchlen; +}; + +/* Protects irc part of conntracks */ +DECLARE_LOCK_EXTERN(ip_irc_lock); + +/* We record seq number and length of irc ip/port text here: all in + host order. */ +struct ip_ct_irc +{ + /* This tells NAT that this is an IRC connection */ + int is_irc; + /* sequence number where address part of DCC command begins */ + u_int32_t seq; + /* 0 means not found yet */ + u_int32_t len; + /* Port that was to be used */ + u_int16_t port; +}; + +#endif /* _IP_CONNTRACK_IRC_H */ diff -urN linux/include/linux/netfilter_ipv4/ip_nat.h linux/include/linux/netfilter_ipv4/ip_nat.h --- linux/include/linux/netfilter_ipv4/ip_nat.h Wed Apr 25 15:00:28 2001 +++ linux/include/linux/netfilter_ipv4/ip_nat.h Sun Jun 3 06:22:34 2001 @@ -111,10 +111,13 @@ struct ip_nat_seq seq[IP_CT_DIR_MAX]; }; -/* Set up the info structure to map into this range. */ +/* Set up the info structure to map into this range. Returns verdict. */ extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack, const struct ip_nat_multi_range *mr, - unsigned int hooknum); + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct sk_buff *skb); /* Is this tuple already taken? (not by us)*/ extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, diff -urN linux/include/linux/netfilter_ipv4/ipt_iplimit.h linux/include/linux/netfilter_ipv4/ipt_iplimit.h --- linux/include/linux/netfilter_ipv4/ipt_iplimit.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ipt_iplimit.h Sun Jun 3 06:22:34 2001 @@ -0,0 +1,12 @@ +#ifndef _IPT_IPLIMIT_H +#define _IPT_IPLIMIT_H + +struct ipt_iplimit_data; + +struct ipt_iplimit_info { + int limit; + int inverse; + u_int32_t mask; + struct ipt_iplimit_data *data; +}; +#endif /* _IPT_IPLIMIT_H */ diff -urN linux/include/linux/netfilter_ipv4/ipt_ipv4options.h linux/include/linux/netfilter_ipv4/ipt_ipv4options.h --- linux/include/linux/netfilter_ipv4/ipt_ipv4options.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ipt_ipv4options.h Sun Jun 3 06:22:34 2001 @@ -0,0 +1,17 @@ +#ifndef __ipt_ipv4options_h_included__ +#define __ipt_ipv4options_h_included__ + +#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */ +#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */ +#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */ +#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */ +#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10 +#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */ +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40 + +struct ipt_ipv4options_info { + u_int8_t options; +}; + + +#endif /* __ipt_ipv4options_h_included__ */ diff -urN linux/include/linux/netfilter_ipv4/ipt_length.h linux/include/linux/netfilter_ipv4/ipt_length.h --- linux/include/linux/netfilter_ipv4/ipt_length.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ipt_length.h Sun Jun 3 06:22:34 2001 @@ -0,0 +1,9 @@ +#ifndef _IPT_LENGTH_H +#define _IPT_LENGTH_H + +struct ipt_length_info { + u_int16_t min, max; + u_int8_t invert; +}; + +#endif /*_IPT_LENGTH_H*/ diff -urN linux/include/linux/netfilter_ipv4/ipt_psd.h linux/include/linux/netfilter_ipv4/ipt_psd.h --- linux/include/linux/netfilter_ipv4/ipt_psd.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ipt_psd.h Sun Jun 3 06:22:34 2001 @@ -0,0 +1,40 @@ +#ifndef _IPT_PSD_H +#define _IPT_PSD_H + +#include +#include + +/* + * High port numbers have a lower weight to reduce the frequency of false + * positives, such as from passive mode FTP transfers. + */ +#define PORT_WEIGHT_PRIV 3 +#define PORT_WEIGHT_HIGH 1 + +/* + * Port scan detection thresholds: at least COUNT ports need to be scanned + * from the same source, with no longer than DELAY ticks between ports. + */ +#define SCAN_MIN_COUNT 7 +#define SCAN_MAX_COUNT (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV) +#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT +#define SCAN_DELAY_THRESHOLD (HZ * 3) + +/* + * Keep track of up to LIST_SIZE source addresses, using a hash table of + * HASH_SIZE entries for faster lookups, but limiting hash collisions to + * HASH_MAX source addresses per the same hash value. + */ +#define LIST_SIZE 0x100 +#define HASH_LOG 9 +#define HASH_SIZE (1 << HASH_LOG) +#define HASH_MAX 0x10 + +struct ipt_psd_info { + unsigned int weight_threshold; + unsigned int delay_threshold; + unsigned short lo_ports_weight; + unsigned short hi_ports_weight; +}; + +#endif /*_IPT_PSD_H*/ diff -urN linux/include/linux/netfilter_ipv4/ipt_string.h linux/include/linux/netfilter_ipv4/ipt_string.h --- linux/include/linux/netfilter_ipv4/ipt_string.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ipt_string.h Sun Jun 3 06:22:34 2001 @@ -0,0 +1,21 @@ +#ifndef _IPT_STRING_H +#define _IPT_STRING_H + +/* *** PERFORMANCE TWEAK *** + * Packet size and search string threshold, + * above which sublinear searches is used. */ +#define IPT_STRING_HAYSTACK_THRESH 100 +#define IPT_STRING_NEEDLE_THRESH 20 + +#define BM_MAX_NLEN 256 +#define BM_MAX_HLEN 1024 + +typedef char *(*proc_ipt_search) (char *, char *, int, int); + +struct ipt_string_info { + char string[BM_MAX_NLEN]; + u_int16_t invert; + u_int16_t len; +}; + +#endif /* _IPT_STRING_H */ diff -urN linux/include/linux/netfilter_ipv4/ipt_time.h linux/include/linux/netfilter_ipv4/ipt_time.h --- linux/include/linux/netfilter_ipv4/ipt_time.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ipt_time.h Sun Jun 3 06:22:34 2001 @@ -0,0 +1,13 @@ + +#ifndef __ipt_time_h_included__ +#define __ipt_time_h_included__ + + +struct ipt_time_info { + u_int8_t days_match; /* 1 bit per day. -SMTWTFS */ + u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */ + u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */ +}; + + +#endif /* __ipt_time_h_included__ */ diff -urN linux/include/linux/netfilter_ipv4.h linux/include/linux/netfilter_ipv4.h --- linux/include/linux/netfilter_ipv4.h Fri May 25 18:02:12 2001 +++ linux/include/linux/netfilter_ipv4.h Sun Jun 3 06:22:34 2001 @@ -47,7 +47,9 @@ #define NF_IP_LOCAL_OUT 3 /* Packets about to hit the wire. */ #define NF_IP_POST_ROUTING 4 -#define NF_IP_NUMHOOKS 5 +/* `Interesting' packets we're about to drop: nfmark holds nf_ip_dropreason */ +#define NF_IP_DROPPING 5 +#define NF_IP_NUMHOOKS 6 enum nf_ip_hook_priorities { NF_IP_PRI_FIRST = INT_MIN, @@ -57,6 +59,18 @@ NF_IP_PRI_FILTER = 0, NF_IP_PRI_NAT_SRC = 100, NF_IP_PRI_LAST = INT_MAX, +}; + +enum nf_ip_dropreason { + NF_IP_DROP_NSA_WATCHING, /* `They' didn't like the packet */ + NF_IP_DROP_INVALID_REDIRECT, /* Invalid redirect */ + NF_IP_DROP_IGNORES_REDIRECT, /* Not heeding redirects */ + NF_IP_DROP_MARTIAN_SOURCE, /* Unexpected source address */ + NF_IP_DROP_MARTIAN_DESTINATION, /* Unexpected destination address */ + NF_IP_DROP_NAT_UNTRACKED, /* NAT dropped untracked packet */ + NF_IP_DROP_NAT_NO_UNIQUE_TUPLE, /* NAT couldn't map connection */ + NF_IP_DROP_NAT_FTP_ERROR, /* NAT on malformed FTP packet */ + NF_IP_DROP_MAX }; #ifdef CONFIG_NETFILTER_DEBUG diff -urN linux/include/linux/rmd160.h linux/include/linux/rmd160.h --- linux/include/linux/rmd160.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/rmd160.h Sun Jun 3 06:22:34 2001 @@ -0,0 +1,138 @@ +/********************************************************************\ + * + * FILE: rmd160.h + * + * CONTENTS: Header file for a sample C-implementation of the + * RIPEMD-160 hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * +\********************************************************************/ + +#ifndef RMD160H /* make sure this file is read only once */ +#define RMD160H + +#define RMDsize 160 + +/********************************************************************/ + +/* typedef 8 and 32 bit types, resp. */ +/* adapt these, if necessary, + for your operating system and compiler */ +typedef u8 byte; +typedef u32 dword; + + +/********************************************************************/ + +/* macro definitions */ + +/* collect four bytes into one word: */ +#define BYTES_TO_DWORD(strptr) \ + (((dword) *((strptr)+3) << 24) | \ + ((dword) *((strptr)+2) << 16) | \ + ((dword) *((strptr)+1) << 8) | \ + ((dword) *(strptr))) + +/* ROL(x, n) cyclically rotates x over n bits to the left */ +/* x must be of an unsigned 32 bits type and 0 <= n < 32. */ +#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* the five basic functions F(), G() and H() */ +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z) ((x) ^ ((y) | ~(z))) + +/* the ten basic operations FF() through III() */ +#define FF(a, b, c, d, e, x, s) {\ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define GG(a, b, c, d, e, x, s) {\ + (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define HH(a, b, c, d, e, x, s) {\ + (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define II(a, b, c, d, e, x, s) {\ + (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define JJ(a, b, c, d, e, x, s) {\ + (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define FFF(a, b, c, d, e, x, s) {\ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define GGG(a, b, c, d, e, x, s) {\ + (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define HHH(a, b, c, d, e, x, s) {\ + (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define III(a, b, c, d, e, x, s) {\ + (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define JJJ(a, b, c, d, e, x, s) {\ + (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } + +/********************************************************************/ + +/* function prototypes */ + +void MDinit(dword *MDbuf); +/* + * initializes MDbuffer to "magic constants" + */ + +void compress(dword *MDbuf, dword *X); +/* + * the compression function. + * transforms MDbuf using message bytes X[0] through X[15] + */ + +void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen); +/* + * puts bytes from strptr into X and pad out; appends length + * and finally, compresses the last block(s) + * note: length in bits == 8 * (lswlen + 2^32 mswlen). + * note: there are (lswlen mod 64) bytes left in strptr. + */ + +void RMD(byte *message,byte *hashcode); +/* + * Return hash in hascode variable. + * Need RMDSize/8 bytes. + */ + +#endif /* RMD160H */ + +/*********************** end of file rmd160.h ***********************/ + diff -urN linux/include/linux/sched.h linux/include/linux/sched.h --- linux/include/linux/sched.h Fri May 25 18:01:28 2001 +++ linux/include/linux/sched.h Sun Jun 3 06:22:34 2001 @@ -26,7 +26,9 @@ #include #include #include - +#ifdef CONFIG_LIDS +#include +#endif /* * cloning flags: */ @@ -398,6 +400,17 @@ u32 self_exec_id; /* Protection of (de-)allocation: mm, files, fs, tty */ spinlock_t alloc_lock; +#ifdef CONFIG_LIDS + /* LIDS refrence box */ + struct lids_sys_acl *lids_sys_acl; + unsigned long lids_cap; +#ifdef CONFIG_LIDS_RELOAD_CONF + unsigned long lids_current; + unsigned long lids_ino; + kdev_t lids_dev; +#endif +#endif + }; /* @@ -423,8 +436,17 @@ #define PT_PTRACED 0x00000001 #define PT_TRACESYS 0x00000002 #define PT_DTRACE 0x00000004 /* delayed trace (used on m68k, i386) */ +#ifdef CONFIG_GRKERNSEC_STACK +#define PF_STACKEXEC 0x01000000 +#endif #define PT_TRACESYSGOOD 0x00000008 +#ifdef CONFIG_GRKERNSEC_PAX +/* PaX: for handling DTLB trashing */ +#define PT_PAX_TRACE 0x00000010 +#define PT_PAX_KEEPTF 0x00000020 +#define PT_PAX_OLDTF 0x00000040 +#endif /* * Limit the stack by to some sane default: root can always * increase this limit if needed.. 8MB seems reasonable. @@ -696,7 +718,19 @@ static inline int capable(int cap) { #if 1 /* ok now */ +#ifdef CONFIG_LIDS + + /* if this proceed has the capability or its effecive + * has or it is in the enviroment of lids switch off + * FIXME, the flag may be combined with cap_effective*/ + + if((cap_raised(current->lids_cap,cap) || + (cap_raised(current->cap_effective, cap)) || + (((current->uid==0)&&(current->euid==0)&&(current->fsuid==0)) && + (!(lids_load && lids_local_load))))) +#else if (cap_raised(current->cap_effective, cap)) +#endif #else if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0) #endif @@ -704,6 +738,11 @@ current->flags |= PF_SUPERPRIV; return 1; } +#ifdef CONFIG_LIDS + /* FIXME, add more detail for auditing */ + LIDS_DBG(":lids_cap =%lx, cap_effective=%x,cap=%d,lids_load=%d,lids_local_load=%d\n",current->lids_cap, current->cap_effective,cap,lids_load,lids_local_load); + lids_cap_log(cap); +#endif return 0; } diff -urN linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- linux/include/linux/sysctl.h Fri May 25 18:01:27 2001 +++ linux/include/linux/sysctl.h Sun Jun 3 06:22:34 2001 @@ -62,6 +62,9 @@ CTL_DEBUG=6, /* Debugging */ CTL_DEV=7, /* Devices */ CTL_BUS=8 /* Buses */ +#ifdef CONFIG_LIDS + ,CTL_LIDS=9 /* LIDS */ +#endif }; /* CTL_BUS names: */ @@ -545,6 +548,13 @@ DEV_RAID=4, DEV_MAC_HID=5 }; + +#ifdef CONFIG_LIDS +/* CTL_LIDS names: */ +enum { + LIDS_LOCKS=1, +}; +#endif /* /proc/sys/dev/cdrom */ enum { diff -urN linux/include/linux/tty.h linux/include/linux/tty.h --- linux/include/linux/tty.h Fri May 25 18:01:28 2001 +++ linux/include/linux/tty.h Sun Jun 3 06:22:35 2001 @@ -335,6 +335,9 @@ #define TTY_HW_COOK_IN 15 #define TTY_PTY_LOCK 16 #define TTY_NO_WRITE_SPLIT 17 +#ifdef CONFIG_LIDS +#define TTY_LIDS_NO_HANGUP 18 +#endif #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) diff -urN linux/include/net/inetpeer.h linux/include/net/inetpeer.h --- linux/include/net/inetpeer.h Fri May 25 18:01:28 2001 +++ linux/include/net/inetpeer.h Sun Jun 3 06:22:35 2001 @@ -14,6 +14,9 @@ #include #include #include +#ifdef CONFIG_GRKERNSEC_RANDID +#include +#endif struct inet_peer { @@ -24,7 +27,9 @@ * referenced entries */ __u32 v4daddr; /* peer's address */ __u16 avl_height; +#ifndef CONFIG_GRKERNSEC_RANDID __u16 ip_id_count; /* IP ID for the next packet */ +#endif __u32 tcp_ts; unsigned long tcp_ts_stamp; }; @@ -56,9 +61,17 @@ extern inline __u16 inet_getid(struct inet_peer *p) { __u16 id; +#ifdef CONFIG_GRKERNSEC_RANDID + __u16 tmpid; +#endif spin_lock_bh(&inet_peer_idlock); +#ifdef CONFIG_GRKERNSEC_RANDID + get_random_bytes(&tmpid,sizeof(__u16)); + id = htons(tmpid); +#else id = p->ip_id_count++; +#endif spin_unlock_bh(&inet_peer_idlock); return id; } diff -urN linux/include/net/ip.h linux/include/net/ip.h --- linux/include/net/ip.h Fri May 25 18:03:37 2001 +++ linux/include/net/ip.h Sun Jun 3 06:22:35 2001 @@ -31,6 +31,9 @@ #include #include #include +#ifdef CONFIG_GRKERNSEC_RANDID +#include +#endif #ifndef _SNMP_H #include @@ -190,13 +193,24 @@ static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk) { +#ifdef CONFIG_GRKERNSEC_RANDID + __u16 tmpid; +#endif if (iph->frag_off&__constant_htons(IP_DF)) { /* This is only to work around buggy Windows95/2000 * VJ compression implementations. If the ID field * does not change, they drop every other packet in * a TCP stream using header compression. */ +#ifdef CONFIG_GRKERNSEC_RANDID + if(sk && sk->daddr){ + get_random_bytes(&tmpid,sizeof(__u16)); + iph->id = htons(tmpid); + } else + iph->id = 0; +#else iph->id = ((sk && sk->daddr) ? htons(sk->protinfo.af_inet.id++) : 0); +#endif } else __ip_select_ident(iph, dst); } diff -urN linux/init/main.c linux/init/main.c --- linux/init/main.c Tue May 22 09:35:42 2001 +++ linux/init/main.c Sun Jun 3 06:22:35 2001 @@ -37,6 +37,10 @@ #include #endif +#ifdef CONFIG_LIDS +#include +#endif + #ifdef CONFIG_PCI #include #endif @@ -57,6 +61,10 @@ #include #endif +#ifdef CONFIG_LIDS +static int __init lids_setup(char *str); +#endif + #ifdef CONFIG_ISAPNP #include #endif @@ -127,6 +135,9 @@ char *execute_command; char root_device_name[64]; +#ifdef CONFIG_LIDS +int _lids_load = 1; +#endif static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; @@ -303,6 +314,20 @@ __setup("root=", root_dev_setup); +#ifdef CONFIG_LIDS + +/* + * lids_setup , read lids info from the kernel. + */ +static int __init lids_setup(char *str) +{ + if(strncmp(str,"0",1) == 0) + _lids_load = 0; + return 0; +} + +__setup("security=",lids_setup); +#endif static int __init checksetup(char *line) { struct kernel_param *p; @@ -757,6 +782,21 @@ } } #endif + +#ifdef CONFIG_LIDS + /* init the ids file system */ + lids_load=_lids_load; + lids_local_on=1; + lids_flags=(lids_load ? LIDS_FLAGS_LIDS_ON : 0) | LIDS_FLAGS_LIDS_LOCAL_ON; + printk("Linux Intrusion Detection System %s %s \n",LIDS_VERSION,lids_load==1?"starts":"doesn't start"); + if(lids_load) { +#ifdef CONFIG_LIDS_SA_THROUGH_NET + lids_klids_init(); +#endif + lids_init(); + } +#endif + } static int init(void * unused) diff -urN linux/kernel/Config.in linux/kernel/Config.in --- linux/kernel/Config.in Wed Dec 31 16:00:00 1969 +++ linux/kernel/Config.in Sun Jun 3 06:39:48 2001 @@ -0,0 +1,54 @@ +# +# Config.in for LIDS +# + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +if [ "$CONFIG_SYSCTL" = "y" ]; then + mainmenu_option next_comment + comment 'Linux Intrusion Detection System' + bool 'Linux Intrusion Detection System support (EXPERIMENTAL)' CONFIG_LIDS + if [ "$CONFIG_LIDS" != "n" ]; then + + comment 'LIDS features' + int ' Maximum protected objects to manage' CONFIG_LIDS_MAX_INODE 1024 + int ' Maximum ACL subjects to manage' CONFIG_LIDS_MAX_SACL 1024 + int ' Maximum ACL objects to manage' CONFIG_LIDS_MAX_OACL 1024 + int ' Maximum protected proceeds' CONFIG_LIDS_MAX_PROTECTED_PID 1024 + bool ' Hang up console when raising a security alert' CONFIG_LIDS_HANGUP + bool ' Security alert when execing unprotected programs before sealing LIDS' CONFIG_LIDS_SA_EXEC_UP + if [ "$CONFIG_LIDS_SA_EXEC_UP" = "y" ]; then + bool ' Do not execute unprotected programs before sealing LIDS' CONFIG_LIDS_NO_EXEC_UP + fi + bool ' Try not to flood logs' CONFIG_LIDS_NO_FLOOD_LOG + if [ "$CONFIG_LIDS_NO_FLOOD_LOG" = "y" ]; then + int ' Authorised time between two identic logs (seconds)' CONFIG_LIDS_TIMEOUT_AFTER_FLOOD 60 + fi + bool ' Allow switching LIDS protections' CONFIG_LIDS_ALLOW_SWITCH + if [ "$CONFIG_LIDS_ALLOW_SWITCH" = "y" ]; then + bool ' Restrict mode switching to specified terminals' CONFIG_LIDS_RESTRICT_MODE_SWITCH + if [ "$CONFIG_LIDS_RESTRICT_MODE_SWITCH" = "y" ]; then + bool ' Allow mode switching from a Linux Console' CONFIG_LIDS_MODE_SWITCH_CONSOLE + bool ' Allow mode switching from a serial Console' CONFIG_LIDS_MODE_SWITCH_SERIAL + bool ' Allow mode switching from a PTY' CONFIG_LIDS_MODE_SWITCH_PTY + fi + int ' Number of attempts to submit password' CONFIG_LIDS_MAX_TRY 3 + int ' Time to wait after a fail (seconds)' CONFIG_LIDS_TTW_FAIL 3 + bool ' Allow any program to switch LIDS protections' CONFIG_LIDS_ALLOW_ANY_PROG_SWITCH + bool ' Allow reloading config. file' CONFIG_LIDS_RELOAD_CONF + fi + bool ' Port Scanner Detector in kernel' CONFIG_LIDS_PORT_SCAN_DETECTOR + + bool ' Send security alerts through network' CONFIG_LIDS_SA_THROUGH_NET + if [ "$CONFIG_LIDS_SA_THROUGH_NET" = "y" ]; then + bool ' Hide klids kernel thread' CONFIG_LIDS_HIDE_KLIDS + int ' Number of connection tries before giving up' CONFIG_LIDS_NET_MAX_TRIES 3 + int ' Sleep time after a failed connection' CONFIG_LIDS_NET_TIMEOUT 30 + int ' Message queue size' CONFIG_LIDS_MSGQUEUE_SIZE 16 + define_bool CONFIG_LIDS_MAIL_SCRIPT y + bool ' Use generic mailer pseudo-script' CONFIG_LIDS_MAIL_SCRIPT + fi + bool ' LIDS Debug ' CONFIG_LIDS_DEBUG + fi + endmenu +fi +fi diff -urN linux/kernel/Makefile linux/kernel/Makefile --- linux/kernel/Makefile Fri Dec 29 14:07:24 2000 +++ linux/kernel/Makefile Sun Jun 3 06:22:35 2001 @@ -19,6 +19,8 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_LIDS) += lids.o rmd160.o +obj-$(CONFIG_LIDS_SA_THROUGH_NET) += klids.o lids_net.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -urN linux/kernel/exit.c linux/kernel/exit.c --- linux/kernel/exit.c Fri May 4 14:44:06 2001 +++ linux/kernel/exit.c Sun Jun 3 06:22:35 2001 @@ -18,6 +18,9 @@ #include #include +#ifdef CONFIG_LIDS +#include +#endif extern void sem_exit (void); extern struct task_struct *child_reaper; @@ -430,6 +433,15 @@ panic("Attempted to kill the idle task!"); if (tsk->pid == 1) panic("Attempted to kill init!"); + +#ifdef CONFIG_LIDS + if ((!lids_local_on) && (lids_local_pid == tsk->pid)) { + lids_local_on=1; + LIDS_FCLR(lids_flags,LIDS_FLAGS_LIDS_LOCAL_ON); /* should not be necessary */ + lids_security_alert("LIDS locally switched off after the termination of process %i",(int)tsk->pid); + } +#endif + tsk->flags |= PF_EXITING; del_timer_sync(&tsk->real_timer); @@ -441,6 +453,9 @@ lock_kernel(); sem_exit(); +#ifdef CONFIG_LIDS + exit_lids(tsk); +#endif __exit_files(tsk); __exit_fs(tsk); exit_sighand(tsk); diff -urN linux/kernel/fork.c linux/kernel/fork.c --- linux/kernel/fork.c Mon Apr 30 22:23:29 2001 +++ linux/kernel/fork.c Sun Jun 3 06:22:35 2001 @@ -18,11 +18,22 @@ #include #include #include +#ifdef CONFIG_GRKERNSEC_RANDPID +#include +#endif #include #include #include #include +#ifdef CONFIG_LIDS +#include +#endif + +#ifdef CONFIG_GRKERNSEC_RANDPID +extern struct entropy_store *random_state; +extern struct entropy_store *sec_random_state; +#endif /* The idle threads do not count.. */ int nr_threads; @@ -81,7 +92,9 @@ static int get_pid(unsigned long flags) { +#ifndef CONFIG_GRKERNSEC_RANDPID static int next_safe = PID_MAX; +#endif struct task_struct *p; if (flags & CLONE_PID) @@ -89,31 +102,54 @@ spin_lock(&lastpid_lock); if((++last_pid) & 0xffff8000) { +#ifndef CONFIG_GRKERNSEC_RANDPID last_pid = 300; /* Skip daemons etc. */ +#endif goto inside; } +#ifndef CONFIG_GRKERNSEC_RANDPID if(last_pid >= next_safe) { +#else + if(last_pid > 1) { +#endif inside: +#ifndef CONFIG_GRKERNSEC_RANDPID next_safe = PID_MAX; +#endif read_lock(&tasklist_lock); repeat: +#ifdef CONFIG_GRKERNSEC_RANDPID + if((random_state) || (sec_random_state)){ + do { + get_random_bytes(&last_pid, sizeof(last_pid)); + last_pid %= PID_MAX; + if(last_pid < 0) + last_pid-=(2 * last_pid); + } while (last_pid < 1); + } else + last_pid = 1+((xtime.tv_usec * total_forks) % PID_MAX); +#endif for_each_task(p) { if(p->pid == last_pid || p->pgrp == last_pid || p->session == last_pid) { +#ifndef CONFIG_GRKERNSEC_RANDPID if(++last_pid >= next_safe) { if(last_pid & 0xffff8000) last_pid = 300; next_safe = PID_MAX; } +#endif goto repeat; } +#ifndef CONFIG_GRKERNSEC_RANDPID if(p->pid > last_pid && next_safe > p->pid) next_safe = p->pid; if(p->pgrp > last_pid && next_safe > p->pgrp) next_safe = p->pgrp; if(p->session > last_pid && next_safe > p->session) next_safe = p->session; +#endif } read_unlock(&tasklist_lock); } @@ -532,6 +568,61 @@ return 0; } +#ifdef CONFIG_LIDS +static inline int copy_lids_sys_acl(struct task_struct * tsk) +{ + struct task_struct * parent = tsk->p_pptr; + + tsk->lids_sys_acl = kmalloc(sizeof(struct lids_sys_acl), GFP_KERNEL); + if (!tsk->lids_sys_acl) + return -1; + tsk->lids_sys_acl->flags = 0; + memset(tsk->lids_sys_acl->cap_inherit,'\0',32*(sizeof(int))); + + tsk->lids_sys_acl->lids_acl = NULL; + tsk->lids_sys_acl->lids_domain = NULL; + tsk->lids_sys_acl->ino = 0; + tsk->lids_sys_acl->dev = 0; + + /* copy ddthe struct from its parent */ + if(parent->lids_sys_acl) { + struct lids_acl *p_acl,*this_acl, *last_acl; + memcpy(tsk->lids_sys_acl,parent->lids_sys_acl, sizeof(struct lids_sys_acl)); + tsk->lids_sys_acl->forked = 1; /* FIXME: do you need this ? */ + + /* 1 . copy lids_acl */ + p_acl = parent->lids_sys_acl->lids_acl; + last_acl = NULL; + while( p_acl ) { + this_acl = kmalloc(sizeof(struct lids_acl),GFP_KERNEL); + if(!this_acl) return -1; + memcpy(this_acl,p_acl,sizeof(struct lids_acl)); + this_acl->next = last_acl; + last_acl = this_acl; + p_acl = p_acl->next; + } + tsk->lids_sys_acl->lids_acl = last_acl; + + /* 2. copy lids_domain + p_acl = parent->lids_sys_acl->lids_domain; + last_acl = NULL; + while( p_acl ) { + this_acl = kmalloc(sizeof(struct lids_acl),GFP_KERNEL); + if(!this_acl) return -1; + memcpy(this_acl,p_acl,sizeof(struct lids_acl)); + this_acl->next = last_acl; + last_acl = this_acl; + p_acl = p_acl->next; + } + tsk->lids_sys_acl->lids_domain = last_acl; + */ + LIDS_DBG("*********copy_lids_sys_acl: pid %d,ppid %d, orig=%x,%x\n",tsk->pid,parent->pid,parent->lids_sys_acl->flags,tsk->lids_sys_acl->flags); + } + return 0; +} +#endif + + static inline void copy_flags(unsigned long clone_flags, struct task_struct *p) { unsigned long new_flags = p->flags; @@ -650,6 +741,10 @@ goto bad_fork_cleanup_fs; if (copy_mm(clone_flags, p)) goto bad_fork_cleanup_sighand; +#ifdef CONFIG_LIDS + if(copy_lids_sys_acl(p)) + goto bad_fork_cleanup_sighand; +#endif retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); if (retval) goto bad_fork_cleanup_mm; @@ -723,6 +818,12 @@ free_uid(p->user); bad_fork_free: free_task_struct(p); +#ifdef CONFIG_GRKERNSEC_FORKFAIL + security_alert("failed fork with errno %d by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), " + "UID (%d), EUID (%d)","failed forks",retval,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif goto fork_out; } diff -urN linux/kernel/klids.c linux/kernel/klids.c --- linux/kernel/klids.c Wed Dec 31 16:00:00 1969 +++ linux/kernel/klids.c Sun Jun 3 07:06:50 2001 @@ -0,0 +1,387 @@ +/****************************************************** + * + * This is klids, the LIDS kernel thread. + * It is used to send security alerts through network + * to remote mail servers (or other listening daemon) + * without the help of any user space program. + * + * Philippe BIONDI (philippe.biondi@webmotion.com) + * March 25, 2000 + * + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR) +#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) + +/* debug messages : */ +#if 0 +#define dprintk(fmt, args...) printk(KERN_DEBUG fmt , ## args) +#else +#define dprintk(fmt, args...) +#endif + +#ifdef CONFIG_LIDS_HIDE_KLIDS +#define eprintk(fmt, args...) +#else +#define eprintk(fmt, args...) printk(KERN_ERR fmt , ## args) +#endif + + +/* + * Pseudo-scripting language commands + * + * About the Pseudo-scripting language : + * C purists won't like it, saying that code + * which is not pretty is bad code. (see latter :)) + * I'll say that is the prettiest manner, + * until they give me a prettier one (if they can) + * + */ + +#define lids_send(x) lids_send_sock(sock,x,strlen(x)); +#define lids_expect(x) if (lids_expect_sock(sock,x)<=0) { dprintk("Didn't get %s\n",x); goto err_expect; } +#define LIDS_MESSAGE lids_msgqueue[0].msg[lids_msgqueue[0].head] + +extern void poll_freewait(poll_table * p); +extern int sock_map_fd(struct socket * ); +extern char lids_mail_source[64],lids_mail_from[64], + lids_mail_to[64],lids_mail_subject[128],lids_rcpt_to[64]; + +extern int lids_mail_switch; +extern unsigned long int lids_mail_relay,lids_mail_port; + +typedef struct t_lids_msgqueue { + char *msg[CONFIG_LIDS_MSGQUEUE_SIZE]; + int msg_size[CONFIG_LIDS_MSGQUEUE_SIZE]; + int head, tail, nbmsg; + wait_queue_head_t writeq, readq; /* read and write queues */ +} lids_msgqueue_s; + + +lids_msgqueue_s lids_msgqueue[1]; /* Actually, there is just one. For now.. */ + +static struct semaphore lids_msgqueue_mutex; + + +int lids_send_sock(struct socket *sock, const char *buffer,const size_t length) +{ + struct msghdr msg; + struct iovec iov; + int len; + + if (!sock->sk) + return -ECONNRESET; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = MSG_NOSIGNAL; + msg.msg_iov->iov_base = (char*) buffer; + msg.msg_iov->iov_len = (__kernel_size_t)length + ; + len = sock_sendmsg(sock,&msg,(size_t)(length)); + return len; +} + + + +int lids_expect_sock(struct socket *sock, char *msgnum) +{ + struct msghdr msg; + struct iovec iov; + int len; + char buffer[1024]; + + unsigned long mask; + poll_table wait_table, *wait; + int retval; + long timeout = CONFIG_LIDS_NET_TIMEOUT*HZ; + struct file *file; + + if (sock->sk==NULL) + return -ECONNRESET; + + poll_initwait(&wait_table); + wait = &wait_table; + + /* wait tables initialization */ + /* + wait_table = (poll_table *) __get_free_page(GFP_KERNEL); + if (!wait_table) + return -ENOMEM; + + wait_table->nr = 0; + wait_table->entry = (struct poll_table_entry *)(wait_table + 1); + wait_table->next = NULL; + wait = wait_table; +*/ + + /* polling */ + + lock_kernel(); + + retval=0; + file = sock->file; + for (;;) { + current->state = TASK_INTERRUPTIBLE; + mask = POLLNVAL; + if (file) { + mask = DEFAULT_POLLMASK; + if (file->f_op && file->f_op->poll) + mask = file->f_op->poll(file, wait); + } + if ((mask & POLLIN_SET) || !timeout || signal_pending(current)) + break; + wait = NULL; + timeout = schedule_timeout(timeout); + } + current->state = TASK_RUNNING; + poll_freewait(&wait_table); + + unlock_kernel(); + + /* receiving */ + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = MSG_DONTWAIT; + + + msg.msg_iov->iov_base = buffer; + msg.msg_iov->iov_len = (__kernel_size_t)1024; + + len = sock_recvmsg(sock,&msg,1024,MSG_DONTWAIT); + if (len > 0) + buffer[len-1]=0; + return ((len > 0) && (strstr(buffer,msgnum))); +} + +int lids_klids_thread(void *m) +{ + struct socket *sock; + struct sockaddr_in loc; + struct sockaddr_in rem; + int retval,sockfd; + int try; + + LIDS_DBG("Launching klids kernel thread %i\n",current->pid); + + /* Adjust thread parameters */ + current->session = 1; + current->pgrp = 1; + strcpy(current->comm, "klids"); + current->p_opptr=&init_task; + current->p_pptr=&init_task; + sigfillset(¤t->blocked); + +#ifdef CONFIG_LIDS_HIDE_KLIDS + current->lids_cap = 0; + set_bit(CAP_HIDDEN,¤t->lids_cap); +#endif + + /* Allow args to be in kernel space. */ + set_fs(KERNEL_DS); + + while (1) { + /* if switch is off, do not send msg, FIXME: or sleep */ + if (!lids_mail_switch) { + LIDS_DBG("sleep a while before retrying\n"); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(CONFIG_LIDS_NET_TIMEOUT*HZ); + continue; + } + + if (lids_msgqueue[0].nbmsg == 0) { + LIDS_DBG("klids: go to sleep...\n"); + interruptible_sleep_on(&(lids_msgqueue[0].readq)); + LIDS_DBG("klids: wake up\n"); + + } + + while (lids_msgqueue[0].nbmsg > 0) { + + try=CONFIG_LIDS_NET_MAX_TRIES; + while(1) { + lock_kernel(); + /* create socket */ +#ifdef CONFIG_LIDS_NET_UDP + retval = sock_create(PF_INET,SOCK_DGRAM,IPPROTO_UDP,&sock); +#else + retval = sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&sock); +#endif + if (retval < 0) { + eprintk("klids: Error %d: can't create socket\n",retval); + goto err_crsock; + } + /* create a file descriptor for the socket */ + sockfd=retval = sock_map_fd(sock); + if (retval < 0) { + eprintk("klids: Error %d: can't create socket fd\n",retval); + goto err_crfd; + } + sock->file = fcheck(retval); + + unlock_kernel(); + /* bind */ + loc.sin_family = AF_INET; + loc.sin_addr.s_addr = INADDR_ANY; + loc.sin_port = 0; /* any port */ + + retval = sock->ops->bind(sock,(struct sockaddr*)&loc,sizeof(loc)); + if (retval < 0) { + eprintk("klids: Error %d: can't bind socket\n",retval); + goto err_bind; + } + + /* connect */ + sock->sk->reuse = 1; /* setsockopt... */ + sock->sk->linger = 1; + + rem.sin_family = AF_INET; + rem.sin_addr.s_addr = lids_mail_relay; + rem.sin_port=htons(lids_mail_port); + + retval=sock->ops->connect(sock,(struct sockaddr *)&rem,sizeof(rem),0); + + if (retval < 0) { + eprintk("klids: Error %d: can't connect to %0x,%d\n",retval,lids_mail_relay,lids_mail_port); + goto err_conn; + } + + /* scripting ... */ + +/* + * Well, that seem strange, at first sight. + * Let's say that it is a special language that + * need to be preprocessed before having gcc fed with. + * It just happens that the preprocessor is also the C + * preprocessor. + * +#ifdef CONFIG_LIDS_MAIL_SCRIPT + */ + +#include "lids_mail_script.c" +/*#else +#include CONFIG_LIDS_SCRIPT_PATH +#endif +*/ + + try=1; /* as if it was the last try */ + dprintk("Message sent successfully\n"); + + goto all_ok; + + err_expect: + eprintk("Timeout/Protocol error\n"); + + all_ok: + + err_conn: + err_bind: + sys_close(sockfd); + /* + * release has just been done by sys_close() + * so we must prevent sock_release to be recalled. + */ + goto err_crsock; + err_crfd: + sock_release(sock); + + err_crsock: + /* nothing to dealloc */ + + /* sleep a while */ + if (--try > 0) { + dprintk("sleep a while before retrying\n"); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(CONFIG_LIDS_NET_TIMEOUT*HZ); + } + else + break; + + } + + /* Remove the message, even if it has not + been successfully sent. It is maybe the cause + of the error and it is blocking the whole + message queue. */ + dprintk("Removing message from the queue\n"); + down(&lids_msgqueue_mutex); + lids_msgqueue[0].nbmsg--; + kfree(lids_msgqueue[0].msg[lids_msgqueue[0].head]); + lids_msgqueue[0].head++; + lids_msgqueue[0].head %= CONFIG_LIDS_MSGQUEUE_SIZE; + up(&lids_msgqueue_mutex); + wake_up_interruptible(&(lids_msgqueue[0].writeq)); + } + } + return 0; /* Never reached ... */ +} + + + +void lids_send_message(char *msg,int len) +{ + down(&lids_msgqueue_mutex); + msg[len-1]=0; + if (lids_msgqueue[0].nbmsg < CONFIG_LIDS_MSGQUEUE_SIZE) { + lids_msgqueue[0].msg[lids_msgqueue[0].tail] = msg; + lids_msgqueue[0].msg_size[lids_msgqueue[0].tail++] = len-1; + lids_msgqueue[0].tail %= CONFIG_LIDS_MSGQUEUE_SIZE; + lids_msgqueue[0].nbmsg++; + + dprintk("Msg : <%s>\n",msg); + dprintk("head:%d tail:%d nbmsg:%d\n",lids_msgqueue[0].head,lids_msgqueue[0].tail,lids_msgqueue[0].nbmsg); + up(&lids_msgqueue_mutex); + + wake_up_interruptible(&(lids_msgqueue[0].readq)); + } + else { + up(&lids_msgqueue_mutex); + /* It is safer to loose the message + than to block the process */ + dprintk("Message queue full. One message lost.\n"); + kfree(msg); + } +} + + +int lids_klids_init(void) +{ + init_MUTEX(&lids_msgqueue_mutex); + /* Initialize lids_msgqueue */ + lids_msgqueue[0].nbmsg=0; + lids_msgqueue[0].tail=0; + lids_msgqueue[0].head=0; + init_waitqueue_head(&(lids_msgqueue[0].readq)); + init_waitqueue_head(&(lids_msgqueue[0].writeq)); + /* + lids_msgqueue[0].readq=NULL; + lids_msgqueue[0].writeq=NULL; + */ + + kernel_thread(lids_klids_thread,(void *)0,0); + + return 0; +} diff -urN linux/kernel/ksyms.c linux/kernel/ksyms.c --- linux/kernel/ksyms.c Thu May 24 15:20:18 2001 +++ linux/kernel/ksyms.c Sun Jun 3 06:22:35 2001 @@ -49,6 +49,10 @@ #include #include +#ifdef CONFIG_LIDS +#include +#endif + #if defined(CONFIG_PROC_FS) #include #endif @@ -546,3 +550,27 @@ EXPORT_SYMBOL(tasklist_lock); EXPORT_SYMBOL(pidhash); + +/* LIDS */ +#ifdef CONFIG_LIDS +#ifdef CONFIG_MODULES +/* for modules which use capable() */ +#ifdef CONFIG_LIDS_SA_THROUGH_NET +EXPORT_SYMBOL(lids_send_message); +#endif +/* for modules which use capable() */ +EXPORT_SYMBOL(lids_load); +EXPORT_SYMBOL(lids_cap_log); +/* FIXME: add the above line to solve the insmod problem */ +#ifdef CONFIG_LIDS_ALLOW_SWITCH +EXPORT_SYMBOL(lids_local_on); +EXPORT_SYMBOL(lids_local_pid); +EXPORT_SYMBOL(lids_local_off); +EXPORT_SYMBOL(tty_name); +#endif +#ifdef CONFIG_LIDS_HANGUP +EXPORT_SYMBOL(lids_first_time); +EXPORT_SYMBOL(tty_vhangup); +#endif +#endif +#endif diff -urN linux/kernel/lids.c linux/kernel/lids.c --- linux/kernel/lids.c Wed Dec 31 16:00:00 1969 +++ linux/kernel/lids.c Sun Jun 3 06:48:15 2001 @@ -0,0 +1,1580 @@ +/* + * linux/kernel/lids.c + * + * Author : Huagang Xie, (xie@gnuchina.org) + * + * This file contain the lids security options. + */ + +/* + * Changes: + * + * [Oct 14 1999, Xie Hua Gang] initial creation + * [Oct 17 1999, Xie Hua Gang] Added to do_truncate,do_link(). + * [Oct 27 1999, Xie Hua Gang] Added Append Only ,Device MBR protection. + * [Dec 05 1999, Philippe Biondi] New design. Added hidding process support. Added /dev/[k]mem protection. + * [Dec 08 1999, Xie Hua Gang] Added firewall rules protection. + * [Dec 09 1999, Philippe Biondi] Added ptrace protection. Permission flags for /dev/mem. + * [Dec 17 1999, Philippe Biondi] Added raw disk access, ioperm, iopl protection. + * [Jan 08 2000, Philippe Biondi] Use of capabilities bounding set. + * + * [May 07 2000, Xie Huagang] Add ACL in kernel, reference monitor. + * + * [Sep 26 2000, Xie Huagang] Port to linux 2.4.0-test8 + * + * [Jan 10 2001, Xie Huagang] LIDS for Linux 2.4.0 released! + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/*********************************************************************** + *********************************************************************** + * + * Here are some consts and type definitions + * + *********************************************************************** + ***********************************************************************/ + +#define LIDS_CONF_FILE "/etc/lids/lids.conf" /* the configuration file */ +#define LIDS_CONF_DIR "/etc/lids" +#define LIDS_ADM_PATH "/sbin/lidsadm" /* the adminstration tool */ +#define LIDS_PW_FILE "/etc/lids/lids.pw" +#define LIDS_PW_LEN 32 +#define LIDS_CAP_FILE "/etc/lids/lids.cap" + +typedef struct +{ +int last_secure; +int last_s_acl; +int last_o_acl; +unsigned long search_secure; +unsigned long search_s_acl; +unsigned long fastguess[2048]; +struct secure_ino secure[CONFIG_LIDS_MAX_INODE]; +struct lids_sys_acl s_acl[CONFIG_LIDS_MAX_SACL]; +struct lids_acl o_acl[CONFIG_LIDS_MAX_OACL]; +} _lids_data_t; + +/*********************************************************************** + *********************************************************************** + * + * General variables + * + *********************************************************************** + ***********************************************************************/ + +int lids_load=0; /* it is raised to 1 when kernel boot */ +int lids_local_on=1; +lids_flags_t lids_flags=0; +int lids_local_pid=0; +unsigned long lids_current=0; + +int lids_first_time=1; + +unsigned long lids_cap_val=0; /* store the capability value in lids.cap */ + +#ifdef CONFIG_LIDS_ALLOW_SWITCH +static char lids_pw[160]; +#endif + +#ifndef CONFIG_LIDS_ALLOW_ANY_PROG_SWITCH +static struct allowed_ino lidsadm; +#endif + +static _lids_data_t lids_data[2]={{0,0},{0,0}}; + +#ifdef CONFIG_LIDS_RELOAD_CONF +static int lids_lock_init=0; +static spinlock_t lids_lock; +#endif + +extern int lids_read_net(void); + +static unsigned long lids_bittab[32]= +{ + 0x00000001,0x00000002,0x00000004,0x00000008, + 0x00000010,0x00000020,0x00000040,0x00000080, + 0x00000100,0x00000200,0x00000400,0x00000800, + 0x00001000,0x00002000,0x00004000,0x00008000, + 0x00010000,0x00020000,0x00040000,0x00080000, + 0x00100000,0x00200000,0x00400000,0x00800000, + 0x01000000,0x02000000,0x04000000,0x08000000, + 0x10000000,0x20000000,0x40000000,0x80000000 +}; + +/*********************************************************************** + *********************************************************************** + * + * LIDS protection management + * + *********************************************************************** + ***********************************************************************/ + +int lids_local_off(void) +{ + struct task_struct *t; + + read_lock(&tasklist_lock); + t=current; + while (t && (t->pid > 1)) { + if (t->pid == lids_local_pid) { + read_unlock(&tasklist_lock); + return 1; + } + t=t->p_pptr; + } + read_unlock(&tasklist_lock); + return 0; +} + +/* + * + * LIDS ACL Function + * + */ + +/* + * used when execed, load the lids_cap into task_struct. + */ + +static __inline__ struct lids_sys_acl * lids_do_search_acl(unsigned long int ino,kdev_t dev,_lids_data_t *data) +{ + long i; + long j; + + /* ok, in case of e.g. 256 entries we would require 256 comparisons + for a linear search with no match, the following reduces this + to 8 comparisons (table is sorted!) */ + + for(j=i=data->search_s_acl;;j>>=1) + { + if(i>=data->last_s_acl)i-=j; + else if(data->s_acl[i].devs_acl[i].dev>dev)i-=j; + else if(data->s_acl[i].inos_acl[i].ino>ino)i-=j; + else return &(data->s_acl[i]); + if(!j||i<0)return NULL; + } +} + +struct lids_sys_acl * lids_search_acl(unsigned long int ino,kdev_t dev,unsigned long lids_curr) +{ + return lids_do_search_acl(ino,dev,&lids_data[lids_curr&1]); +} + +/* + * used in before access file(lids_check_base), + * check if the program have permission to access the files. + * if it has, then dont access the files. + * + * we must sure that current->lids_cap is not NULL when call. + */ +static int lids_check_acl(struct dentry *base,int type,unsigned long lids_curr,int check_domain) +{ + struct lids_acl *acl; + struct dentry *parent; + struct inode *inode; + +#ifdef NO_CONFIG_LIDS_RELOAD_CONF + if(lids_curr!=current->lids_current) + { + /* minimal race condition here: in the worst case the + following code is executed a second time but this + is better than a global or per process spinlock */ + spin_lock(&lids_lock); + current->lids_current=lids_current; + current->lids_sys_acl = lids_do_search_acl(current->lids_ino,current->lids_dev,&lids_data[lids_curr&1]); + spin_unlock(&lids_lock); + } +#endif + if( base == NULL || current->lids_sys_acl==NULL) + return -EPERM; + inode = base->d_inode; + parent = base->d_parent; + + if(parent == NULL) + return -EPERM; + + if ( inode == NULL ) { + inode = parent->d_inode; + parent = parent->d_parent; + } + + do { + LIDS_DBG("checking for (%p,%p) %ld,%d--domain=%d\n",base,parent,inode->i_ino,inode->i_dev,check_domain); + if(check_domain) + acl = current->lids_sys_acl->lids_domain; + else + acl = current->lids_sys_acl->lids_acl; + + while(acl != NULL) { + LIDS_DBG("checking loop for %ld,%d vs %ld,%d\n",acl->ino,acl->dev,inode->i_ino,inode->i_dev); + if(acl->ino==inode->i_ino && acl->dev==inode->i_dev) { + LIDS_DBG("bingo! type=%d,acl->type=%d\n",type,acl->type); + return type&acl->type?0:-EPERM; + } + acl = acl->next; + } + if ( inode == parent->d_inode) { + LIDS_DBG("inode == parent->d_inode,return -1\n"); + break; + } + inode = parent->d_inode; + } while( ((parent = parent->d_parent ) != NULL)); + + return -1; +} + +/* + * lids_set_flags, this_sys_acl must be NOT NULL. + */ +int lids_set_acls(struct lids_sys_acl *this_sys_acl) +{ + + struct lids_acl *t_acl,*this_acl,*last_acl; + int i; + + LIDS_DBG("current->cap_effective = %x\n",current->cap_effective); + + /* current->p_pptr,get parent's inherit_flags. + * get the inherit from it's direct parent + * if the inherit is not NULL, inherit the capability + * or clear the capability */ + + current->lids_cap = 0; + + /* exam the inherit first from current->lids_sys_acl*/ + /* 1. CAP inherit */ + if(current->lids_sys_acl->forked) { + + if(current->lids_sys_acl->flags !=0 ) { + current->lids_sys_acl->flags = 0; + /* reset the cap_inherit */ + for(i=0;i<32;i++) { + if(current->lids_sys_acl->cap_inherit[i] !=0) { + set_bit(i,¤t->lids_sys_acl->flags); + } + if(current->lids_sys_acl->cap_inherit[i] > 0) { + current->lids_sys_acl->cap_inherit[i]--; + } + } + } + /* 2. File Acls inherit */ + this_acl = current->lids_sys_acl->lids_acl; + last_acl = NULL; + i=0; + while(this_acl) { + if(this_acl->inherit == 0) { + /*delete the no inheritabe acls */ + if(i == 0) + current->lids_sys_acl->lids_acl=this_acl->next; + else + last_acl->next = this_acl->next; + kfree(this_acl); + } + else if(this_acl->inherit > 0) + this_acl->inherit--; + if(this_acl->inherit !=0) { + last_acl = this_acl; + i++; + } + this_acl =this_acl->next; + } + current->lids_sys_acl->forked=0; + } + + /* Set its own ACLs and CAP */ + if(this_sys_acl) { + int i,inherit; + int this_inherit; + + current->lids_sys_acl->flags |= this_sys_acl->flags; + + /* set the cap_inherit array*/ + for( i=0;i<32;i++) { + inherit = current->lids_sys_acl->cap_inherit[i]; + this_inherit = this_sys_acl->cap_inherit[i]; + if((inherit!=0 && inheritlids_sys_acl->cap_inherit[i] = this_inherit; + if(current->lids_sys_acl->cap_inherit[i]!=0) { + set_bit(i,¤t->lids_sys_acl->flags); + } + } + /* FIXME:The domain change to current running process's domain*/ + current->lids_sys_acl->lids_domain = this_sys_acl->lids_domain; + /* get the lids acl from the this proceeds's ACL-list */ + t_acl=this_sys_acl->lids_acl; + + last_acl = current->lids_sys_acl->lids_acl; + while(t_acl) { + this_acl = kmalloc(sizeof(struct lids_acl), GFP_KERNEL); + if(!this_acl) return -1; + memcpy(this_acl,t_acl,sizeof(struct lids_acl)); + this_acl->next=last_acl; + last_acl = this_acl; + t_acl = t_acl->next; + } + current->lids_sys_acl->lids_acl = last_acl; + } + + /* from the inherit flags, set current flags + * Do you consider the INIT --> all the children, FIXME + */ + current->lids_cap = current->lids_sys_acl->flags; + + LIDS_DBG("set_acls: current->lids_cap =%x\n", current->lids_cap); + + return 0; +} +/* + * free allocated current->lids_sys_acl when do_exit() + */ +void exit_lids(struct task_struct *tsk) +{ + struct lids_sys_acl * this_sys_acl = current->lids_sys_acl; + struct lids_acl *this_acl,*next_acl; + + task_lock(tsk); + current->lids_sys_acl=NULL; + task_unlock(tsk); + + if (this_sys_acl) { + this_acl = this_sys_acl->lids_acl; + while(this_acl) { + next_acl = this_acl->next; + kfree(this_acl); + this_acl = next_acl; + } + LIDS_DBG("pid=%d begin to free %p\n",current->pid,this_sys_acl); + kfree(this_sys_acl); + } +} +/* + * lids_add_acl + * add the acl into system. + */ +static void lids_add_acl(unsigned long int s_ino ,kdev_t s_dev , unsigned long int o_ino,kdev_t o_dev, int type, int inherit, _lids_data_t *data) +{ + struct lids_sys_acl *this_sys_acl; + struct lids_acl *lids_acl,*acl; + int i; + + LIDS_DBG("enter lids_add_acl %ld,%d,%ld,%d,%d,inherit=%d,last_s_acl=%d\n",s_ino,s_dev,o_ino,o_dev,type,inherit,data->last_s_acl); + + for(this_sys_acl=NULL,i=0;ilast_s_acl&&!this_sys_acl;i++) + if(data->s_acl[i].ino==s_ino&&data->s_acl[i].dev==s_dev) + this_sys_acl=&(data->s_acl[i]); + + if(!this_sys_acl) + { + if(data->last_s_acl==CONFIG_LIDS_MAX_SACL)return; + if((int)(o_ino)!=-1&&data->last_o_acl==CONFIG_LIDS_MAX_OACL) + return; + + LIDS_DBG("lids_add_s_acl,%ld,%d\n",s_ino,s_dev); + + this_sys_acl=&(data->s_acl[(data->last_s_acl)++]); + this_sys_acl->ino = s_ino; + this_sys_acl->dev = s_dev; + this_sys_acl->flags = 0; + memset(this_sys_acl->cap_inherit,'\0',32*sizeof(int *)); + this_sys_acl->lids_acl = NULL; + this_sys_acl->lids_domain = NULL; + } + + if((int)(o_ino)==-1) + { + /* flags indicate that this proceed has capability + * to do someting ,inherit_flags dicide that if the capability + * can be inherit to its children */ + set_bit(o_dev,&this_sys_acl->flags); + this_sys_acl->cap_inherit[o_dev] = inherit; + return; + } + + if(data->last_o_acl==CONFIG_LIDS_MAX_OACL)return; + + LIDS_DBG("lids_add_o_acl,%ld,%d,%ld,%d,%d\n",this_sys_acl->ino,this_sys_acl->dev,o_ino,o_dev,type); + + lids_acl=&(data->o_acl[(data->last_o_acl)++]); + lids_acl->ino = o_ino; + lids_acl->dev = o_dev; + lids_acl->inherit = inherit; + lids_acl->next = NULL; + + if(type < 0) { + lids_acl->type = -type; + if((acl=this_sys_acl->lids_domain)==NULL) + this_sys_acl->lids_domain=lids_acl; + else { + while(acl->next)acl=acl->next; + acl->next = lids_acl; + } + } + else { + lids_acl->type = type; + if((acl=this_sys_acl->lids_acl)==NULL) + this_sys_acl->lids_acl=lids_acl; + else { + while(acl->next)acl=acl->next; + acl->next = lids_acl; + } + } +} + +static __inline__ int lids_acl_dev_ino_cmp(struct lids_sys_acl *s1,struct lids_sys_acl *s2) +{ + if(s1->devdev)return -1; + if(s1->dev>s2->dev)return 1; + if(s1->inoino)return -1; + if(s1->ino>s2->ino)return 1; + return 0; /* Aieeeh, duplicate entry */ +} + +static int lids_sort_acls(_lids_data_t *data) +{ + int i; + int working; + struct lids_sys_acl tmp; + + /* sort source acl entries by device and inode */ + + do + { + working=0; + for(i=0;ilast_s_acl-1;i++) + switch(lids_acl_dev_ino_cmp(&(data->s_acl[i]), + &(data->s_acl[i+1]))) + { + case 0: return 0; + case 1: tmp=data->s_acl[i]; + data->s_acl[i]=data->s_acl[i+1]; + data->s_acl[i+1]=tmp; + working=1; + } + for(i=data->last_s_acl-1;i>0;i--) + switch(lids_acl_dev_ino_cmp(&(data->s_acl[i-1]), + &(data->s_acl[i]))) + { + case 0: return 0; + case 1: tmp=data->s_acl[i-1]; + data->s_acl[i-1]=data->s_acl[i]; + data->s_acl[i]=tmp; + working=1; + } + } while(working); + + /* set up base index for fast search: no, we can't use >0x20000000 + here but anyway it'll take some years for computers to + allow for the memory required for this size :-) */ + + data->search_s_acl=0x20000000; + while(data->last_s_acl<=data->search_s_acl&&data->search_s_acl) + data->search_s_acl>>=1; + + return 1; +} + +/*********************************************************************** + * + * lids_search_inode() + * + * check the inode in a arr_ino array. + * may be use fast search in this array. + * xhg, 1999/10/11. + * + */ + +static __inline__ int lids_search_inode(unsigned long ino,kdev_t dev,_lids_data_t *data) +{ + long i=(ino^dev)&0xffff; + long j; + + /* when the 'hash' bit is not set we for sure don't have + a matching entry, so just signal 'nothing found' */ + + if(!(data->fastguess[i>>5]&lids_bittab[i&31]))return -1; + + /* ok, in case of e.g. 256 entries we would require 256 comparisons + for a linear search with no match, the following reduces this + to 8 comparisons (table is sorted!) */ + + for(j=i=data->search_secure;;j>>=1) + { + if(i>=data->last_secure)i-=j; + else if(data->secure[i].devsecure[i].dev>dev)i-=j; + else if(data->secure[i].inosecure[i].ino>ino)i-=j; + else + { + return data->secure[i].type; + } + if(!j||i<0)return -1; + } +} + +int lids_check_hidden_inode(unsigned long ino,kdev_t dev) +{ + if(lids_search_inode(ino,dev,&lids_data[lids_current&1])==LIDS_DENY) + return -1; + return 0; +} + +/*********************************************************************** + * + * lids_check_base(); + * + * check if the base have been protected by the IDS system. + * use the base->d_parent + * check if the requried access can be permitted + */ + +int lids_check_base(struct dentry *base, int flag) +{ + struct inode *ino; + struct dentry *dentry=base; + int retval=0; + unsigned long lids_curr=lids_current; + + /* check if the dentry is in the domain */ + while(dentry) { + if((ino=dentry->d_inode)!=NULL) { + if(current->lids_sys_acl && current->lids_sys_acl->lids_domain) + retval = lids_check_acl(base,flag,lids_curr,1); + else + break; + if(retval == 0) + break; + return -EPERM; + } + if (dentry==dentry->d_parent) { + /* do not in this exec domain */ + return -EPERM; + } + dentry=dentry->d_parent; + } + + while (dentry) { + if((ino=dentry->d_inode)!=NULL) + if((retval=lids_search_inode(ino->i_ino,ino->i_dev, + &lids_data[lids_curr&1])) >= 0) { + return (retval & flag) ? 0: + lids_check_acl(base,flag,lids_curr,0); + } + if (dentry==dentry->d_parent) + return 0; + dentry=dentry->d_parent; + } + + return 0; +} + +/*********************************************************************** + * + * lids_add_inode(inode,dev,type) + * + * add the given inode into the arr_ino. + * if full return 0 + * else return the insert position. + * + */ +static void lids_add_inode(unsigned long inode ,kdev_t dev , int type,_lids_data_t *data) +{ + int i; + + if (data->last_secure==CONFIG_LIDS_MAX_INODE)return; + + LIDS_DBG("lids_add_inode,%ld,%d,%d\n",inode,dev,type); + + for(i=0;ilast_secure;i++) + if(data->secure[i].ino==inode&&data->secure[i].dev==dev) + return; + + data->secure[data->last_secure].ino = inode; + data->secure[data->last_secure].dev = dev; + data->secure[data->last_secure].type = type; + + (data->last_secure)++; + + i=(dev^inode)&0xffff; + data->fastguess[i>>5]|=lids_bittab[i&31]; +} + +static __inline__ int lids_inode_dev_ino_cmp(struct secure_ino *s1,struct secure_ino *s2) +{ + if(s1->devdev)return -1; + if(s1->dev>s2->dev)return 1; + if(s1->inoino)return -1; + if(s1->ino>s2->ino)return 1; + return 0; /* Aieeeh, duplicate entry */ +} + +static int lids_sort_inodes(_lids_data_t *data) +{ + int i; + int working; + struct secure_ino tmp; + + /* sort inode entries by device and inode */ + + do { + working=0; + for(i=0;ilast_secure-1;i++) + switch(lids_inode_dev_ino_cmp(&(data->secure[i]), + &(data->secure[i+1]))) { + case 0: return 0; + case 1: tmp=data->secure[i]; + data->secure[i]=data->secure[i+1]; + data->secure[i+1]=tmp; + working=1; + } + for(i=data->last_secure-1;i>0;i--) + switch(lids_inode_dev_ino_cmp(&(data->secure[i-1]), + &(data->secure[i]))) { + case 0: return 0; + case 1: tmp=data->secure[i-1]; + data->secure[i-1]=data->secure[i]; + data->secure[i]=tmp; + working=1; + } + } while(working); + + /* set up base index for fast search: no, we can't use >0x20000000 + here but anyway it'll take some years for computers to + allow for the memory required for this size :-) */ + + data->search_secure=0x20000000; + while(data->last_secure<=data->search_secure&&data->search_secure) + data->search_secure>>=1; + + return 1; +} + +/**************************************************************************/ + +/* + * lids_get_info(char *buffer); + * + */ +static int lids_get_info(char *buffer, unsigned long int *ino,kdev_t *dev) +{ + int error = -1; + char ino_str[64],dev_str[64]; + char *q,*p; + struct dentry *d_file; + int is_special = 0; + struct nameidata nd; + + /* get the dentry of the file */ + /* it is a special type, ino=-1*/ + if(*buffer == '-' ) { + is_special = 1; + } + memset(ino_str,'\0',64); + memset(dev_str,'\0',64); + + p = memscan(buffer,':',strlen(buffer)); + if(((unsigned long)(p-buffer))==strlen(buffer))goto exit; + if(((unsigned long)(p-buffer))>63)goto exit; + memcpy(ino_str,buffer,p-buffer); + + p++; + q = memscan(p,':',strlen(p)); + if(((unsigned long)(q-p))==strlen(p))goto exit; + if(((unsigned long)(q-p))>63)goto exit; + memcpy(dev_str,p,q-p); + + error = 0; + if(is_special) { + *dev = (kdev_t)simple_strtoul(dev_str,0,0); + *ino = -1; + goto exit; + } + q++; + /* + if(path_init(q, LOOKUP_FOLLOW|LOOKUP_POSITIVE,&nd)) + error = path_walk(q,&nd); + */ + error = user_path_walk(q,&nd); + /* + if(error) + goto exit; + */ + d_file = nd.dentry; + + + if(error) { + *ino = simple_strtoul(ino_str,0,0); + *dev = (kdev_t)simple_strtoul(dev_str,0,0); + } + else { + if (d_file) if(d_file->d_inode){ + if ( (d_mountpoint(d_file))) { /* FIXME: is right?? */ + LIDS_DBG("OK,Mount point found!\n"); + *ino = simple_strtoul(ino_str,0,0); + *dev = (kdev_t)simple_strtoul(dev_str,0,0); + } + else { + *ino=simple_strtoul(ino_str,0,0); + *dev=(kdev_t)simple_strtoul(dev_str,0,0) ; + if ((*ino != d_file->d_inode->i_ino) || + (*dev != d_file->d_inode->i_dev)) { + LIDS_DBG("now=%p\n",d_file); + printk("LIDS: [%s] dev/inode in lids.conf seems wrong\n",q); + } + } + } + path_release(&nd); + } + error = 0; + exit: + LIDS_DBG("lids_get_info : return %d\n",error); + return error; +} +/*********************************************************************** + * + * lids_init_add_file ( char * filename) + * + * read filename from read_file() + * + * method : get the dentry from the filename. + * check if its parent is in the err_ino. + * if not, add the inode. + * + * the format is s_ino:s_dev:s_file:type:o_ino:o_dev:o_file + */ + +static int lids_init_add_file ( char *buffer,_lids_data_t *data) +{ + char *p,*q; + int error = -1; + int is_default_rule = 0; + int type,inherit; + unsigned long int s_ino,o_ino; + kdev_t s_dev,o_dev; + + p = memscan(buffer,':',strlen(buffer)); + if(((unsigned long)(p-buffer))==strlen(buffer))goto exit; + + p++; + q = memscan(p,':',strlen(p)); + if(((unsigned long)(q-p))==strlen(p))goto exit; + + q++; + if(*q == ':' ) { + is_default_rule = 1; + p = q; + } + else { + p = memscan(q,':',strlen(q)); + if(((unsigned long)(p-q))==strlen(q))goto exit; + } + *p = '\0'; + p++; + q = memscan(p,':',strlen(p)); + *q = '\0'; + q++; + type =simple_strtol(p,0,0); + + p = memscan(q,':',strlen(q)); + *p = '\0'; + inherit = simple_strtol(q,0,0); + p++; + + /* q point to the object's ino,dev,filename */ + if(is_default_rule) { + s_ino = s_dev = 0; + } + else { + if ( lids_get_info(buffer,&s_ino,&s_dev) < 0 ) + goto exit; + } + if ( lids_get_info(p,&o_ino,&o_dev) < 0 ) + goto exit ; + + if(is_default_rule) + lids_add_inode(o_ino,o_dev,type,data); + else { + lids_add_acl(s_ino,s_dev,o_ino,o_dev,type,inherit,data); + } + error = 0; +exit: + return error; +} + +/*********************************************************************** + * + * add a file into the secure list. + * + */ + +static int init_add_file(char *filename,_lids_data_t *data) +{ + struct dentry *dentry; + int error=0; + struct nameidata nd; + + if (path_init(filename, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) + error = path_walk(filename, &nd); + if(error) + goto err_out; + /* + down(&nd.dentry->d_inode->i_sem); + dentry = lookup_hash(&nd.last, nd.dentry); + */ + dentry = nd.dentry; + + if (IS_ERR(dentry) || !dentry || !(dentry->d_inode)) + error = -1; + else { + lids_add_inode(dentry->d_inode->i_ino,dentry->d_inode->i_dev, + LIDS_DENY,data); + // dput(dentry); + } + /* + up(&nd.dentry->d_inode->i_sem); + */ + path_release(&nd); +err_out: + LIDS_DBG("init_add_file : return %d\n",error); + return error; +} +/* + * read the capability value into lids_cap + * format [+|-]number:cap_name + */ +int lids_cap_init(char *buffer) +{ + char *p; + int flag; + int error = 0; + error = -1; + p = memscan(buffer,':',strlen(buffer)); + if(((unsigned long)(p-buffer))==strlen(buffer))goto exit; + + *p = '\0'; + flag = simple_strtoul(buffer+1,0,0); + error = 0; + if(buffer[0] == '+') + cap_raise(lids_cap_val,flag); + else if(buffer[0] == '-' ) + cap_lower(lids_cap_val,flag); + else + error = -2; +exit: + return error; +} + +/* + * lids read capability from /etc/lids/lids.cap + */ + +int lids_read_cap(void) +{ + struct file *filp; + char buffer[1024], *p,*q; + mm_segment_t oldfs; + int bytes; + int error =0; + int start=0,finished=0; + + filp = filp_open(LIDS_CAP_FILE,O_RDONLY,O_RDONLY); + if (IS_ERR(filp)||(filp==NULL)) { + error = -1 ; + printk("LIDS: Checking capability file %s error,does it exist?\n",LIDS_CONF_FILE); + /* FIXME: if (lids_load) goto err_panic; */ + return error; + } + + if (filp->f_op->read==NULL) { + fput(filp); + error = -3 ; + printk("LIDS: The file %s can not be read\n",LIDS_CONF_FILE); + /* + if (lids_load) goto err_panic ; + */ + return error; + } + while ( !finished ) { + filp->f_pos = start; + oldfs = get_fs(); + set_fs(KERNEL_DS); + bytes = filp->f_op->read(filp,buffer,1024,&filp->f_pos); + set_fs(oldfs); + + q=buffer; + + if(bytes<1024){ + finished=1; + q[bytes++]='\n'; + } + /* Now read 1024 bytes into buffer */ + /* analyze the buffer */ + while(bytes&&(p=memscan(q,'\n',bytes))!=q+bytes) { + *p++='\0'; + start+=(int)(p-q); + bytes-=(int)(p-q); + while(*q=='\r')q++; /* hmmm... */ + if(*q=='-' || *q=='+') if ( lids_cap_init(q) < 0) { + error = -5; + printk("LIDS: error in adding [%s] to the kernel\n",q); + break; + } + q=p; + } + if(error)break; + + if(bytes==1024) + { + printk("LIDS: Line too long in file %s\n",LIDS_CAP_FILE); + error = -4; /* if the line contains no '\n' */ + break; + } + } + LIDS_DBG("lids_read_cap:lids_cap_val = %x\n",lids_cap_val); + /* Close the file */ + fput(filp); + return error; +} +/* + * read the lids password generated by "lidsadm -P" into kernel + * if nessary + */ +#ifdef CONFIG_LIDS_ALLOW_SWITCH +int lids_read_pw(void) +{ + struct file *filp; + char buffer[LIDS_PW_LEN]; + mm_segment_t oldfs; + int bytes; + int error =0; + + filp = filp_open(LIDS_PW_FILE,O_RDONLY,O_RDONLY); + if (IS_ERR(filp)||(filp==NULL)) { + error = -1 ; + printk("LIDS: Checking passwd file %s error,does it exist?\n",LIDS_CONF_FILE); + /* + FIXME: if (lids_load) goto err_panic; + */ + + return error; + } + + if (filp->f_op->read==NULL) { + fput(filp); + error = -3 ; + printk("LIDS: The file %s can not be read\n",LIDS_CONF_FILE); + /* + if (lids_load) goto err_panic ; + */ + return error; + } + + /* Now read LIDS_PW_LEN bytes from postion "StartPos" */ + filp->f_pos = 0; + oldfs = get_fs(); + set_fs(KERNEL_DS); + bytes = filp->f_op->read(filp,buffer,LIDS_PW_LEN,&filp->f_pos); + set_fs(oldfs); + + if(bytesfastguess,0,sizeof(data->fastguess)); + +#ifndef CONFIG_LIDS_ALLOW_ANY_PROG_SWITCH + if(path_init(LIDS_ADM_PATH, LOOKUP_FOLLOW|LOOKUP_POSITIVE,&nd)) + error = path_walk(LIDS_ADM_PATH,&nd); + if(error) + return -1; + /* + down(&nd.dentry->d_inode->i_sem); + dentry = lookup_hash(&nd.last, nd.dentry); + */ + dentry = nd.dentry; + + if (IS_ERR(dentry) || (!dentry)) { + printk("LIDS : " LIDS_ADM_PATH " not found \n"); + lidsadm.ino = 0; + lidsadm.dev = 0; + } + else { + if(!dentry->d_inode || + !dentry->d_inode->i_dev || + !dentry->d_inode->i_ino) { + printk("LIDS: something wrong with " LIDS_ADM_PATH "\n"); + lidsadm.ino = 0; + lidsadm.dev = 0; + } + else { + lidsadm.ino = dentry->d_inode->i_ino; + lidsadm.dev = dentry->d_inode->i_dev; + } + } + path_release(&nd); +#endif + + /* Now, try to read lids.conf */ + + if ( init_add_file(LIDS_CONF_DIR,data) < 0 ) { + error = -1; + printk("LIDS: Adding conf file %s error,does it exist?\n",LIDS_CONF_FILE); + if (lids_load) goto lids_panic; + return -1; + } + filp = filp_open(LIDS_CONF_FILE,O_RDONLY,O_RDONLY); + + if (IS_ERR(filp)||(filp==NULL)) { + error = -2 ; + printk("LIDS: Checking conf file %s error,does it exist?\n",LIDS_CONF_FILE); + if (lids_load) goto lids_panic; /* Or do something else */ + return -1; + } + + if (filp->f_op->read==NULL) { + fput(filp); + error = -3 ; + printk("LIDS: The file %s can not be read\n",LIDS_CONF_FILE); + if (lids_load) goto lids_panic ; /* File(system) doesn't allow reads */ + return -1; + } + + /* Now read 1024 bytes from postion "StartPos" */ + while ( !finished ) { + filp->f_pos = start; + oldfs = get_fs(); + set_fs(KERNEL_DS); + bytes = filp->f_op->read(filp,buffer,1024,&filp->f_pos); + set_fs(oldfs); + + q=buffer; + + if(bytes<1024) + { + finished=1; + q[bytes++]='\n'; + } + + while(bytes&&(p=memscan(q,'\n',bytes))!=q+bytes) + { + *p++='\0'; + LIDS_DBG(" read_file : line=->%s<-\n",q); + start+=(int)(p-q); + bytes-=(int)(p-q); + while(*q=='\r')q++; /* hmmm... */ + if(*q&&*q!='#')if(lids_init_add_file(q,data)<0) + { + printk("LIDS: error in adding [%s] to the kernel\n",q); + error = -5; + break; + } + q=p; + } + + if(error)break; + + if(bytes==1024) + { + printk("LIDS: Line too long in file %s\n",LIDS_CONF_FILE); + error = -4; /* if the line contains no '\n' */ + break; + } + } + + memset(buffer,'\0',1024); + + /* Close the file */ + fput(filp); + + if(error) + { + if (lids_load) goto lids_panic; /* Or do something else */ + return -1; + } + if(!lids_sort_inodes(data)) + { + printk("LIDS: Aieeh, duplicate inode entry in file %s\n",LIDS_CONF_FILE); + error = -6; + if (lids_load) goto lids_panic; /* Or do something else */ + return -1; + } + + if(!lids_sort_acls(data)) + { + printk("LIDS: Aieeh, duplicate source acl entry in file %s\n",LIDS_CONF_FILE); + error = -7; + if (lids_load) goto lids_panic; /* Or do something else */ + return -1; + } +#ifdef CONFIG_LIDS_ALLOW_SWITCH + /* Read the password now */ + if(lids_read_pw()) { + printk("LIDS: Read password file error\n"); + error = -8; + goto lids_panic; + } +#endif + /* read the cap init from lids.cap into lids_cap_val */ + if(lids_read_cap()) { + printk("LIDS: Read capability file error\n"); + error = -9; + goto lids_panic; + } +#ifdef CONFIG_LIDS_SA_THROUGH_NET + /* read network parameter from lids.net */ + if(lids_read_net()) { + printk("LIDS: Read mail parameter error\n"); + error = -10; + goto lids_panic; + } +#endif + +#if 0 + printk("read_file : finish=%d ret %d\n",finished,error); + for(start=0;startlast_secure;start++) + { + struct lids_sys_acl *this_sys_acl; + struct lids_acl *this_acl; + int i; + this_sys_acl = (struct lids_sys_acl *)&(data->s_acl[start]); + + printk("-----------\ndefault: %ld--%d--%d\n",data->secure[start].ino, data->secure[start].dev, data->secure[start].type); + for(i=0;i<32;i++) + printk("CAPABILITY:%d\t",this_sys_acl->cap_inherit[i]); + + this_acl = this_sys_acl->lids_acl; + while(this_acl!=NULL) { + LIDS_DBG("----------\nobject:\tthis_acl=%ld,%d,type=%d,inherit=%d\n",this_acl->ino,this_acl->dev,this_acl->type,this_acl->inherit); + this_acl = this_acl->next; + } + + this_acl = this_sys_acl->lids_domain; + while(this_acl!=NULL) { + printk("object:\tthis_domain=%ld,%d,type=%d\n",this_acl->ino,this_acl->dev,this_acl->type); + this_acl = this_acl->next; + } + } +#endif + if (!error ) { + LIDS_DBG("written to index %d\n",(lids_current&1)^1); + printk("LIDS: Statistics: %d objects, %d source ACLS, %d object ACLs,capability = %lx\n",data->last_secure,data->last_s_acl,data->last_o_acl,lids_cap_val); + lids_current++; + LIDS_DBG("lids_current=%d index=%d\n",lids_current,lids_current&1); + return 0; + } + else +lids_panic: + panic("LIDS: Can not initial the lids system, return code %d, pls contact Huagang Xie (xie@gnuchina.org)",error); + return error; +} + +/*********************************************************************** + *********************************************************************** + * + * Now, the sysctl procedures + * + *********************************************************************** + ***********************************************************************/ + + + +/*********************************************************************** + * + * What is needed to lock init children + * + */ + +pid_t lids_protected_pid[CONFIG_LIDS_MAX_PROTECTED_PID]; +int lids_last_pid=0; + +static int init_no_kill_pid(void) +{ + struct task_struct * p; + + read_lock(&tasklist_lock); + for_each_task(p) { + if ( p->pid >1 && p->p_pptr->pid == 1 ) { + if( lids_last_pid < CONFIG_LIDS_MAX_PROTECTED_PID) { + lids_protected_pid[lids_last_pid++] = p->pid; + } + } + } + read_unlock(&tasklist_lock); + return 0; +} + +/*********************************************************************** + * + * The one which process flags changes + * + * If it returns 0, caps won't be processed. + * + */ + +static int lids_process_flags(lids_flags_t flags) +{ +#ifdef CONFIG_LIDS_ALLOW_SWITCH + _lids_data_t *data=&lids_data[(lids_current&1)^1]; + + /* LIDS switching */ + if (lids_first_time && (LIDS_FISSET(flags,LIDS_FLAGS_LIDS_ON) == 0) && (lids_load)) { + lids_security_alert("Try to switch LIDS off at sealing time"); + return 0; + } + else { + if (lids_load != LIDS_FISSET(flags,LIDS_FLAGS_LIDS_ON)) { + lids_load=LIDS_FISSET(flags,LIDS_FLAGS_LIDS_ON); + lids_security_alert("LIDS switched to %i",lids_load); + if (lids_load) + LIDS_FSET(lids_flags,LIDS_FLAGS_LIDS_ON); + else + LIDS_FCLR(lids_flags,LIDS_FLAGS_LIDS_ON); + } + } + if (lids_first_time && (LIDS_FISSET(flags,LIDS_FLAGS_LIDS_LOCAL_ON) == 0) && (lids_load)) { + lids_security_alert("Try to switch LIDS locally off at sealing time"); + return 0; + } + else { + if (lids_local_on != LIDS_FISSET(flags,LIDS_FLAGS_LIDS_LOCAL_ON)) { + lids_local_on=LIDS_FISSET(flags,LIDS_FLAGS_LIDS_LOCAL_ON); + lids_security_alert("LIDS locally switched to %i",lids_local_on); + if (lids_local_on) { + LIDS_FSET(lids_flags,LIDS_FLAGS_LIDS_LOCAL_ON); + } + else { + lids_local_pid=current->p_pptr->pid; + if (lids_local_pid == 1) { /* this doesn't apply to init */ + printk("Can't give local lids deactivation to init!!\n"); + LIDS_FSET(lids_flags,LIDS_FLAGS_LIDS_LOCAL_ON); + lids_local_on = 1; + } + else + LIDS_FCLR(lids_flags,LIDS_FLAGS_LIDS_LOCAL_ON); /* should not be necessary */ + + } + } + } +#else + if (LIDS_FISSET(flags,LIDS_FLAGS_LIDS_ON) != lids_load) { + lids_security_alert("Try to switch LIDS off (feature disabled)"); + return 0; + } +#endif + + /* Config file reload */ + if (LIDS_FISSET(flags,LIDS_FLAGS_RELOAD_CONF)) { +#ifdef CONFIG_LIDS_RELOAD_CONF + if((!lids_local_on&&lids_local_pid==current->p_pptr->pid)||!lids_load) + { + data->last_secure=0; + data->last_s_acl=0; + data->last_o_acl=0; + lids_init(); + /* cap_bset=locks.cap_bset;*/ + cap_bset = lids_cap_val; + lids_security_alert("Config. file reloaded"); + } + else lids_security_alert("Security enabled, config. file NOT reloaded"); +#else + lids_security_alert("Try to reload config. file (feature disabled)"); +#endif + } + return 1; +} + + +/*********************************************************************** + * + * The one which set/get security features + * + */ + +static int number_failed=0; +static int wait_after_fail=0; +#ifdef CONFIG_LIDS_ALLOW_SWITCH +static struct timer_list fail_timer; +#endif + +/* called by timer */ +static void reenable_sysctl(unsigned long user_data) +{ + number_failed=0; + wait_after_fail=0; +} + +int lids_proc_locks_sysctl(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, int conv, int op) +{ + lids_locks_t locks; + char rmd160sig[LIDS_PW_LEN+10]; + +#ifdef CONFIG_LIDS_ALLOW_SWITCH + byte hashcode[RMDsize/8]; + int i; +#endif + + /* first: check the terminal and the program which access the sysctl */ + +#ifdef CONFIG_LIDS_RESTRICT_MODE_SWITCH + if (current->tty + && ! (0 +#ifdef CONFIG_LIDS_MODE_SWITCH_CONSOLE + || current->tty->driver.type == TTY_DRIVER_TYPE_CONSOLE +#endif +#ifdef CONFIG_LIDS_MODE_SWITCH_SERIAL + || current->tty->driver.type == TTY_DRIVER_TYPE_SERIAL +#endif +#ifdef CONFIG_LIDS_MODE_SWITCH_PTY + || current->tty->driver.type == TTY_DRIVER_TYPE_PTY +#endif + )) { + lids_security_alert("Try to %s locks sysctl (unauthorized terminal)", + write ? "write" : "read"); + return -EPERM; + } +#endif /* CONFIG_LIDS_RESTRICT_MODE_SWITCH */ + +#ifndef CONFIG_LIDS_ALLOW_ANY_PROG_SWITCH + { + struct vm_area_struct * vma; + unsigned long ino; + dev_t dev; + + ino=-1; + dev=-1; + if (current->mm) { + vma = current->mm->mmap; + while (vma) { + if ((vma->vm_flags & VM_EXECUTABLE) && + vma->vm_file && vma->vm_file->f_dentry && + vma->vm_file->f_dentry->d_inode) { + ino=vma->vm_file->f_dentry->d_inode->i_ino; + dev=vma->vm_file->f_dentry->d_inode->i_dev; + break; + } + vma = vma->vm_next; + } + } + if ( (ino != lidsadm.ino) || (dev != lidsadm.dev) ) { + lids_security_alert("Try to %s locks sysctl (unauthorised program)", + write ? "write" : "read"); + return -EPERM; + } + } +#endif + /* second: check wether it is not a timeout period after two many failed attempts */ + + if (wait_after_fail) { + lids_security_alert("Try to %s locks sysctl during timeout",write ? "write" : "read"); + return -EPERM; + } + + if (write) { + /* Third : check what is submitted (size, magics, passwd) */ + if (*lenp != sizeof(lids_locks_t)) { + lids_security_alert("Try to feed locks sysctl with garbage"); + return -EINVAL; + } + if (copy_from_user(&locks,buffer,sizeof(lids_locks_t))) + return -EFAULT; + if ((locks.magic1 != LIDS_MAGIC_1) || (locks.magic2 != LIDS_MAGIC_2) || + (locks.magic3 != LIDS_MAGIC_3) || (locks.magic4 != LIDS_MAGIC_4)) { + memset((char *)locks.passwd,'\0',sizeof(passwd_t)); + lids_security_alert("Try to feed locks sysctl bad magic numbers"); + return -EINVAL; + } + locks.passwd[sizeof(passwd_t)-1]=0; /* We don't take the risk */ + rmd160sig[0]=0; + +#ifdef CONFIG_LIDS_ALLOW_SWITCH + if ((!lids_first_time) || (locks.passwd[0])) { + RMD((byte *)locks.passwd,hashcode); + memset((char *)locks.passwd,'\0',sizeof(passwd_t)); + for (i=0; itty!=NULL) + set_bit(TTY_LIDS_NO_HANGUP, &(current->tty->flags)); +#endif + if (lids_process_flags(locks.flags)) { + /* Seal the kernel,we can change the cap_set here */ + if(lids_first_time || LIDS_FISSET(locks.flags,LIDS_FLAGS_RELOAD_CONF)) + cap_bset = lids_cap_val; + else + cap_bset = locks.cap_bset; + if((lids_first_time || LIDS_FISSET(locks.flags,LIDS_FLAGS_RELOAD_CONF)) && (!cap_raised(cap_bset,CAP_INIT_KILL))){ + lids_last_pid=0; + init_no_kill_pid(); + } + lids_security_alert("Changed: cap_bset=0x%x lids_flags=0x%x",cap_t(cap_bset),lids_flags); + } + lids_first_time=0; + } + else { +#ifdef CONFIG_LIDS_HANGUP + if(current->tty!=NULL) + clear_bit(TTY_LIDS_NO_HANGUP, &(current->tty->flags)); +#endif +#ifdef CONFIG_LIDS_ALLOW_SWITCH + number_failed++; + lids_security_alert("Give incorrect password (try #%d) with caps=0x%x and flags=0x%x", + number_failed,cap_t(locks.cap_bset),locks.flags); + if (number_failed >= CONFIG_LIDS_MAX_TRY) { + wait_after_fail=1; + init_timer(&fail_timer); + fail_timer.function=reenable_sysctl; + fail_timer.data=(unsigned long)NULL; + fail_timer.expires=jiffies+CONFIG_LIDS_TTW_FAIL*HZ; + add_timer(&fail_timer); + } +#else + lids_security_alert("Try %d to switch caps/flags with caps=0x%x and flags=0x%x (feature disabled)", + number_failed,cap_t(locks.cap_bset),locks.flags); +#endif + } + } + else { + locks.cap_bset=cap_bset; + locks.flags=lids_flags; + if (*lenp < sizeof(lids_locks_t)) + return -EINVAL; + if (copy_to_user(buffer,&locks,sizeof(lids_locks_t))) + return -EFAULT; + } + return 0; +} + +/* + * lids capability violate logging + */ + +static char *lids_caps_desc[] = +{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_KILL", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETPCAP", + "CAP_LINUX_IMMUTABLE", + "CAP_NET_BIND_SERVICE", + "CAP_NET_BROADCAST", + "CAP_NET_ADMIN", + "CAP_NET_RAW", + "CAP_IPC_LOCK", + "CAP_IPC_OWNER", + "CAP_SYS_MODULE", + "CAP_SYS_RAWIO", + "CAP_SYS_CHROOT", + "CAP_SYS_PTRACE", + "CAP_SYS_PACCT", + "CAP_SYS_ADMIN", + "CAP_SYS_BOOT", + "CAP_SYS_NICE", + "CAP_SYS_RESOURCE", + "CAP_SYS_TIME", + "CAP_SYS_TTY_CONFIG", + "CAP_MKNOD", + "CAP_LEASE", + "CAP_HIDDEN", + "CAP_INIT_KILL", + NULL +}; + +void lids_cap_log(int cap) +{ + LIDS_DBG("pid=%d,lids_cap =%lx, cap_effective=%x,cap=%d,lids_load=%d,lids_local_load=%d--lids_local_off=%d\n",current->pid,current->lids_cap, current->cap_effective,cap,lids_load,lids_local_load,lids_local_off()); + LIDS_DBG("uid=%d,euid=%d,first_time=%d\n",current->uid,current->euid,lids_first_time); + if(!cap_raised(lids_cap_val,cap)) + lids_security_alert(" violated %s",lids_caps_desc[cap]); +} diff -urN linux/kernel/lids_mail_script.c linux/kernel/lids_mail_script.c --- linux/kernel/lids_mail_script.c Wed Dec 31 16:00:00 1969 +++ linux/kernel/lids_mail_script.c Sun Jun 3 07:07:46 2001 @@ -0,0 +1,34 @@ +/* + * Mail LIDS security alerts + * + * Philippe Biondi (philippe.biondi@webmotion.com) + * March 29, 2000 + * + * Sep 1, 2000 Xie Huagang, used configuation file. + * But It is not compatible to write the pseudo file. + * + */ + + +/* + * This is a pseudo scripting language + * It is in fact directly included in the C source of + * klids.c by the cpp. + * + */ + + +lids_expect("220"); +lids_send(lids_mail_source); +lids_expect("250"); +lids_send(lids_mail_from); +lids_expect("250"); +lids_send(lids_rcpt_to); +lids_expect("250"); +lids_send("data\r\n"); +lids_expect("354"); +lids_send(lids_mail_subject); +lids_send(LIDS_MESSAGE); +lids_send("\r\n.\r\n"); +lids_expect("250"); +lids_send("quit\r\n"); diff -urN linux/kernel/lids_net.c linux/kernel/lids_net.c --- linux/kernel/lids_net.c Wed Dec 31 16:00:00 1969 +++ linux/kernel/lids_net.c Sun Jun 3 07:10:05 2001 @@ -0,0 +1,173 @@ +/* + Sending Msg through Network + + Copyright 1999, 2000 by Xie Huagang ( xhg@gem.ncic.ac.cn). + + This file is part of the Linux Intrusion Detection System. + + 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. + + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +struct lids_net_val { + char * name; + void (*setup_func)(char *) ; +}; +char lids_mail_source[64],lids_mail_from[64], + lids_mail_to[64],lids_mail_subject[1024]; +char lids_rcpt_to[64],lids_s_from[64]; + +int lids_mail_switch; +unsigned long int lids_mail_relay,lids_mail_port; + +static void lids_mail_switch_setup(char *str) +{ + while(*str==' '||*str == '\r') str++; + lids_mail_switch=simple_strtoul(str,NULL,0); + printk(" Mail Switch is %s\n",lids_mail_switch?"on":"off"); +} +static void lids_mail_source_setup(char *str) +{ + sprintf(lids_mail_source,"ehlo %s \r\n",str); +} + +static void lids_mail_from_setup(char *str) +{ + sprintf(lids_mail_from,"mail from:<%s>\r\n",str); + strcpy(lids_s_from,str); +} +static void lids_mail_to_setup(char *str) +{ + sprintf(lids_rcpt_to,"rcpt to:<%s>\r\n",str); + strcpy(lids_mail_to,str); +} +static void lids_mail_subject_setup(char *str) +{ + sprintf(lids_mail_subject,"From: %s\r\nTo:%s\r\nSubject: %s\r\n\r\n",lids_s_from,lids_mail_to,str); +} +static void lids_mail_relay_setup(char *str) +{ + char *p; + + p = strchr(str,':'); + if(p == NULL) + lids_mail_port = 25; + else { + (*p) = '\0'; + lids_mail_port =simple_strtoul(p+1,NULL,0); + } + + lids_mail_relay = in_aton(str); + +} + +static struct lids_net_val lids_net_val[] = { + {"MAIL_SWITCH=",lids_mail_switch_setup}, + {"MAIL_SOURCE=",lids_mail_source_setup }, + {"MAIL_FROM=",lids_mail_from_setup}, + {"MAIL_TO=",lids_mail_to_setup}, + {"MAIL_SUBJECT=",lids_mail_subject_setup}, + {"MAIL_RELAY=",lids_mail_relay_setup}, + {NULL,NULL} +}; +/* + * lids network initial working + */ +int lids_net_init(char *line) +{ + int i,n; + + /* now split the name and value */ + for(i=0;lids_net_val[i].name;i++) { + n = strlen(lids_net_val[i].name); + if(!strncmp(line,lids_net_val[i].name,n)) { + lids_net_val[i].setup_func(line+n); + } + } + return 0; +} +int lids_read_net(void) +{ + struct file *filp; + char buffer[1024], *p,*q; + mm_segment_t oldfs; + int bytes; + int error =0; + + filp = filp_open("/etc/lids/lids.net",O_RDONLY,O_RDONLY); + if (IS_ERR(filp)||(filp==NULL)) { + error = -1 ; + printk("LIDS: Checking net file error,does it exist?\n"); + /* FIXME: if (lids_load) goto err_panic; */ + return error; + } + + if (filp->f_op->read==NULL) { + fput(filp); + error = -3 ; + printk("LIDS: The file can not be read\n"); + /* + if (lids_load) goto err_panic ; + */ + return error; + } + + /* Now read 1024 bytes into buffer */ + filp->f_pos = 0; + oldfs = get_fs(); + set_fs(KERNEL_DS); + bytes = filp->f_op->read(filp,buffer,1024,&filp->f_pos); + set_fs(oldfs); + + q = buffer; + /* analyze the buffer */ + while(bytes&&(p=memscan(q,'\n',bytes))!=q+bytes) + { + *p++='\0'; + /* + printk("read_file : line=->%s<-\n",q); + */ + bytes-=(int)(p-q); + while(*q=='\r')q++; /* hmmm... */ + if(*q&&*q!='#') if ( lids_net_init(q) < 0) + { + error = -5; + printk("LIDS: error in adding [%s] to the kernel\n",q); + break; + } + q=p; + } + + /* Close the file */ + fput(filp); + return error; +} diff -urN linux/kernel/lids_syslog_script.c linux/kernel/lids_syslog_script.c --- linux/kernel/lids_syslog_script.c Wed Dec 31 16:00:00 1969 +++ linux/kernel/lids_syslog_script.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,20 @@ +/* + * Log LIDS security alerts to a remote syslog + * + * Philippe Biondi (philippe.biondi@webmotion.com) + * March 29, 2000 + * + */ + + +/* + * This is a pseudo scripting language + * It is in fact directly included in the C source of + * klids.c by the cpp. + * + */ + + +lids_send(LIDS_MESSAGE); + + diff -urN linux/kernel/rmd160.c linux/kernel/rmd160.c --- linux/kernel/rmd160.c Wed Dec 31 16:00:00 1969 +++ linux/kernel/rmd160.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,315 @@ +/********************************************************************\ + * + * FILE: rmd160.c + * + * CONTENTS: A sample C-implementation of the RIPEMD-160 + * hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * +\********************************************************************/ + +/* header files */ +#include "linux/string.h" +#include "linux/rmd160.h" + +/********************************************************************/ + +void MDinit(dword *MDbuf) +{ + MDbuf[0] = 0x67452301UL; + MDbuf[1] = 0xefcdab89UL; + MDbuf[2] = 0x98badcfeUL; + MDbuf[3] = 0x10325476UL; + MDbuf[4] = 0xc3d2e1f0UL; + + return; +} + +/********************************************************************/ + +void compress(dword *MDbuf, dword *X) +{ + dword aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], + dd = MDbuf[3], ee = MDbuf[4]; + dword aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], + ddd = MDbuf[3], eee = MDbuf[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[ 0], 11); + FF(ee, aa, bb, cc, dd, X[ 1], 14); + FF(dd, ee, aa, bb, cc, X[ 2], 15); + FF(cc, dd, ee, aa, bb, X[ 3], 12); + FF(bb, cc, dd, ee, aa, X[ 4], 5); + FF(aa, bb, cc, dd, ee, X[ 5], 8); + FF(ee, aa, bb, cc, dd, X[ 6], 7); + FF(dd, ee, aa, bb, cc, X[ 7], 9); + FF(cc, dd, ee, aa, bb, X[ 8], 11); + FF(bb, cc, dd, ee, aa, X[ 9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[ 7], 7); + GG(dd, ee, aa, bb, cc, X[ 4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[ 1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[ 6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[ 3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[ 0], 12); + GG(ee, aa, bb, cc, dd, X[ 9], 15); + GG(dd, ee, aa, bb, cc, X[ 5], 9); + GG(cc, dd, ee, aa, bb, X[ 2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[ 3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[ 4], 7); + HH(ee, aa, bb, cc, dd, X[ 9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[ 8], 13); + HH(bb, cc, dd, ee, aa, X[ 1], 15); + HH(aa, bb, cc, dd, ee, X[ 2], 14); + HH(ee, aa, bb, cc, dd, X[ 7], 8); + HH(dd, ee, aa, bb, cc, X[ 0], 13); + HH(cc, dd, ee, aa, bb, X[ 6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[ 5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[ 1], 11); + II(bb, cc, dd, ee, aa, X[ 9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[ 0], 14); + II(cc, dd, ee, aa, bb, X[ 8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[ 4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[ 3], 14); + II(cc, dd, ee, aa, bb, X[ 7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[ 5], 6); + II(dd, ee, aa, bb, cc, X[ 6], 5); + II(cc, dd, ee, aa, bb, X[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[ 4], 9); + JJ(aa, bb, cc, dd, ee, X[ 0], 15); + JJ(ee, aa, bb, cc, dd, X[ 5], 5); + JJ(dd, ee, aa, bb, cc, X[ 9], 11); + JJ(cc, dd, ee, aa, bb, X[ 7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[ 2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[ 1], 12); + JJ(bb, cc, dd, ee, aa, X[ 3], 13); + JJ(aa, bb, cc, dd, ee, X[ 8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[ 6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); + + /* combine results */ + ddd += cc + MDbuf[1]; /* final result for MDbuf[0] */ + MDbuf[1] = MDbuf[2] + dd + eee; + MDbuf[2] = MDbuf[3] + ee + aaa; + MDbuf[3] = MDbuf[4] + aa + bbb; + MDbuf[4] = MDbuf[0] + bb + ccc; + MDbuf[0] = ddd; + + return; +} + +/********************************************************************/ + +void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen) +{ + unsigned int i; /* counter */ + dword X[16]; /* message words */ + + memset(X, 0, 16*sizeof(dword)); + + /* put bytes from strptr into X */ + for (i=0; i<(lswlen&63); i++) { + /* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */ + X[i>>2] ^= (dword) *strptr++ << (8 * (i&3)); + } + + /* append the bit m_n == 1 */ + X[(lswlen>>2)&15] ^= (dword)1 << (8*(lswlen&3) + 7); + + if ((lswlen & 63) > 55) { + /* length goes to next block */ + compress(MDbuf, X); + memset(X, 0, 16*sizeof(dword)); + } + + /* append length in bits*/ + X[14] = lswlen << 3; + X[15] = (lswlen >> 29) | (mswlen << 3); + compress(MDbuf, X); + + return; +} + +/********************************************************************/ + +void RMD(byte *message,byte *hashcode) +/* + * Return hash in hascode variable. + * Need RMDSize/8 bytes. + */ +{ + dword MDbuf[RMDsize/32]; /* contains (A, B, C, D(, E)) */ + dword X[16]; /* current 16-word chunk */ + unsigned int i; /* counter */ + dword length; /* length in bytes of message */ + dword nbytes; /* # of bytes not yet processed */ + + /* initialize */ + MDinit(MDbuf); + length = (dword)strlen((char *)message); + + /* process message in 16-word chunks */ + for (nbytes=length; nbytes > 63; nbytes-=64) { + for (i=0; i<16; i++) { + X[i] = BYTES_TO_DWORD(message); + message += 4; + } + compress(MDbuf, X); + } /* length mod 64 bytes left */ + + /* finish: */ + MDfinish(MDbuf, message, length, 0); + + for (i=0; i>2]; /* implicit cast to byte */ + hashcode[i+1] = (MDbuf[i>>2] >> 8); /* extracts the 8 least */ + hashcode[i+2] = (MDbuf[i>>2] >> 16); /* significant bits. */ + hashcode[i+3] = (MDbuf[i>>2] >> 24); + } +} + + + + +/************************ end of file rmd160.c **********************/ + + + + + + + diff -urN linux/kernel/signal.c linux/kernel/signal.c --- linux/kernel/signal.c Wed Jan 3 20:45:26 2001 +++ linux/kernel/signal.c Sun Jun 3 06:22:35 2001 @@ -16,6 +16,16 @@ #include +#ifdef CONFIG_GRKERNSEC_CHROOT +extern struct task_struct *child_reaper; +#endif + +#ifdef CONFIG_LIDS +#include +extern int lids_local_pid; +extern pid_t lids_protected_pid[]; +extern int lids_last_pid; +#endif /* * SLAB caches for signal bits. */ @@ -518,7 +528,31 @@ ret = -EPERM; if (bad_signal(sig, info, t)) goto out_nolock; - +#ifdef CONFIG_GRKERNSEC_CHROOT + if( t->pid && current->pid && child_reaper && child_reaper->pid && current->fs && current->pid > 1 + && sig && + !( sig == SIGALRM || sig == SIGIO || + ((current->fs->root->d_inode->i_dev == + child_reaper->fs->root->d_inode->i_dev) && + (current->fs->root->d_inode->i_ino == + child_reaper->fs->root->d_inode->i_ino)) || + ((t->fs->root->d_inode->i_dev == + current->fs->root->d_inode->i_dev) && + (t->fs->root->d_inode->i_ino == + current->fs->root->d_inode->i_ino)) || + (t->pid == current->p_pptr->pid && sig == SIGCHLD) ) ) { + security_alert("denied signal %d out of chroot() jail (%.32s:%lu) of %d.%d " + "by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d) " + "to (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d)", + "denied signals in chroot()",sig,kdevname(current->fs->root->d_inode->i_dev), + current->fs->root->d_inode->i_ino,current->fs->root->d_inode->i_uid, + current->fs->root->d_inode->i_gid,current->comm,current->pid,current->uid, + current->euid,current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid,t->comm,t->pid,t->uid,t->euid,t->p_pptr->comm, + t->p_pptr->pid,t->p_pptr->uid,t->p_pptr->euid); + goto out_nolock; + } +#endif /* The null signal is a permissions and process existance probe. No signal is actually delivered. Same goes for zombies. */ ret = 0; @@ -528,6 +562,24 @@ spin_lock_irqsave(&t->sigmask_lock, flags); handle_stop_signal(sig, t); +#ifdef CONFIG_GRKERNSEC_SIGNAL + if((sig == SIGSEGV) || (sig == SIGILL) || (sig == SIGABRT) || (sig == SIGBUS)) { + if(t->pid == current->pid) { + security_alert("signal %d sent to (%.16s:%d), UID (%d), EUID (%d), " + "parent (%.16s:%d), UID (%d), EUID (%d)","signal warnings",sig, + t->comm,t->pid,t->uid,t->euid,t->p_pptr->comm,t->p_pptr->pid, + t->p_pptr->uid,t->p_pptr->euid); + } else { + security_alert("signal %d sent to (%.16s:%d), UID (%d), EUID (%d), " + "parent (%.16s:%d), UID (%d), EUID (%d) by (%.16s:%d), UID (%d), EUID (%d), " + "parent (%.16s:%d), UID (%d), EUID (%d)","signal warnings", + sig,t->comm,t->pid,t->uid,t->euid,t->p_pptr->comm,t->p_pptr->pid, + t->p_pptr->uid,t->p_pptr->euid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); + } + } +#endif /* Optimize away the signal, if it's a signal that can be handled immediately (ie non-blocked and untraced) and that is ignored (either explicitly or by default). */ @@ -980,6 +1032,23 @@ sys_kill(int pid, int sig) { struct siginfo info; + +#ifdef CONFIG_LIDS + pid_t this_pid; + int i; + + LIDS_DBG("cap_bset=%x,lids_cap=%x,pid=%d,cap_raised = %d \n",cap_bset,current->lids_cap,pid,cap_raised(current->lids_cap,CAP_INIT_KILL)); + if ( !(cap_raised(cap_bset,CAP_INIT_KILL) || cap_raised(current->lids_cap, CAP_INIT_KILL)) && lids_local_load && lids_load ) { + this_pid = pid>0?pid:-pid; + LIDS_DBG("try to kill pid=%d\n",this_pid); + for(i=0;i #include #include #include @@ -378,6 +379,12 @@ int old_egid = current->egid; int new_rgid = old_rgid; int new_egid = old_egid; +#ifdef CONFIG_GRKERNSEC_SUID + printk(KERN_INFO "GETREWTED SGID: setregid(rgid=%d/egid=%d) by (%.16s:%d),UID(%d), EUID(%d), parent (%.16s:%d), " + "UID(%d), EUID(%d)\n",rgid,egid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || @@ -419,6 +426,12 @@ asmlinkage long sys_setgid(gid_t gid) { int old_egid = current->egid; +#ifdef CONFIG_GRKERNSEC_SUID + printk(KERN_INFO "GETREWTED SGID: setgid(%d) by (%.16s:%d), UID(%d), EUID(%d), parent (%.16s:%d), " + "UID(%d), EUID(%d)\n",gid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif if (capable(CAP_SETGID)) { @@ -538,6 +551,12 @@ new_ruid = old_ruid = current->uid; new_euid = old_euid = current->euid; old_suid = current->suid; +#ifdef CONFIG_GRKERNSEC_SUID + printk(KERN_INFO "GETREWTED SUID: setreuid(ruid=%d/euid=%d) by (%.16s:%d), UID(%d), EUID(%d), parent (%.16s:%d), " + "UID(%d), EUID(%d)\n",ruid,euid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif if (ruid != (uid_t) -1) { new_ruid = ruid; @@ -598,7 +617,12 @@ old_ruid = new_ruid = current->uid; old_suid = current->suid; new_suid = old_suid; - +#ifdef CONFIG_GRKERNSEC_SUID + printk(KERN_INFO "GETREWTED SUID: setuid(%d) by (%.16s:%d), UID(%d), EUID(%d), parent (%.16s:%d), " + "UID(%d), EUID(%d)\n",uid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif if (capable(CAP_SETUID)) { if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) return -EAGAIN; @@ -631,6 +655,12 @@ int old_ruid = current->uid; int old_euid = current->euid; int old_suid = current->suid; +#ifdef CONFIG_GRKERNSEC_SUID + printk(KERN_INFO "GETREWTED SUID: setresuid(ruid=%d/suid=%d/euid=%d) by (%.16s:%d), UID(%d), EUID(%d), parent (%.16s:%d), " + "UID(%d), EUID(%d)\n",ruid,suid,euid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif if (!capable(CAP_SETUID)) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && @@ -682,6 +712,13 @@ */ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { +#ifdef CONFIG_GRKERNSEC_SUID + printk(KERN_INFO "GETREWTED SGID: setresgid(rgid=%d/sgid=%d/egid=%d) by (%.16s:%d), UID(%d), EUID(%d), parent (%.16s:%d), " + "UID(%d), EUID(%d)\n",rgid,sgid,egid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif + if (!capable(CAP_SETGID)) { if ((rgid != (gid_t) -1) && (rgid != current->gid) && (rgid != current->egid) && (rgid != current->sgid)) @@ -730,6 +767,12 @@ asmlinkage long sys_setfsuid(uid_t uid) { int old_fsuid; +#ifdef CONFIG_GRKERNSEC_SUID + printk(KERN_INFO "GETREWTED SUID: setfsuid(%d) by (%.16s:%d), UID(%d), EUID(%d), parent (%.16s:%d), " + "UID(%d), EUID(%d)\n",uid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif old_fsuid = current->fsuid; if (uid == current->uid || uid == current->euid || @@ -772,6 +815,12 @@ asmlinkage long sys_setfsgid(gid_t gid) { int old_fsgid; +#ifdef CONFIG_GRKERNSEC_SUID + printk(KERN_INFO "GETREWTED SGID: setfsgid(%d) by (%.16s:%d), UID(%d), EUID(%d), parent (%.16s:%d), " + "UID(%d), EUID(%d)\n",gid,current->comm,current->pid, + current->uid,current->euid,current->p_pptr->comm,current->p_pptr->pid, + current->p_pptr->uid,current->p_pptr->euid); +#endif old_fsgid = current->fsgid; if (gid == current->gid || gid == current->egid || diff -urN linux/kernel/sysctl.c linux/kernel/sysctl.c --- linux/kernel/sysctl.c Thu Apr 12 12:20:31 2001 +++ linux/kernel/sysctl.c Sun Jun 3 06:22:35 2001 @@ -38,7 +38,9 @@ #endif #if defined(CONFIG_SYSCTL) - +#ifdef CONFIG_LIDS +#include +#endif /* External variables not in a header file. */ extern int panic_timeout; extern int C_A_D; @@ -114,6 +116,9 @@ static ctl_table debug_table[]; static ctl_table dev_table[]; extern ctl_table random_table[]; +#ifdef CONFIG_LIDS +extern ctl_table lids_table[]; +#endif /* /proc declarations: */ @@ -150,6 +155,9 @@ {CTL_FS, "fs", NULL, 0, 0555, fs_table}, {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table}, {CTL_DEV, "dev", NULL, 0, 0555, dev_table}, +#ifdef CONFIG_LIDS + {CTL_LIDS,"lids",NULL,0,0500,lids_table}, +#endif {0} }; @@ -319,6 +327,14 @@ {0} }; +#ifdef CONFIG_LIDS +static ctl_table lids_table[] = { + {LIDS_LOCKS, "locks", + NULL, sizeof(int), 0600, NULL, &lids_proc_locks_sysctl}, + {0} +}; +#endif + extern void init_irq_proc (void); void __init sysctl_init(void) @@ -931,8 +947,17 @@ */ int proc_dointvec(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) -{ +{ +#ifdef CONFIG_LIDS + if (!write || (capable(CAP_SYS_ADMIN))) + return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET); + else { + lids_security_alert("Try to write in sysctl %s",table->procname); + return -EACCES; + } +#else return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET); +#endif } /* @@ -942,6 +967,12 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) { +#ifdef CONFIG_LIDS + if(write) { + lids_security_alert("Try to modify capabilities boundig set"); + return -EPERM; + } +#endif if (!capable(CAP_SYS_MODULE)) { return -EPERM; } @@ -973,6 +1004,13 @@ #define TMPBUFLEN 20 char buf[TMPBUFLEN], *p; +#ifdef CONFIG_LIDS + if (write && !capable(CAP_SYS_ADMIN)) { + lids_security_alert("try to write in sysctl %s",table->procname); + return -EACCES; + } +#endif + if (!table->data || !table->maxlen || !*lenp || (filp->f_pos && !write)) { *lenp = 0; @@ -1236,7 +1274,16 @@ int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) { +#ifdef CONFIG_LIDS + if (!write || capable(CAP_SYS_ADMIN)) + return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET); + else { + lids_security_alert("try to write in sysctl %s",table->procname); + return -EACCES; + } +#else return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET); +#endif } #else /* CONFIG_PROC_FS */ diff -urN linux/kernel/time.c linux/kernel/time.c --- linux/kernel/time.c Mon Oct 16 12:58:51 2000 +++ linux/kernel/time.c Sun Jun 3 06:22:35 2001 @@ -105,6 +105,12 @@ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; write_unlock_irq(&xtime_lock); +#ifdef CONFIG_GRKERNSEC_TIME + security_alert("time set by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d)", + "time sets", current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); +#endif return 0; } @@ -181,6 +187,12 @@ * globally block out interrupts when it runs. */ do_settimeofday(tv); +#ifdef CONFIG_GRKERNSEC_TIME + security_alert("time set by (%.16s:%d), UID (%d), EUID (%d), parent (%.16s:%d), UID (%d), EUID (%d)", + "time sets", current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); +#endif } return 0; } diff -urN linux/mm/mmap.c linux/mm/mmap.c --- linux/mm/mmap.c Thu May 24 15:20:18 2001 +++ linux/mm/mmap.c Sun Jun 3 06:22:35 2001 @@ -196,6 +196,10 @@ _trans(prot, PROT_READ, VM_READ) | _trans(prot, PROT_WRITE, VM_WRITE) | _trans(prot, PROT_EXEC, VM_EXEC); +#ifdef CONFIG_GRKERNSEC_PAX + prot_bits |= + _trans(prot, PROT_EXEC, VM_MAYEXEC); +#endif flag_bits = _trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) | _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) | @@ -241,7 +245,11 @@ * to. we assume access permissions have been handled by the open * of the memory object, so we don't do any here. */ +#ifdef CONFIG_GRKERNSEC_PAX + vm_flags = calc_vm_flags(prot,flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE; +#else vm_flags = calc_vm_flags(prot,flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; +#endif /* mlock MCL_FUTURE? */ if (vm_flags & VM_LOCKED) { @@ -406,7 +414,11 @@ if (len > TASK_SIZE) return -ENOMEM; if (!addr) - addr = TASK_UNMAPPED_BASE; +#ifdef CONFIG_GRKERNSEC_STACK + addr = TASK_UNMAPPED_BASE(len); +#else + addr = TASK_UNMAPPED_BASE; +#endif addr = PAGE_ALIGN(addr); for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { @@ -854,10 +866,18 @@ if (!vm_enough_memory(len >> PAGE_SHIFT)) return -ENOMEM; +#ifdef CONFIG_GRKERNSEC_PAX + flags = calc_vm_flags(PROT_READ|PROT_WRITE, +#else flags = calc_vm_flags(PROT_READ|PROT_WRITE|PROT_EXEC, +#endif MAP_FIXED|MAP_PRIVATE) | mm->def_flags; +#ifdef CONFIG_GRKERNSEC_PAX + flags |= VM_MAYREAD | VM_MAYWRITE; +#else flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; +#endif /* Can we just expand an old anonymous mapping? */ if (addr) { diff -urN linux/mm/mprotect.c linux/mm/mprotect.c --- linux/mm/mprotect.c Mon Mar 19 12:35:08 2001 +++ linux/mm/mprotect.c Sun Jun 3 06:22:35 2001 @@ -260,7 +260,12 @@ error = -EACCES; break; } - +#ifdef CONFIG_GRKERNSEC_PAX +/* PaX: disallow write access after relocs are done, hopefully noone else needs it... */ + if ((prot & PROT_WRITE) && (vma->vm_flags & VM_MAYEXEC)) { + newflags &= ~VM_MAYWRITE; + } +#endif if (vma->vm_end >= end) { error = mprotect_fixup(vma, nstart, end, newflags); break; diff -urN linux/net/core/dev.c linux/net/core/dev.c --- linux/net/core/dev.c Sat May 19 18:11:49 2001 +++ linux/net/core/dev.c Sun Jun 3 06:22:35 2001 @@ -2781,7 +2781,23 @@ dp = &dev->next; } } - +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP +#ifdef CONFIG_PROC_FS + proc_net_create("dev", S_IRUSR|S_IRGRP, dev_get_info); + create_proc_read_entry("net/softnet_stat", S_IRUSR|S_IRGRP, 0, dev_proc_stats, NULL); +#ifdef WIRELESS_EXT + proc_net_create("wireless", S_IRUSR|S_IRGRP, dev_get_wireless_info); +#endif /* WIRELESS_EXT */ +#endif /* CONFIG_PROC_FS */ +#elif CONFIG_GRKERNSEC_PROC_USER +#ifdef CONFIG_PROC_FS + proc_net_create("dev", S_IRUSR, dev_get_info); + create_proc_read_entry("net/softnet_stat", S_IRUSR, 0, dev_proc_stats, NULL); +#ifdef WIRELESS_EXT + proc_net_create("wireless", S_IRUSR, dev_get_wireless_info); +#endif /* WIRELESS_EXT */ +#endif /* CONFIG_PROC_FS */ +#else #ifdef CONFIG_PROC_FS proc_net_create("dev", 0, dev_get_info); create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL); @@ -2789,7 +2805,7 @@ proc_net_create("wireless", 0, dev_get_wireless_info); #endif /* WIRELESS_EXT */ #endif /* CONFIG_PROC_FS */ - +#endif dev_boot_phase = 0; open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); diff -urN linux/net/core/netfilter.c linux/net/core/netfilter.c --- linux/net/core/netfilter.c Fri Apr 27 14:15:01 2001 +++ linux/net/core/netfilter.c Sun Jun 3 06:22:35 2001 @@ -559,6 +559,14 @@ with it. */ void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *); +/* Embodyment of drop the packet fn for NF_HOOK() (sometimes this + address is taken) */ +int nf_drop_okfn(struct sk_buff *skb) +{ + kfree_skb(skb); + return 0; +} + void __init netfilter_init(void) { int i, h; diff -urN linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c --- linux/net/core/rtnetlink.c Sun Feb 27 18:45:10 2000 +++ linux/net/core/rtnetlink.c Sun Jun 3 06:22:35 2001 @@ -50,6 +50,9 @@ #include #include +#ifdef CONFIG_LIDS +#include +#endif DECLARE_MUTEX(rtnl_sem); void rtnl_lock(void) @@ -322,7 +325,12 @@ sz_idx = type>>2; kind = type&3; +#ifdef CONFIG_LIDS + if (kind != 2 && !cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN) && !cap_raised(current->lids_cap, CAP_NET_ADMIN) && lids_load && lids_local_load) { + lids_security_alert("NETLINK violate CAP_NET_ADMIN"); +#else if (kind != 2 && !cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) { +#endif *errp = -EPERM; return -1; } diff -urN linux/net/core/utils.c linux/net/core/utils.c --- linux/net/core/utils.c Mon Aug 23 10:01:02 1999 +++ linux/net/core/utils.c Sun Jun 3 06:22:35 2001 @@ -20,19 +20,32 @@ #include #include #include - +#ifndef CONFIG_GRKERNSEC_RANDNET static unsigned long net_rand_seed = 152L; +#else +#include +#endif unsigned long net_random(void) { +#ifdef CONFIG_GRKERNSEC_RANDNET + unsigned long dummy; + get_random_bytes (&dummy, sizeof(dummy)); + return dummy; +#else net_rand_seed=net_rand_seed*69069L+1; return net_rand_seed^jiffies; +#endif } void net_srandom(unsigned long entropy) { +#ifdef CONFIG_GRKERNSEC_RANDNET + add_mouse_randomness((__u32)entropy); +#else net_rand_seed ^= entropy; net_random(); +#endif } int net_msg_cost = 5*HZ; diff -urN linux/net/ipv4/Makefile linux/net/ipv4/Makefile --- linux/net/ipv4/Makefile Fri Dec 29 14:07:24 2000 +++ linux/net/ipv4/Makefile Sun Jun 3 06:22:35 2001 @@ -25,6 +25,7 @@ obj-$(CONFIG_NET_IPGRE) += ip_gre.o obj-$(CONFIG_SYN_COOKIES) += syncookies.o obj-$(CONFIG_IP_PNP) += ipconfig.o +obj-$(CONFIG_LIDS_PORT_SCAN_DETECTOR) += lids_check_scan.o include $(TOPDIR)/Rules.make diff -urN linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- linux/net/ipv4/af_inet.c Tue May 1 20:59:24 2001 +++ linux/net/ipv4/af_inet.c Sun Jun 3 06:22:35 2001 @@ -1048,6 +1048,25 @@ /* * Create all the /proc entries. */ +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP +#ifdef CONFIG_PROC_FS + proc_net_create ("raw", S_IRUSR|S_IRGRP, raw_get_info); + proc_net_create ("netstat", S_IRUSR|S_IRGRP, netstat_get_info); + proc_net_create ("snmp", S_IRUSR|S_IRGRP, snmp_get_info); + proc_net_create ("sockstat", S_IRUSR|S_IRGRP, afinet_get_info); + proc_net_create ("tcp", S_IRUSR|S_IRGRP, tcp_get_info); + proc_net_create ("udp", S_IRUSR|S_IRGRP, udp_get_info); +#endif +#elif CONFIG_GRKERNSEC_PROC_USER +#ifdef CONFIG_PROC_FS + proc_net_create ("raw", S_IRUSR, raw_get_info); + proc_net_create ("netstat", S_IRUSR, netstat_get_info); + proc_net_create ("snmp", S_IRUSR, snmp_get_info); + proc_net_create ("sockstat", S_IRUSR, afinet_get_info); + proc_net_create ("tcp", S_IRUSR, tcp_get_info); + proc_net_create ("udp", S_IRUSR, udp_get_info); +#endif +#else #ifdef CONFIG_PROC_FS proc_net_create ("raw", 0, raw_get_info); proc_net_create ("netstat", 0, netstat_get_info); @@ -1055,6 +1074,7 @@ proc_net_create ("sockstat", 0, afinet_get_info); proc_net_create ("tcp", 0, tcp_get_info); proc_net_create ("udp", 0, udp_get_info); +#endif #endif /* CONFIG_PROC_FS */ return 0; } diff -urN linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- linux/net/ipv4/arp.c Wed May 16 10:21:45 2001 +++ linux/net/ipv4/arp.c Sun Jun 3 06:22:35 2001 @@ -1196,8 +1196,13 @@ neigh_table_init(&arp_tbl); dev_add_pack(&arp_packet_type); - +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + proc_net_create ("arp", S_IRUSR|S_IRGRP, arp_get_info); +#elif CONFIG_GRKERNSEC_PROC_USER + proc_net_create ("arp", S_IRUSR, arp_get_info); +#else proc_net_create ("arp", 0, arp_get_info); +#endif #ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4"); diff -urN linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- linux/net/ipv4/fib_frontend.c Wed May 16 10:31:23 2001 +++ linux/net/ipv4/fib_frontend.c Sun Jun 3 06:22:35 2001 @@ -643,9 +643,19 @@ void __init ip_fib_init(void) { +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP +#ifdef CONFIG_PROC_FS + proc_net_create("route",S_IRUSR|S_IRGRP,fib_get_procinfo); +#endif /* CONFIG_PROC_FS */ +#elif CONFIG_GRKERNSEC_PROC_USER +#ifdef CONFIG_PROC_FS + proc_net_create("route",S_IRUSR,fib_get_procinfo); +#endif /* CONFIG_PROC_FS */ +#else #ifdef CONFIG_PROC_FS proc_net_create("route",0,fib_get_procinfo); #endif /* CONFIG_PROC_FS */ +#endif #ifndef CONFIG_IP_MULTIPLE_TABLES local_table = fib_hash_init(RT_TABLE_LOCAL); diff -urN linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- linux/net/ipv4/icmp.c Wed May 16 10:31:26 2001 +++ linux/net/ipv4/icmp.c Sun Jun 3 06:22:35 2001 @@ -732,7 +732,9 @@ icmp_param.offset=0; icmp_param.data_len=skb->len; icmp_param.head_len=sizeof(struct icmphdr); +#ifndef CONFIG_GRKERNSEC_STEALTH_ICMP icmp_reply(&icmp_param, skb); +#endif } } @@ -773,7 +775,9 @@ icmp_param.offset=0; icmp_param.data_len=0; icmp_param.head_len=sizeof(struct icmphdr)+12; +#ifndef CONFIG_GRKERNSEC_STEALTH_ICMP icmp_reply(&icmp_param, skb); +#endif } diff -urN linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- linux/net/ipv4/igmp.c Thu Apr 12 12:11:39 2001 +++ linux/net/ipv4/igmp.c Sun Jun 3 06:22:35 2001 @@ -199,7 +199,9 @@ struct igmphdr *ih; struct rtable *rt; u32 dst; - +#ifdef CONFIG_GRKERNSEC_STEALTH_IGMP + return(-1); +#endif /* According to IGMPv2 specs, LEAVE messages are * sent to all-routers group. */ diff -urN linux/net/ipv4/inetpeer.c linux/net/ipv4/inetpeer.c --- linux/net/ipv4/inetpeer.c Tue Oct 10 10:33:52 2000 +++ linux/net/ipv4/inetpeer.c Sun Jun 3 06:22:35 2001 @@ -390,7 +390,9 @@ return NULL; n->v4daddr = daddr; atomic_set(&n->refcnt, 1); +#ifndef CONFIG_GRKERNSEC_RANDID n->ip_id_count = secure_ip_id(daddr); +#endif n->tcp_ts_stamp = 0; write_lock_bh(&peer_pool_lock); diff -urN linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- linux/net/ipv4/ip_output.c Thu Apr 12 12:11:39 2001 +++ linux/net/ipv4/ip_output.c Sun Jun 3 06:22:35 2001 @@ -990,7 +990,17 @@ ip_rt_init(); inet_initpeers(); +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP +#ifdef CONFIG_IP_MULTICAST + proc_net_create("igmp", S_IRUSR|S_IRGRP, ip_mc_procinfo); +#endif +#elif CONFIG_GRKERNSEC_PROC_USER +#ifdef CONFIG_IP_MULTICAST + proc_net_create("igmp", S_IRUSR, ip_mc_procinfo); +#endif +#else #ifdef CONFIG_IP_MULTICAST proc_net_create("igmp", 0, ip_mc_procinfo); +#endif #endif } diff -urN linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- linux/net/ipv4/ipmr.c Thu Apr 12 12:11:39 2001 +++ linux/net/ipv4/ipmr.c Sun Jun 3 06:22:35 2001 @@ -1761,8 +1761,20 @@ init_timer(&ipmr_expire_timer); ipmr_expire_timer.function=ipmr_expire_process; register_netdevice_notifier(&ip_mr_notifier); +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP +#ifdef CONFIG_PROC_FS + proc_net_create("ip_mr_vif",S_IRUSR|S_IRGRP,ipmr_vif_info); + proc_net_create("ip_mr_cache",S_IRUSR|S_IRGRP,ipmr_mfc_info); +#endif +#elif CONFIG_GRKERNSEC_PROC_USER +#ifdef CONFIG_PROC_FS + proc_net_create("ip_mr_vif",S_IRUSR,ipmr_vif_info); + proc_net_create("ip_mr_cache",S_IRUSR,ipmr_mfc_info); +#endif +#else #ifdef CONFIG_PROC_FS proc_net_create("ip_mr_vif",0,ipmr_vif_info); proc_net_create("ip_mr_cache",0,ipmr_mfc_info); #endif +#endif } diff -urN linux/net/ipv4/lids_check_scan.c linux/net/ipv4/lids_check_scan.c --- linux/net/ipv4/lids_check_scan.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/lids_check_scan.c Sun Jun 3 06:51:02 2001 @@ -0,0 +1,171 @@ +/* + linux/net/ipv4/lids_check_scan.c + + Copy right by Huagang Xie(xhg@gnuchina.org) for LIDS Project + + 200.5.17 add some pointer checkers. + 2000.5.6 fixed some condition contest. + 2000.4.3 initially released +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + + + +#define LIDS_WARNING 10 +#define LIDS_SCAN_TIMEOUT 3*HZ +#define LIDS_SCAN_TIME 10*HZ + +struct lids_scan +{ + struct lids_scan *next,*pre; + __u32 addr; + unsigned long counter; + unsigned long lower_counter; + unsigned long create_time; + spinlock_t lock; + struct timer_list timer; +}lids_scan_head; + +void free_scan(struct lids_scan *p) +{ + LIDS_DBG("free %d.%d.%d.%d",NIPQUAD(p->addr)); + del_timer(&(p->timer)); + + spin_lock(&(p->lock)); + spin_lock(&(p->pre->lock)); + p->pre->next = p->next; + spin_unlock(&(p->pre->lock)); + if(p->next) { + spin_lock(&(p->next->lock)); + p->next->pre = p->pre; + spin_unlock(&(p->next->lock)); + } + spin_unlock(&(p->lock)); + + kfree(p); + LIDS_DBG("out"); +} +/* + * + */ +static void lids_proceed_scan(unsigned long __data) +{ + struct lids_scan *p=(struct lids_scan *)__data; + unsigned long current_time = jiffies; + unsigned long counter; + unsigned long lower_counter; + __u32 addr; + + + if(p) { + if(p->counter > LIDS_WARNING ) { + addr=p->addr; + counter=p->counter; + lower_counter=p->lower_counter; + + lids_security_alert("Port scan detected: %d.%d.%d.%d scanned %ld closed ports including %ld ports < 1024)", NIPQUAD(addr),counter, lower_counter); + free_scan(p); + } + else { + if(current_time - p->create_time > LIDS_SCAN_TIME) + free_scan(p); + else + mod_timer(&(p->timer), LIDS_SCAN_TIMEOUT+current_time); + } + } + LIDS_DBG("exit"); +} +/* + * + */ +struct lids_scan * lids_find_scan(__u32 addr) +{ + struct lids_scan *p ; + + LIDS_DBG("checking %d.%d.%d.%d\n",NIPQUAD(addr)); + + for(p=lids_scan_head.next;p!=NULL;p=p->next) { + LIDS_DBG("searching exist: %d.%d.%d.%d\n",NIPQUAD(p->addr)); + if(p->addr == addr) { + LIDS_DBG("exit from return not NULL"); + return p; + } + } + + LIDS_DBG("exit from return NULL"); + return NULL; +} +/* + * lids_check_scan ... + */ +int lids_check_scan(__u32 addr,__u16 port) +{ + struct lids_scan *p,*p1; + unsigned long current_time=jiffies; + + LIDS_DBG("%d.%d.%d.%d : %d\n",NIPQUAD(addr),port); + if((p = lids_find_scan(addr)) == NULL) { + + p1 = &lids_scan_head; + p = (struct lids_scan*)kmalloc(sizeof(struct lids_scan),GFP_ATOMIC); + if(p == NULL ) { + LIDS_DBG("kmalloc error, return -1"); + return -1; + } + spin_lock_init(&(p->lock)); + + while((p1->next)!=NULL)p1=p1->next; + + spin_lock(&(p1->lock)); + p1->next = p; + spin_unlock(&(p1->lock)); + + spin_lock(&(p->lock)); + p->pre = p1; + spin_unlock(&(p->lock)); + + p->next = NULL; + p->addr = addr; + p->counter = 0; + p->lower_counter = 0; + p->create_time = current_time; + + init_timer(&(p->timer)); + p->timer.expires = LIDS_SCAN_TIMEOUT + current_time; + p->timer.data = (unsigned long) p; + p->timer.function = &lids_proceed_scan; + add_timer(&(p->timer)); + } + spin_lock(&(p->lock)); + (p->counter)++; + if(port < 1024) + (p->lower_counter)++; + spin_unlock(&(p->lock)); + LIDS_DBG("exit return 0"); + return 0; +} +void lids_port_scanner_detector_init(void) +{ + static int initialized=0; + if(!initialized)spin_lock_init(&(lids_scan_head.lock)); + initialized=1; +} diff -urN linux/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in --- linux/net/ipv4/netfilter/Config.in Tue Mar 6 22:44:16 2001 +++ linux/net/ipv4/netfilter/Config.in Sun Jun 3 06:22:35 2001 @@ -7,6 +7,8 @@ tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK + dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK + dep_tristate ' Eggdrop bot support' CONFIG_IP_NF_EGG $CONFIG_IP_NF_CONNTRACK fi if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NETLINK" = "y" ]; then @@ -20,12 +22,18 @@ dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES + dep_tristate ' TIME match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_TIME $CONFIG_IP_NF_IPTABLES + dep_tristate ' PSD match support' CONFIG_IP_NF_MATCH_PSD $CONFIG_IP_NF_IPTABLES + dep_tristate ' LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES + dep_tristate ' IPV4OPTIONS match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_IPV4OPTIONS $CONFIG_IP_NF_IPTABLES dep_tristate ' tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then dep_tristate ' Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES + dep_tristate ' Connections/IP limit match support' CONFIG_IP_NF_MATCH_IPLIMIT $CONFIG_IP_NF_IPTABLES fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES + dep_tristate ' String match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_STRING $CONFIG_IP_NF_IPTABLES dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES fi # The targets @@ -43,6 +51,13 @@ define_bool CONFIG_IP_NF_NAT_NEEDED y dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT + if [ "$CONFIG_IP_NF_IRC" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_IRC m + else + if [ "$CONFIG_IP_NF_IRC" = "y" ]; then + define_tristate CONFIG_IP_NF_NAT_IRC $CONFIG_IP_NF_NAT + fi + fi # If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), # or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh. if [ "$CONFIG_IP_NF_FTP" = "m" ]; then @@ -61,6 +76,7 @@ dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE fi dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES + dep_tristate ' Packet drop table' CONFIG_IP_NF_DROPTABLE $CONFIG_IP_NF_IPTABLES dep_tristate ' TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES fi diff -urN linux/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile --- linux/net/ipv4/netfilter/Makefile Wed Apr 25 15:00:28 2001 +++ linux/net/ipv4/netfilter/Makefile Sun Jun 3 06:22:35 2001 @@ -31,8 +31,14 @@ # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o +# IRC support +obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o +obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o + # connection tracking helpers obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o +obj-$(CONFIG_IP_NF_EGG) += ip_conntrack_egg.o + # NAT helpers obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o @@ -43,6 +49,7 @@ # the three instances of ip_tables obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o +obj-$(CONFIG_IP_NF_DROPTABLE) += iptable_drop.o obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o # matches @@ -52,8 +59,21 @@ obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o + +obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o + + +obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o + +obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o + + +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o + obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o +obj-$(CONFIG_IP_NF_MATCH_IPLIMIT) += ipt_iplimit.o obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o +obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o # targets diff -urN linux/net/ipv4/netfilter/ip_conntrack_egg.c linux/net/ipv4/netfilter/ip_conntrack_egg.c --- linux/net/ipv4/netfilter/ip_conntrack_egg.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ip_conntrack_egg.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,224 @@ +/* Eggdrop extension for IP connection tracking, Version 0.0.2 + * based on ip_conntrack_irc.c + * + * This module only supports the share userfile-send command, + * used by eggdrops to share it's userfile. + * + * There are no support for NAT at the moment. + * + * 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. + * + * Module load syntax: + * + * please give the ports of all Eggdrops You have running + * on your system, the default port is 3333. + * + * 2001-04-19: Security update. IP addresses are now compared + * to prevent unauthorized "related" access. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +MODULE_AUTHOR("Magnus Sandin "); +MODULE_DESCRIPTION("Eggdrop (userfile-sharing) connection tracking module"); +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of eggdrop servers"); +#endif + +DECLARE_LOCK(ip_egg_lock); +struct module *ip_conntrack_egg = THIS_MODULE; + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +int parse_command(char *data, char *data_end, u_int32_t * ip, u_int16_t * port) +/* tries to get the ip_addr and port out of a eggdrop command + return value: -1 on failure, 0 on success + data pointer to first byte of DCC command data + data_end pointer to last byte of dcc command data + ip returns parsed ip of dcc command + port returns parsed port of dcc command */ +{ + + if (data > data_end) + return -1; + + *ip = simple_strtoul(data, &data, 10); + + /* skip blanks between ip and port */ + while (*data == ' ' && data < data_end) + data++; + + *port = simple_strtoul(data, &data, 10); + + return 0; +} + + +/* FIXME: This should be in userspace. Later. */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + char *data = (char *) tcph + tcph->doff * 4; + char *data_limit; + u_int32_t tcplen = len - iph->ihl * 4; + u_int32_t datalen = tcplen - tcph->doff * 4; + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_tuple t, mask; + + u_int32_t egg_ip; + u_int16_t egg_port; + + memset(&mask, 0, sizeof(struct ip_conntrack_tuple)); + mask.dst.u.tcp.port = 0xFFFF; + mask.dst.protonum = 0xFFFF; + + DEBUGP("ip_ct_egg: help entered\n"); + + /* If packet is coming from IRC server */ + if (dir != IP_CT_DIR_REPLY) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("ip_ct_egg: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { + DEBUGP("ip_ct_egg: tcplen = %u\n", (unsigned) tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + DEBUGP ("ip_ct_egg: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + data_limit = (char *) data + datalen; + if (datalen > 5) { + if (memcmp(data, "s us ", 5)) { + return NF_ACCEPT;; + } + + data += 5; + + DEBUGP ("ip_ct_egg: Userfile-share found in connection %u.%u.%u.%u %u.%u.%u.%u\n", + NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + + if (parse_command + ((char *) data, data_limit, &egg_ip, + &egg_port)) { + DEBUGP ("ip_ct_egg: Didn't find any data in the Userfile-share packet\n"); + return NF_ACCEPT; + } + + memset(&t, 0, sizeof(t)); + t.src.ip = iph->daddr; + t.src.u.tcp.port = 0; + t.dst.ip = htonl(egg_ip); + t.dst.u.tcp.port = htons(egg_port); + t.dst.protonum = IPPROTO_TCP; + + if (ct->tuplehash[dir].tuple.src.ip != htonl(egg_ip)) { + if (net_ratelimit()) + printk("Forged Eggdrop command from " + "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + HIPQUAD(egg_ip), egg_port); + return NF_ACCEPT; + } + + DEBUGP ("ip_ct_egg: expect_related %u.%u.%u.%u:%u - %u.%u.%u.%u:%u\n", + NIPQUAD(t.src.ip), + ntohs(t.src.u.tcp.port), + NIPQUAD(t.dst.ip), + ntohs(t.dst.u.tcp.port)); + + ip_conntrack_expect_related(ct, &t, + &mask, + NULL); + } + return NF_ACCEPT; +} + +static struct ip_conntrack_helper egg_helpers[MAX_PORTS]; + +static void __exit fini(void); + +static int __init init(void) +{ + int i, ret; + + /* If no port given, default to standard eggdrop port */ + if (ports[0] == 0) + ports[0] = 3333; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + memset(&egg_helpers[i], 0, + sizeof(struct ip_conntrack_helper)); + egg_helpers[i].tuple.src.u.tcp.port = htons(ports[i]); + egg_helpers[i].tuple.dst.protonum = IPPROTO_TCP; + egg_helpers[i].mask.src.u.tcp.port = 0xFFFF; + egg_helpers[i].mask.dst.protonum = 0xFFFF; + egg_helpers[i].help = help; + + DEBUGP("ip_ct_egg: port #%d: %d\n", i, ports[i]); + + ret = ip_conntrack_helper_register(&egg_helpers[i]); + + if (ret) { + printk("ip_ct_egg: ERROR registering port %d\n", + ports[i]); + fini(); + return 1; + } + ports_n_c++; + } + return 0; +} + +static void __exit fini(void) +{ + int i; + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + DEBUGP("ip_ct_egg: unregistering port %d\n", + ports[i]); + ip_conntrack_helper_unregister(&egg_helpers[i]); + } +} + +module_init(init); +module_exit(fini); + + + + diff -urN linux/net/ipv4/netfilter/ip_conntrack_ftp.c linux/net/ipv4/netfilter/ip_conntrack_ftp.c --- linux/net/ipv4/netfilter/ip_conntrack_ftp.c Wed Apr 25 15:02:09 2001 +++ linux/net/ipv4/netfilter/ip_conntrack_ftp.c Sun Jun 3 06:22:35 2001 @@ -335,7 +335,7 @@ LOCK_BH(&ip_ftp_lock); if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]) == ct->tuplehash[dir].tuple.src.ip) { - info->is_ftp = 1; + info->is_ftp = 21; info->seq = ntohl(tcph->seq) + matchoff; info->len = matchlen; info->ftptype = search[i].ftptype; diff -urN linux/net/ipv4/netfilter/ip_conntrack_irc.c linux/net/ipv4/netfilter/ip_conntrack_irc.c --- linux/net/ipv4/netfilter/ip_conntrack_irc.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ip_conntrack_irc.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,276 @@ +/* IRC extension for IP connection tracking, Version 1.17 + * (C) 2000 by Harald Welte + * based on RR's ip_conntrack_ftp.c + * + * ip_conntrack_irc.c,v 1.17 2001/04/23 05:21:22 laforge Exp + * + * 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. + ** + * Module load syntax: + * insmod ip_nat_irc.o ports=port1,port2,...port + * + * please give the ports of all IRC servers You wish to connect to. + * If You don't specify ports, the default will be port 6667 + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IRC (DCC) connection tracking module"); +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of IRC servers"); +#endif + +#define NUM_DCCPROTO 5 +struct dccproto dccprotos[NUM_DCCPROTO] = { + {"SEND ", 5}, + {"CHAT ", 5}, + {"MOVE ", 5}, + {"TSEND ", 6}, + {"SCHAT ", 6} +}; +#define MAXMATCHLEN 6 + +DECLARE_LOCK(ip_irc_lock); +struct module *ip_conntrack_irc = THIS_MODULE; + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ + ":" format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port, + char **ad_beg_p, char **ad_end_p) +/* tries to get the ip_addr and port out of a dcc command + return value: -1 on failure, 0 on success + data pointer to first byte of DCC command data + data_end pointer to last byte of dcc command data + ip returns parsed ip of dcc command + port returns parsed port of dcc command + ad_beg_p returns pointer to first byte of addr data + ad_end_p returns pointer to last byte of addr data */ +{ + + /* at least 12: "AAAAAAAA P\1\n" */ + while (*data++ != ' ') + if (data > data_end - 12) + return -1; + + *ad_beg_p = data; + *ip = simple_strtoul(data, &data, 10); + + /* skip blanks between ip and port */ + while (*data == ' ') + data++; + + + *port = simple_strtoul(data, &data, 10); + *ad_end_p = data; + + return 0; +} + + +/* FIXME: This should be in userspace. Later. */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + const char *data = (const char *) tcph + tcph->doff * 4; + const char *_data = data; + char *data_limit; + u_int32_t tcplen = len - iph->ihl * 4; + u_int32_t datalen = tcplen - tcph->doff * 4; + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_tuple t, mask; + + u_int32_t dcc_ip; + u_int16_t dcc_port; + int i; + char *addr_beg_p, *addr_end_p; + + struct ip_ct_irc *info = &ct->help.ct_irc_info; + + memset(&mask, 0, sizeof(struct ip_conntrack_tuple)); + mask.dst.u.tcp.port = 0xFFFF; + mask.dst.protonum = 0xFFFF; + + DEBUGP("entered\n"); + /* Can't track connections formed before we registered */ + if (!info) + return NF_ACCEPT; + + /* If packet is coming from IRC server */ + if (dir == IP_CT_DIR_REPLY) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { + DEBUGP("tcplen = %u\n", (unsigned) tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + data_limit = (char *) data + datalen; + while (data < (data_limit - (22 + MAXMATCHLEN))) { + if (memcmp(data, "\1DCC ", 5)) { + data++; + continue; + } + + data += 5; + + DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), + NIPQUAD(iph->daddr), ntohs(tcph->dest)); + + for (i = 0; i < NUM_DCCPROTO; i++) { + if (memcmp(data, dccprotos[i].match, + dccprotos[i].matchlen)) { + /* no match */ + continue; + } + + DEBUGP("DCC %s detected\n", dccprotos[i].match); + data += dccprotos[i].matchlen; + if (parse_dcc((char *) data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + /* unable to parse */ + DEBUGP("unable to parse dcc command\n"); + continue; + } + DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", + HIPQUAD(dcc_ip), dcc_port); + + if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) { + if (net_ratelimit()) + printk(KERN_WARNING + "Forged DCC command from " + "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", + HIPQUAD(ct->tuplehash[dir].tuple.src.ip), + NIPQUAD(dcc_ip), dcc_port); + + continue; + } + + LOCK_BH(&ip_irc_lock); + + /* save position of address in dcc string, + * neccessary for NAT */ + info->is_irc = IP_CONNTR_IRC; + DEBUGP("tcph->seq = %u\n", tcph->seq); + info->seq = ntohl(tcph->seq) + (addr_beg_p - _data); + info->len = (addr_end_p - addr_beg_p); + info->port = dcc_port; + DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n", + info->seq, (addr_end_p - _data), info->len); + + memset(&t, 0, sizeof(t)); + t.src.ip = 0; + t.src.u.tcp.port = 0; + t.dst.ip = htonl(dcc_ip); + t.dst.u.tcp.port = htons(info->port); + t.dst.protonum = IPPROTO_TCP; + + DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", + NIPQUAD(t.src.ip), + ntohs(t.src.u.tcp.port), + NIPQUAD(t.dst.ip), + ntohs(t.dst.u.tcp.port)); + + ip_conntrack_expect_related(ct, &t, &mask, NULL); + UNLOCK_BH(&ip_irc_lock); + + return NF_ACCEPT; + } /* for .. NUM_DCCPROTO */ + } /* while data < ... */ + + return NF_ACCEPT; +} + +static struct ip_conntrack_helper irc_helpers[MAX_PORTS]; + +static void fini(void); + +static int __init init(void) +{ + int i, ret; + + /* If no port given, default to standard irc port */ + if (ports[0] == 0) + ports[0] = 6667; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + memset(&irc_helpers[i], 0, + sizeof(struct ip_conntrack_helper)); + irc_helpers[i].tuple.src.u.tcp.port = htons(ports[i]); + irc_helpers[i].tuple.dst.protonum = IPPROTO_TCP; + irc_helpers[i].mask.src.u.tcp.port = 0xFFFF; + irc_helpers[i].mask.dst.protonum = 0xFFFF; + irc_helpers[i].help = help; + + DEBUGP("port #%d: %d\n", i, ports[i]); + + ret = ip_conntrack_helper_register(&irc_helpers[i]); + + if (ret) { + printk("ip_conntrack_irc: ERROR registering port %d\n", + ports[i]); + fini(); + return -EBUSY; + } + ports_n_c++; + } + return 0; +} + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by the init function */ +static void fini(void) +{ + int i; + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + DEBUGP("unregistering port %d\n", + ports[i]); + ip_conntrack_helper_unregister(&irc_helpers[i]); + } +} + +module_init(init); +module_exit(fini); diff -urN linux/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux/net/ipv4/netfilter/ip_conntrack_standalone.c Fri Apr 27 14:15:01 2001 +++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c Sun Jun 3 06:22:35 2001 @@ -328,6 +328,7 @@ EXPORT_SYMBOL(ip_ct_selective_cleanup); EXPORT_SYMBOL(ip_ct_refresh); EXPORT_SYMBOL(ip_conntrack_expect_related); +EXPORT_SYMBOL(ip_conntrack_find_get); EXPORT_SYMBOL(ip_conntrack_tuple_taken); EXPORT_SYMBOL(ip_ct_gather_frags); EXPORT_SYMBOL(ip_conntrack_htable_size); diff -urN linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c --- linux/net/ipv4/netfilter/ip_fw_compat_masq.c Mon Sep 18 15:09:55 2000 +++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c Sun Jun 3 06:22:35 2001 @@ -85,7 +85,8 @@ newsrc, newsrc, { htons(61000) }, { htons(65095) } } } }); - ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING, + NULL, dev, *pskb); if (ret != NF_ACCEPT) { WRITE_UNLOCK(&ip_nat_lock); return ret; diff -urN linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c --- linux/net/ipv4/netfilter/ip_nat_core.c Wed May 16 10:31:27 2001 +++ linux/net/ipv4/netfilter/ip_nat_core.c Sun Jun 3 06:22:35 2001 @@ -500,7 +500,10 @@ unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack, const struct ip_nat_multi_range *mr, - unsigned int hooknum) + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct sk_buff *skb) { struct ip_conntrack_tuple new_tuple, inv_tuple, reply; struct ip_conntrack_tuple orig_tp; @@ -551,7 +554,12 @@ hooknum)) { DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n", conntrack); - return NF_DROP; + skb->nfmark = NF_IP_DROP_NAT_NO_UNIQUE_TUPLE; + NF_HOOK(PF_INET, NF_IP_DROPPING, skb, + (struct net_device *)in, + (struct net_device *)out, + nf_drop_okfn); + return NF_STOLEN; } #if 0 diff -urN linux/net/ipv4/netfilter/ip_nat_ftp.c linux/net/ipv4/netfilter/ip_nat_ftp.c --- linux/net/ipv4/netfilter/ip_nat_ftp.c Wed Apr 25 15:02:35 2001 +++ linux/net/ipv4/netfilter/ip_nat_ftp.c Sun Jun 3 06:22:35 2001 @@ -52,7 +52,7 @@ ftpinfo = &master->help.ct_ftp_info; LOCK_BH(&ip_ftp_lock); - if (!ftpinfo->is_ftp) { + if (ftpinfo->is_ftp != 21) { UNLOCK_BH(&ip_ftp_lock); DEBUGP("nat_expected: master not ftp\n"); return 0; @@ -94,8 +94,8 @@ = ((union ip_conntrack_manip_proto) { htons(ftpinfo->port) }); } - *verdict = ip_nat_setup_info(ct, &mr, hooknum); - + *verdict = ip_nat_setup_info(ct, &mr, hooknum, (*pskb)->dev, NULL, + *pskb); return 1; } diff -urN linux/net/ipv4/netfilter/ip_nat_irc.c linux/net/ipv4/netfilter/ip_nat_irc.c --- linux/net/ipv4/netfilter/ip_nat_irc.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ip_nat_irc.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,361 @@ +/* IRC extension for TCP NAT alteration. + * (C) 2000 by Harald Welte + * based on a copy of RR's ip_nat_ftp.c + * + * ip_nat_irc.c,v 1.12 2001/04/23 05:21:22 laforge Exp + * + * 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. + * + * Module load syntax: + * insmod ip_nat_irc.o ports=port1,port2,...port + * + * please give the ports of all IRC servers You wish to connect to. + * If You don't specify ports, the default will be port 6667 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_c = 0; + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IRC (DCC) network address translation module"); +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of IRC servers"); +#endif + +/* protects irc part of conntracks */ +DECLARE_LOCK_EXTERN(ip_irc_lock); + +/* FIXME: Time out? --RR */ + +static int +irc_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info, + struct ip_conntrack *master, + struct ip_nat_info *masterinfo, unsigned int *verdict) +{ + struct ip_nat_multi_range mr; + u_int32_t newdstip, newsrcip, newip; + struct ip_ct_irc *ircinfo; + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + IP_NF_ASSERT(masterinfo); + + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); + + DEBUGP("nat_expected: We have a connection!\n"); + + /* Master must be an irc connection */ + ircinfo = &master->help.ct_irc_info; + LOCK_BH(&ip_irc_lock); + if (ircinfo->is_irc != IP_CONNTR_IRC) { + UNLOCK_BH(&ip_irc_lock); + DEBUGP("nat_expected: master not irc\n"); + return 0; + } + + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + + UNLOCK_BH(&ip_irc_lock); + + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) + newip = newsrcip; + else + newip = newdstip; + + DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); + + mr.rangesize = 1; + /* We don't want to manip the per-protocol, just the IPs. */ + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + + *verdict = ip_nat_setup_info(ct, &mr, hooknum, (*pskb)->dev, NULL, + *pskb); + + return 1; +} + +/* Grrr... SACK. Fuck me even harder. Don't want to fix it on the + fly, so blow it away. */ +static void delete_sack(struct sk_buff *skb, struct tcphdr *tcph) +{ + unsigned int i; + u_int8_t *opt = (u_int8_t *) tcph; + + DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n", + tcph->doff * 4); + for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) { + DEBUGP("%u ", opt[i]); + switch (opt[i]) { + case TCPOPT_NOP: + case TCPOPT_EOL: + i++; + break; + + case TCPOPT_SACK_PERM: + goto found_opt; + + default: + /* Worst that can happen: it will take us over. */ + i += opt[i + 1] ? : 1; + } + } + DEBUGP("\n"); + return; + + found_opt: + DEBUGP("\n"); + DEBUGP("Found SACKPERM at offset %u.\n", i); + + /* Must be within TCP header, and valid SACK perm. */ + if (i + opt[i + 1] <= tcph->doff * 4 && opt[i + 1] == 2) { + /* Replace with NOPs. */ + tcph->check + = + ip_nat_cheat_check(*((u_int16_t *) (opt + i)) ^ 0xFFFF, + 0, tcph->check); + opt[i] = opt[i + 1] = 0; + } else + DEBUGP("Something wrong with SACK_PERM.\n"); +} + +static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info, + struct ip_conntrack *ct, + unsigned int datalen, + struct sk_buff **pskb, + enum ip_conntrack_info ctinfo) +{ + u_int32_t newip; + struct ip_conntrack_tuple t; + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + int port; + + /* "4294967296 65635 " */ + char buffer[18]; + + MUST_BE_LOCKED(&ip_irc_lock); + + DEBUGP("IRC_NAT: info (seq %u + %u) packet(seq %u + %u)\n", + ct_irc_info->seq, ct_irc_info->len, + ntohl(tcph->seq), datalen); + + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + + /* Alter conntrack's expectations. */ + + /* We can read expect here without conntrack lock, since it's + only set in ip_conntrack_irc, with ip_irc_lock held + writable */ + + t = ct->expected.tuple; + t.dst.ip = newip; + for (port = ct_irc_info->port; port != 0; port++) { + t.dst.u.tcp.port = htons(port); + if (ip_conntrack_expect_related(ct, &t, + &ct->expected.mask, + NULL) == 0) { + DEBUGP("using port %d", port); + break; + } + + } + if (port == 0) + return 0; + + /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27 + * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28 + * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26 + * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26 + * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27 + * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits, + * 255.255.255.255==4294967296, 10 digits) + * P: bound port (min 1 d, max 5d (65635)) + * F: filename (min 1 d ) + * S: size (min 1 d ) + * 0x01, \n: terminators + */ + + sprintf(buffer, "%u %u", ntohl(newip), port); + DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n", + buffer, NIPQUAD(newip), port); + + return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + ct_irc_info->seq - ntohl(tcph->seq), + ct_irc_info->len, buffer, + strlen(buffer)); +} + +static unsigned int help(struct ip_conntrack *ct, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + unsigned int datalen; + int dir; + int score; + struct ip_ct_irc *ct_irc_info = &ct->help.ct_irc_info; + + /* Delete SACK_OK on initial TCP SYNs. */ + if (tcph->syn && !tcph->ack) + delete_sack(*pskb, tcph); + + /* Only mangle things once: original direction in POST_ROUTING + and reply direction on PRE_ROUTING. */ + dir = CTINFO2DIR(ctinfo); + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { + DEBUGP("nat_irc: Not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + return NF_ACCEPT; + } + DEBUGP("got beyond not touching\n"); + + datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; + score = 0; + LOCK_BH(&ip_irc_lock); + if (ct_irc_info->len) { + DEBUGP("got beyond ct_irc_info->len\n"); + + /* If it's in the right range... */ + score += between(ct_irc_info->seq, ntohl(tcph->seq), + ntohl(tcph->seq) + datalen); + score += between(ct_irc_info->seq + ct_irc_info->len, + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen); + if (score == 1) { + /* Half a match? This means a partial retransmisison. + It's a cracker being funky. */ + if (net_ratelimit()) { + printk + ("IRC_NAT: partial packet %u/%u in %u/%u\n", + ct_irc_info->seq, ct_irc_info->len, + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen); + } + UNLOCK_BH(&ip_irc_lock); + return NF_DROP; + } else if (score == 2) { + DEBUGP("IRC_NAT: score=2, calling fixup\n"); + if (!irc_data_fixup(ct_irc_info, ct, datalen, + pskb, ctinfo)) { + UNLOCK_BH(&ip_irc_lock); + return NF_DROP; + } + /* skb may have been reallocated */ + iph = (*pskb)->nh.iph; + tcph = (void *) iph + iph->ihl * 4; + } + } + + UNLOCK_BH(&ip_irc_lock); + + ip_nat_seq_adjust(*pskb, ct, ctinfo); + + return NF_ACCEPT; +} + +static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS]; +static char ip_nih_names[MAX_PORTS][6]; + +static struct ip_nat_expect irc_expect + = { {NULL, NULL}, irc_nat_expected }; + + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by init() */ +static void fini(void) +{ + int i; + + for (i = 0; i < ports_c; i++) { + DEBUGP("ip_nat_irc: unregistering helper for port %d\n", + ports[i]); + ip_nat_helper_unregister(&ip_nat_irc_helpers[i]); + } + ip_nat_expect_unregister(&irc_expect); +} +static int __init init(void) +{ + int ret; + int i; + struct ip_nat_helper *hlpr; + char *tmpname; + + ret = ip_nat_expect_register(&irc_expect); + if (ret == 0) { + + if (ports[0] == 0) { + ports[0] = 6667; + } + + for (i = 0; ports[i] != 0; i++) { + hlpr = &ip_nat_irc_helpers[i]; + memset(hlpr, 0, + sizeof(struct ip_nat_helper)); + + hlpr->tuple.dst.protonum = IPPROTO_TCP; + hlpr->tuple.src.u.tcp.port = htons(ports[i]); + hlpr->mask.src.u.tcp.port = 0xFFFF; + hlpr->mask.dst.protonum = 0xFFFF; + hlpr->help = help; + + tmpname = &ip_nih_names[i][0]; + sprintf(tmpname, "irc%2.2d", i); + + hlpr->name = tmpname; + DEBUGP + ("ip_nat_irc: Trying to register helper for port %d: name %s\n", + ports[i], hlpr->name); + ret = ip_nat_helper_register(hlpr); + + if (ret) { + printk + ("ip_nat_irc: error registering helper for port %d\n", + ports[i]); + fini(); + return -EBUSY; + } + ports_c++; + } + } + return ret; +} + + +module_init(init); +module_exit(fini); diff -urN linux/net/ipv4/netfilter/ip_nat_rule.c linux/net/ipv4/netfilter/ip_nat_rule.c --- linux/net/ipv4/netfilter/ip_nat_rule.c Fri Apr 27 14:15:01 2001 +++ linux/net/ipv4/netfilter/ip_nat_rule.c Sun Jun 3 06:22:35 2001 @@ -127,7 +127,7 @@ IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); IP_NF_ASSERT(out); - return ip_nat_setup_info(ct, targinfo, hooknum); + return ip_nat_setup_info(ct, targinfo, hooknum, in, out, *pskb); } static unsigned int ipt_dnat_target(struct sk_buff **pskb, @@ -148,7 +148,7 @@ /* Connection must be valid and new. */ IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); - return ip_nat_setup_info(ct, targinfo, hooknum); + return ip_nat_setup_info(ct, targinfo, hooknum, in, out, *pskb); } static int ipt_snat_checkentry(const char *tablename, @@ -224,7 +224,10 @@ static inline unsigned int alloc_null_binding(struct ip_conntrack *conntrack, struct ip_nat_info *info, - unsigned int hooknum) + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct sk_buff *skb) { /* Force range to this IP; let proto decide mapping for per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). @@ -239,7 +242,7 @@ DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", conntrack, NIPQUAD(ip)); - return ip_nat_setup_info(conntrack, &mr, hooknum); + return ip_nat_setup_info(conntrack, &mr, hooknum, in, out, skb); } static inline int call_expect(const struct ip_nat_expect *i, @@ -278,9 +281,11 @@ } ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL); if (ret == NF_ACCEPT) { - if (!(info->initialized & (1 << HOOK2MANIP(hooknum)))) + if (!(info->initialized & (1 << HOOK2MANIP(hooknum)))) { /* NUL mapping */ - ret = alloc_null_binding(ct, info, hooknum); + ret = alloc_null_binding(ct, info, hooknum, in, out, + *pskb); + } } return ret; } diff -urN linux/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c --- linux/net/ipv4/netfilter/ip_queue.c Mon Dec 11 12:37:04 2000 +++ linux/net/ipv4/netfilter/ip_queue.c Sun Jun 3 06:22:35 2001 @@ -445,8 +445,17 @@ RCV_SKB_FAIL(-EINVAL); if (type <= IPQM_BASE) return; +#ifdef CONFIG_LIDS + if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN) && + !cap_raised(current->lids_cap,CAP_NET_ADMIN) && + lids_load && lids_local_load) { + lids_security_alert("NetLink receiver violate CAP_NET_ADMIN"); + RCV_SKB_FAIL(-EPERM); + } +#else if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); +#endif if (nlq->peer.pid && !nlq->peer.died && (nlq->peer.pid != nlh->nlmsg_pid)) { printk(KERN_WARNING "ip_queue: peer pid changed from %d to " diff -urN linux/net/ipv4/netfilter/ipt_LOG.c linux/net/ipv4/netfilter/ipt_LOG.c --- linux/net/ipv4/netfilter/ipt_LOG.c Mon Jan 1 09:54:07 2001 +++ linux/net/ipv4/netfilter/ipt_LOG.c Sun Jun 3 06:22:35 2001 @@ -281,8 +281,10 @@ level_string[1] = '0' + (loginfo->level % 8); spin_lock_bh(&log_lock); printk(level_string); - printk("%sIN=%s OUT=%s ", - loginfo->prefix, + printk("%s", loginfo->prefix); + if (userinfo && hooknum == NF_IP_DROPPING) + printk("(%s) ", (const char *)userinfo); + printk("IN=%s OUT=%s ", in ? in->name : "", out ? out->name : ""); if (in && !out) { diff -urN linux/net/ipv4/netfilter/ipt_MASQUERADE.c linux/net/ipv4/netfilter/ipt_MASQUERADE.c --- linux/net/ipv4/netfilter/ipt_MASQUERADE.c Fri Apr 27 14:15:01 2001 +++ linux/net/ipv4/netfilter/ipt_MASQUERADE.c Sun Jun 3 06:22:35 2001 @@ -112,7 +112,7 @@ mr->range[0].min, mr->range[0].max } } }); /* Hand modified range to generic setup. */ - return ip_nat_setup_info(ct, &newrange, hooknum); + return ip_nat_setup_info(ct, &newrange, hooknum, in, out, *pskb); } static inline int diff -urN linux/net/ipv4/netfilter/ipt_REDIRECT.c linux/net/ipv4/netfilter/ipt_REDIRECT.c --- linux/net/ipv4/netfilter/ipt_REDIRECT.c Tue Jun 20 14:32:27 2000 +++ linux/net/ipv4/netfilter/ipt_REDIRECT.c Sun Jun 3 06:22:35 2001 @@ -86,7 +86,7 @@ mr->range[0].min, mr->range[0].max } } }); /* Hand modified range to generic setup. */ - return ip_nat_setup_info(ct, &newrange, hooknum); + return ip_nat_setup_info(ct, &newrange, hooknum, in, out, *pskb); } static struct ipt_target redirect_reg diff -urN linux/net/ipv4/netfilter/ipt_iplimit.c linux/net/ipv4/netfilter/ipt_iplimit.c --- linux/net/ipv4/netfilter/ipt_iplimit.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ipt_iplimit.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,226 @@ +/* + * netfilter module to limit the number of parallel tcp + * connections per IP address. + * (c) 2000 Gerd Knorr + * + * based on ... + * + * Kernel module to match connection tracking information. + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 0 + +/* we'll save the tuples of all connections we care about */ +struct ipt_iplimit_conn +{ + struct list_head list; + struct ip_conntrack_tuple tuple; +}; + +struct ipt_iplimit_data { + spinlock_t lock; + struct list_head iphash[256]; +}; + +static int ipt_iphash(u_int32_t addr) +{ + int hash; + + hash = addr & 0xff; + hash ^= (addr >> 8) & 0xff; + hash ^= (addr >> 16) & 0xff; + hash ^= (addr >> 24) & 0xff; + return hash; +} + +static int count_them(struct ipt_iplimit_data *data, + u_int32_t addr, u_int32_t mask, + struct ip_conntrack *ct) +{ +#if DEBUG + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv", + "fin_wait", "time_wait", "close", "close_wait", + "last_ack", "listen" }; +#endif + int addit = 1, matches = 0; + struct ip_conntrack_tuple tuple; + struct ip_conntrack_tuple_hash *found; + struct ipt_iplimit_conn *conn; + struct list_head *hash,*lh; + + spin_lock(&data->lock); + tuple = ct->tuplehash[0].tuple; + hash = &data->iphash[ipt_iphash(addr & mask)]; + + /* check the saved connections */ + for (lh = hash->next; lh != hash; lh = lh->next) { + conn = list_entry(lh,struct ipt_iplimit_conn,list); + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple))) { + /* Just to be sure we have it only once in the list. + We should'nt see tuples twice unless someone hooks this + into a table without "-p tcp --syn" */ + addit = 0; + } + found = ip_conntrack_find_get(&conn->tuple,ct); +#if DEBUG + printk("ipt_iplimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n", + ipt_iphash(addr & mask), + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port), + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port), + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone"); +#endif + if (NULL == found) { + /* this one is gone */ + lh = lh->prev; + list_del(lh->next); + kfree(conn); + continue; + } + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) { + /* we don't care about connections which are + closed already -> ditch it */ + lh = lh->prev; + list_del(lh->next); + kfree(conn); + nf_conntrack_put(&found->ctrack->infos[0]); + continue; + } + if ((addr & mask) == (conn->tuple.src.ip & mask)) { + /* same source IP address -> be counted! */ + matches++; + } + nf_conntrack_put(&found->ctrack->infos[0]); + } + if (addit) { + /* save the new connection in our list */ +#if DEBUG + printk("ipt_iplimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n", + ipt_iphash(addr & mask), + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); +#endif + conn = kmalloc(sizeof(*conn),GFP_ATOMIC); + if (NULL == conn) + return -1; + memset(conn,0,sizeof(*conn)); + INIT_LIST_HEAD(&conn->list); + conn->tuple = tuple; + list_add(&conn->list,hash); + matches++; + } + spin_unlock(&data->lock); + return matches; +} + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_iplimit_info *info = matchinfo; + int connections, match; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (NULL == ct) { + printk("ipt_iplimit: Oops: invalid ct state ?\n"); + *hotdrop = 1; + return 0; + } + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct); + if (-1 == connections) { + printk("ipt_iplimit: Hmm, kmalloc failed :-(\n"); + *hotdrop = 1; /* let's free some memory :-) */ + return 0; + } + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit); +#if DEBUG + printk("ipt_iplimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u " + "connections=%d limit=%d match=%s\n", + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask), + connections, info->limit, match ? "yes" : "no"); +#endif + + return match; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_iplimit_info *info = matchinfo; + int i; + + /* verify size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_iplimit_info))) + return 0; + + /* refuse anything but tcp */ + if (ip->proto != IPPROTO_TCP) + return 0; + + /* init private data */ + info->data = kmalloc(sizeof(struct ipt_iplimit_data),GFP_KERNEL); + spin_lock_init(&(info->data->lock)); + for (i = 0; i < 256; i++) + INIT_LIST_HEAD(&(info->data->iphash[i])); + + return 1; +} + +static void destroy(void *matchinfo, unsigned int matchinfosize) +{ + struct ipt_iplimit_info *info = matchinfo; + struct ipt_iplimit_conn *conn; + struct list_head *hash; + int i; + + /* cleanup */ + for (i = 0; i < 256; i++) { + hash = &(info->data->iphash[i]); + while (hash != hash->next) { + conn = list_entry(hash->next,struct ipt_iplimit_conn,list); + list_del(hash->next); + kfree(conn); + } + } + kfree(info->data); +} + +static struct ipt_match iplimit_match += { { NULL, NULL }, "iplimit", &match, &check, &destroy, THIS_MODULE }; + +static int __init init(void) +{ + /* NULL if ip_conntrack not a module */ + if (ip_conntrack_module) + __MOD_INC_USE_COUNT(ip_conntrack_module); + return ipt_register_match(&iplimit_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&iplimit_match); + if (ip_conntrack_module) + __MOD_DEC_USE_COUNT(ip_conntrack_module); +} + +module_init(init); +module_exit(fini); diff -urN linux/net/ipv4/netfilter/ipt_ipv4options.c linux/net/ipv4/netfilter/ipt_ipv4options.c --- linux/net/ipv4/netfilter/ipt_ipv4options.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ipt_ipv4options.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,128 @@ +/* + This is a module which is used to match ipv4 options. + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 11-mars-2001 Fabrice MARIE : initial development. +*/ + +#include +#include +#include + +#include +#include + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */ + const struct iphdr *iph = skb->nh.iph; + const struct ip_options *opt; + + if (iph->ihl * 4 == sizeof(struct iphdr)) { + /* No options, so we match only the "DONTs" and the "IGNOREs" */ + + if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) || + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP)) + return 0; + return 1; + } + +/* if (ip_options_compile(NULL, skb)) + return 0;*/ + opt = &(IPCB(skb)->opt); + + /* source routing */ + if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) { + if (!((opt->srr) & (opt->is_strictroute))) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) { + if (!((opt->srr) & (!opt->is_strictroute))) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) { + if (opt->srr) + return 0; + } + /* record route */ + if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) { + if (!opt->rr) + return 0; + } + if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) { + if (opt->rr) + return 0; + } + /* timestamp */ + if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) { + if (!opt->ts) + return 0; + } + if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) { + if (opt->ts) + return 0; + } + + /* we match ! */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */ + /* Check the size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info))) + return 0; + /* Now check the coherence of the data ... */ + if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) && + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) + return 0; /* cannot match in the same time loose and strict source routing */ + if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR)) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR)) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP)) + return 0; /* opposites */ + + /* everything looks ok. */ + return 1; +} + +static struct ipt_match ipv4options_match += { { NULL, NULL }, "ipv4options", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + printk("ipt_ipv4options loading\n"); + return ipt_register_match(&ipv4options_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipv4options_match); + printk("ipt_ipv4options unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -urN linux/net/ipv4/netfilter/ipt_length.c linux/net/ipv4/netfilter/ipt_length.c --- linux/net/ipv4/netfilter/ipt_length.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ipt_length.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,51 @@ +/* Kernel module to match packet length. */ +#include +#include + +#include +#include + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_length_info *info = matchinfo; + u_int16_t pktlen = ntohs(skb->nh.iph->tot_len); + + return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_length_info))) + return 0; + + return 1; +} + +static struct ipt_match length_match += { { NULL, NULL }, "length", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&length_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&length_match); +} + +module_init(init); +module_exit(fini); diff -urN linux/net/ipv4/netfilter/ipt_psd.c linux/net/ipv4/netfilter/ipt_psd.c --- linux/net/ipv4/netfilter/ipt_psd.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ipt_psd.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,358 @@ +/* + This is a module which is used for PSD (portscan detection) + Derived from scanlogd v2.1 written by Solar Designer + and LOG target module. + + Copyright (C) 2000,2001 astaro AG + + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 2000-05-04 Markus Hennig : initial + 2000-08-18 Dennis Koslowski : first release + 2000-12-01 Dennis Koslowski : UDP scans detection added + 2001-01-02 Dennis Koslowski : output modified + 2001-02-04 Jan Rekorajski : converted from target to match +*/ + +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define HF_DADDR_CHANGING 0x01 +#define HF_SPORT_CHANGING 0x02 +#define HF_TOS_CHANGING 0x04 +#define HF_TTL_CHANGING 0x08 + +/* + * Information we keep per each target port + */ +struct port { + u_int16_t number; /* port number */ + u_int8_t proto; /* protocol number */ + u_int8_t and_flags; /* tcp ANDed flags */ + u_int8_t or_flags; /* tcp ORed flags */ +}; + +/* + * Information we keep per each source address. + */ +struct host { + struct host *next; /* Next entry with the same hash */ + clock_t timestamp; /* Last update time */ + struct in_addr src_addr; /* Source address */ + struct in_addr dest_addr; /* Destination address */ + unsigned short src_port; /* Source port */ + int count; /* Number of ports in the list */ + int weight; /* Total weight of ports in the list */ + struct port ports[SCAN_MAX_COUNT - 1]; /* List of ports */ + unsigned char tos; /* TOS */ + unsigned char ttl; /* TTL */ + unsigned char flags; /* HF_ flags bitmask */ +}; + +/* + * State information. + */ +static struct { + spinlock_t lock; + struct host list[LIST_SIZE]; /* List of source addresses */ + struct host *hash[HASH_SIZE]; /* Hash: pointers into the list */ + int index; /* Oldest entry to be replaced */ +} state; + +/* + * Convert an IP address into a hash table index. + */ +static inline int hashfunc(struct in_addr addr) +{ + unsigned int value; + int hash; + + value = addr.s_addr; + hash = 0; + do { + hash ^= value; + } while ((value >>= HASH_LOG)); + + return hash & (HASH_SIZE - 1); +} + +static int +ipt_psd_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + struct iphdr *ip_hdr; + struct tcphdr *tcp_hdr; + struct in_addr addr; + u_int16_t src_port,dest_port; + u_int8_t tcp_flags, proto; + clock_t now; + struct host *curr, *last, **head; + int hash, index, count; + + /* Parameters from userspace */ + const struct ipt_psd_info *psdinfo = matchinfo; + + /* IP header */ + ip_hdr = pskb->nh.iph; + + /* Sanity check */ + if (ntohs(ip_hdr->frag_off) & IP_OFFSET) { + DEBUGP("PSD: sanity check failed\n"); + return 0; + } + + /* TCP or UDP ? */ + proto = ip_hdr->protocol; + + if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) { + DEBUGP("PSD: protocol not supported\n"); + return 0; + } + + /* Get the source address, source & destination ports, and TCP flags */ + + addr.s_addr = ip_hdr->saddr; + + tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl); + + /* Yep, itīs dirty */ + src_port = tcp_hdr->source; + dest_port = tcp_hdr->dest; + + if (proto == IPPROTO_TCP) { + tcp_flags = *((u_int8_t*)tcp_hdr + 13); + } + else { + tcp_flags = 0x00; + } + + /* We're using IP address 0.0.0.0 for a special purpose here, so don't let + * them spoof us. [DHCP needs this feature - HW] */ + if (!addr.s_addr) { + DEBUGP("PSD: spoofed source address (0.0.0.0)\n"); + return 0; + } + + /* Use jiffies here not to depend on someone setting the time while we're + * running; we need to be careful with possible return value overflows. */ + now = jiffies; + + spin_lock(&state.lock); + + /* Do we know this source address already? */ + count = 0; + last = NULL; + if ((curr = *(head = &state.hash[hash = hashfunc(addr)]))) + do { + if (curr->src_addr.s_addr == addr.s_addr) break; + count++; + if (curr->next) last = curr; + } while ((curr = curr->next)); + + if (curr) { + + /* We know this address, and the entry isn't too old. Update it. */ + if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 && + time_after_eq(now, curr->timestamp)) { + + /* Just update the appropriate list entry if we've seen this port already */ + for (index = 0; index < curr->count; index++) { + if (curr->ports[index].number == dest_port) { + curr->ports[index].proto = proto; + curr->ports[index].and_flags &= tcp_flags; + curr->ports[index].or_flags |= tcp_flags; + goto out_no_match; + } + } + + /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */ + if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst)) + goto out_no_match; + + /* Packet to a new port, and not TCP/ACK: update the timestamp */ + curr->timestamp = now; + + /* Logged this scan already? Then drop the packet. */ + if (curr->weight >= psdinfo->weight_threshold) + goto out_match; + + /* Specify if destination address, source port, TOS or TTL are not fixed */ + if (curr->dest_addr.s_addr != ip_hdr->daddr) + curr->flags |= HF_DADDR_CHANGING; + if (curr->src_port != src_port) + curr->flags |= HF_SPORT_CHANGING; + if (curr->tos != ip_hdr->tos) + curr->flags |= HF_TOS_CHANGING; + if (curr->ttl != ip_hdr->ttl) + curr->flags |= HF_TTL_CHANGING; + + /* Update the total weight */ + curr->weight += (ntohs(dest_port) < 1024) ? + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight; + + /* Got enough destination ports to decide that this is a scan? */ + /* Then log it and drop the packet. */ + if (curr->weight >= psdinfo->weight_threshold) + goto out_match; + + /* Remember the new port */ + if (curr->count < SCAN_MAX_COUNT) { + curr->ports[curr->count].number = dest_port; + curr->ports[curr->count].proto = proto; + curr->ports[curr->count].and_flags = tcp_flags; + curr->ports[curr->count].or_flags = tcp_flags; + curr->count++; + } + + goto out_no_match; + } + + /* We know this address, but the entry is outdated. Mark it unused, and + * remove from the hash table. We'll allocate a new entry instead since + * this one might get re-used too soon. */ + curr->src_addr.s_addr = 0; + if (last) + last->next = last->next->next; + else if (*head) + *head = (*head)->next; + last = NULL; + } + + /* We don't need an ACK from a new source address */ + if (proto == IPPROTO_TCP && tcp_hdr->ack) + goto out_no_match; + + /* Got too many source addresses with the same hash value? Then remove the + * oldest one from the hash table, so that they can't take too much of our + * CPU time even with carefully chosen spoofed IP addresses. */ + if (count >= HASH_MAX && last) last->next = NULL; + + /* We're going to re-use the oldest list entry, so remove it from the hash + * table first (if it is really already in use, and isn't removed from the + * hash table already because of the HASH_MAX check above). */ + + /* First, find it */ + if (state.list[state.index].src_addr.s_addr) + head = &state.hash[hashfunc(state.list[state.index].src_addr)]; + else + head = &last; + last = NULL; + if ((curr = *head)) + do { + if (curr == &state.list[state.index]) break; + last = curr; + } while ((curr = curr->next)); + + /* Then, remove it */ + if (curr) { + if (last) + last->next = last->next->next; + else if (*head) + *head = (*head)->next; + } + + /* Get our list entry */ + curr = &state.list[state.index++]; + if (state.index >= LIST_SIZE) state.index = 0; + + /* Link it into the hash table */ + head = &state.hash[hash]; + curr->next = *head; + *head = curr; + + /* And fill in the fields */ + curr->timestamp = now; + curr->src_addr = addr; + curr->dest_addr.s_addr = ip_hdr->daddr; + curr->src_port = src_port; + curr->count = 1; + curr->weight = (ntohs(dest_port) < 1024) ? + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight; + curr->ports[0].number = dest_port; + curr->ports[0].proto = proto; + curr->ports[0].and_flags = tcp_flags; + curr->ports[0].or_flags = tcp_flags; + curr->tos = ip_hdr->tos; + curr->ttl = ip_hdr->ttl; + +out_no_match: + spin_unlock(&state.lock); + return 0; + +out_match: + spin_unlock(&state.lock); + return 1; +} + +static int ipt_psd_checkentry(const char *tablename, + const struct ipt_ip *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ +/* const struct ipt_psd_info *psdinfo = targinfo;*/ + + /* we accept TCP only */ +/* if (e->ip.proto != IPPROTO_TCP) { */ +/* DEBUGP("PSD: specified protocol may be TCP only\n"); */ +/* return 0; */ +/* } */ + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) { + DEBUGP("PSD: matchsize %u != %u\n", + matchsize, + IPT_ALIGN(sizeof(struct ipt_psd_info))); + return 0; + } + + return 1; +} + +static struct ipt_match ipt_psd_reg = { + {NULL, NULL}, + "psd", + ipt_psd_match, + ipt_psd_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_match(&ipt_psd_reg)) + return -EINVAL; + + memset(&state, 0, sizeof(state)); + + spin_lock_init(&(state.lock)); + + printk("netfilter PSD loaded - (c) astaro AG\n"); + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_psd_reg); + printk("netfilter PSD unloaded - (c) astaro AG\n"); +} + +module_init(init); +module_exit(fini); diff -urN linux/net/ipv4/netfilter/ipt_string.c linux/net/ipv4/netfilter/ipt_string.c --- linux/net/ipv4/netfilter/ipt_string.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ipt_string.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,156 @@ +/* Kernel module to match a string into a packet. + * + * Copyright (C) 2000 Emmanuel Roger + * + * ChangeLog + * 02.05.2001: Gianni Tedesco + * Fixed kernel panic, due to overrunning boyer moore string + * tables. Also slightly tweaked heuristic for deciding what + * search algo to use. + * 27.01.2001: Gianni Tedesco + * Implemented Boyer Moore Sublinear search algorithm + * alongside the existing linear search based on memcmp(). + * Also a quick check to decide which method to use on a per + * packet basis. + */ + +#include +#include +#include +#include + +#include +#include + +int skip[BM_MAX_HLEN]; +int shift[BM_MAX_HLEN]; + +/* Boyer Moore Sublinear string search - VERY FAST */ +char *search_sublinear (char *needle, char *haystack, int needle_len, int haystack_len) +{ + int M1, right_end, sk, sh; + int ended, j, len[BM_MAX_HLEN]; + int i; + + /* Setup skip/shift tables */ + M1 = right_end = needle_len-1; + for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len; + for (i = 0; needle[i]; i++) skip[needle[i]] = M1 - i; + + for (i = 1; i < needle_len; i++) { + for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++); + len[i] = j; + } + + shift[0] = 1; + for (i = 1; i < needle_len; i++) shift[i] = needle_len; + for (i = M1; i > 0; i--) shift[len[i]] = i; + ended = 0; + + for (i = 0; i < needle_len; i++) { + if (len[i] == M1 - i) ended = i; + if (ended) shift[i] = ended; + } + + /* Do the search*/ + while (right_end < haystack_len) + { + for (i = 0; i < needle_len && haystack[right_end - i] == needle[M1 - i]; i++); + if (i == needle_len) { + return haystack+(right_end - M1); + } + + sk = skip[haystack[right_end - i]]; + sh = shift[i]; + right_end = max(right_end - i + sk, right_end + sh); + } + + return NULL; +} + +/* Linear string search based on memcmp() */ +char *search_linear (char *needle, char *haystack, int needle_len, int haystack_len) +{ + char *k = haystack + (haystack_len-needle_len); + char *t = haystack; + + while ( t++ < k ) { + if ( memcmp(t, needle, needle_len) == 0 ) return t; + } + + return NULL; +} + + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_string_info *info = matchinfo; + struct iphdr *ip = skb->nh.iph; + int hlen, nlen; + char *needle, *haystack; + proc_ipt_search search=search_linear; + + if ( !ip ) return 0; + + /* get lenghts, and validate them */ + nlen=info->len; + hlen=ntohs(ip->tot_len)-(ip->ihl*4); + if ( nlen > hlen ) return 0; + + needle=(char *)&info->string; + haystack=(char *)ip+(ip->ihl*4); + + /* The sublinear search comes in to its own + * on the larger packets */ + if ( (hlen>IPT_STRING_HAYSTACK_THRESH) && + (nlen>IPT_STRING_NEEDLE_THRESH) ) { + if ( hlen < BM_MAX_HLEN ) { + search=search_sublinear; + }else{ + if (net_ratelimit()) + printk(KERN_INFO "ipt_string: Packet too big " + "to attempt sublinear string search " + "(%d bytes)\n", hlen ); + } + } + + return ((search(needle, haystack, nlen, hlen)!=NULL) ^ info->invert); +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info))) + return 0; + + return 1; +} + +static struct ipt_match string_match += { { NULL, NULL }, "string", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&string_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&string_match); +} + +module_init(init); +module_exit(fini); diff -urN linux/net/ipv4/netfilter/ipt_time.c linux/net/ipv4/netfilter/ipt_time.c --- linux/net/ipv4/netfilter/ipt_time.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ipt_time.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,147 @@ +/* + This is a module which is used for time matching + is using some modified code from dietlibc (localtime() function) + that you can find at http://www.fefe.de/dietlibc/ + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL + 2001-05-04 Fabrice MARIE : initial development. + 2001-21-05 Fabrice MARIE : bug fix in the match code, + thanks to "Zeng Yu" for bug report. +*/ + +#include +#include + +#include +#include + + +struct tm +{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + + long int tm_gmtoff; /* we don't care, we count from GMT */ + const char *tm_zone; /* we don't care, we count from GMT */ +}; + +void +localtime(const time_t *timep, struct tm *r); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_time_info *info = matchinfo; /* match info for rule */ + struct tm currenttime; /* time human readable */ + u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1}; + u_int16_t packet_time; + + /* Transform the timestamp of the packet, in a human readable form */ + localtime(&skb->stamp.tv_sec, ¤ttime); + /* check if we match this timestamp */ + if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday]) + return 0; /* the day doesn't match */ + + /* Check the time now */ + packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min; + if ((packet_time < info->time_start) || (packet_time > info->time_stop)) + return 0; + + /* else we match ! */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + const struct ipt_time_info *info = matchinfo; /* match info for rule */ + /* Check the size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info))) + return 0; + /* Now check the coherence of the data ... */ + if ((info->time_start > 1439) || /* 23*60+59 = 1439*/ + (info->time_stop > 1439)) + { + printk(KERN_WARNING "ipt_time: invalid argument"); + return 0; + } + + return 1; +} + +static struct ipt_match time_match += { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + printk("ipt_time loading\n"); + return ipt_register_match(&time_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&time_match); + printk("ipt_time unloaded\n"); +} + +module_init(init); +module_exit(fini); + + +/* The part below is borowed and modified from dietlibc */ + +/* seconds per day */ +#define SPD 24*60*60 + +void +localtime(const time_t *timep, struct tm *r) { + time_t i; + const unsigned int __spm[12] = + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + }; + register time_t work=*timep%(SPD); + r->tm_sec=work%60; work/=60; + r->tm_min=work%60; r->tm_hour=work/60; + work=*timep/(SPD); + r->tm_wday=(4+work)%7; + for (i=1970; ; ++i) { + register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365; + if (work>k) + work-=k; + else + break; + } + r->tm_year=i-1900; + for (i=11; i && __spm[i]>work; --i) ; + r->tm_mon=i; + r->tm_mday=work-__spm[i]+1; +} diff -urN linux/net/ipv4/netfilter/iptable_drop.c linux/net/ipv4/netfilter/iptable_drop.c --- linux/net/ipv4/netfilter/iptable_drop.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/iptable_drop.c Sun Jun 3 06:22:35 2001 @@ -0,0 +1,123 @@ +/* + * Table for dropped packets. + * + * Copyright (C) 2000 Paul `Rusty' Russell + */ +#include +#include + +#define DROPPED_VALID_HOOKS (1 << NF_IP_DROPPING) + +/* Standard entry. */ +struct ipt_standard +{ + struct ipt_entry entry; + struct ipt_standard_target target; +}; + +struct ipt_error_target +{ + struct ipt_entry_target target; + char errorname[IPT_FUNCTION_MAXNAMELEN]; +}; + +struct ipt_error +{ + struct ipt_entry entry; + struct ipt_error_target target; +}; + +static struct +{ + struct ipt_replace repl; + struct ipt_standard entries[1]; + struct ipt_error term; +} initial_table __initdata += { { "drop", DROPPED_VALID_HOOKS, 2, + sizeof(struct ipt_standard) + sizeof(struct ipt_error), + { [NF_IP_DROPPING] 0 }, + { [NF_IP_DROPPING] 0 }, + 0, NULL, { } }, + { + /* DROPPING */ + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, + 0, + sizeof(struct ipt_entry), + sizeof(struct ipt_standard), + 0, { 0, 0 }, { } }, + { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, + -NF_ACCEPT - 1 } } + }, + /* ERROR */ + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, + 0, + sizeof(struct ipt_entry), + sizeof(struct ipt_error), + 0, { 0, 0 }, { } }, + { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, + { } }, + "ERROR" + } + } +}; + +static struct ipt_table packet_dropped += { { NULL, NULL }, "drop", &initial_table.repl, + DROPPED_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL }; + +static const char *dropnames[NF_IP_DROP_MAX] += { [NF_IP_DROP_IGNORES_REDIRECT] = "Invalid redirect", + [NF_IP_DROP_MARTIAN_SOURCE] = "Unexpected source address", + [NF_IP_DROP_MARTIAN_DESTINATION] = "Unexpected destination address", + [NF_IP_DROP_NAT_UNTRACKED] = "NAT dropped untracked packet", + [NF_IP_DROP_NAT_NO_UNIQUE_TUPLE] = "NAT couldn't map connection", + [NF_IP_DROP_NAT_FTP_ERROR] = "NAT failed on malformed FTP packet", +}; + +/* The work comes in here from netfilter.c. */ +static unsigned int +ipt_hook(unsigned int hook, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + const char *reason = NULL; + + if ((*pskb)->nfmark < NF_IP_DROP_MAX) + reason = dropnames[(*pskb)->nfmark]; + + return ipt_do_table(pskb, hook, in, out, &packet_dropped, (void *)reason); +} + +static struct nf_hook_ops ipt_ops += { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_DROPPING, NF_IP_PRI_FILTER }; + +static int __init init(void) +{ + int ret; + + /* Register table */ + ret = ipt_register_table(&packet_dropped); + if (ret < 0) { + printk("iptable_drop: ipt_register_table failed!\n"); + return ret; + } + + /* Register hooks */ + ret = nf_register_hook(&ipt_ops); + if (ret < 0) { + printk("iptable_drop: nf_register_hook failed!\n"); + ipt_unregister_table(&packet_dropped); + } + return ret; +} + +static void __exit fini(void) +{ + nf_unregister_hook(&ipt_ops); + ipt_unregister_table(&packet_dropped); +} + +module_init(init); +module_exit(fini); diff -urN linux/net/ipv4/proc.c linux/net/ipv4/proc.c --- linux/net/ipv4/proc.c Wed May 16 10:21:45 2001 +++ linux/net/ipv4/proc.c Sun Jun 3 06:22:35 2001 @@ -50,6 +50,11 @@ #include #include +#ifdef CONFIG_LIDS +#include +#include +#endif + static int fold_prot_inuse(struct proto *proto) { int res = 0; diff -urN linux/net/ipv4/route.c linux/net/ipv4/route.c --- linux/net/ipv4/route.c Wed May 16 10:31:27 2001 +++ linux/net/ipv4/route.c Sun Jun 3 06:22:35 2001 @@ -1979,6 +1979,9 @@ #ifdef CONFIG_IP_MROUTE struct rtattr *eptr; #endif +#ifdef CONFIG_GRKERNSEC_RANDID + __u16 tmpid; +#endif nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*r)); r = NLMSG_DATA(nlh); nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; @@ -2022,7 +2025,12 @@ ci.rta_error = rt->u.dst.error; ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; if (rt->peer) { +#ifndef CONFIG_GRKERNSEC_RANDID ci.rta_id = rt->peer->ip_id_count; +#else + get_random_bytes(&tmpid,sizeof(__u16)); + ci.rta_id = htons(tmpid); +#endif if (rt->peer->tcp_ts_stamp) { ci.rta_ts = rt->peer->tcp_ts; ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; @@ -2473,8 +2481,24 @@ ip_rt_gc_interval; add_timer(&rt_periodic_timer); +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + proc_net_create ("rt_cache", S_IRUSR|S_IRGRP, rt_cache_get_info); +#elif CONFIG_GRKERNSEC_PROC_USER + proc_net_create ("rt_cache", S_IRUSR, rt_cache_get_info); +#else proc_net_create ("rt_cache", 0, rt_cache_get_info); +#endif +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP +#ifdef CONFIG_NET_CLS_ROUTE + create_proc_read_entry("net/rt_acct", S_IRUSR|S_IRGRP, 0, ip_rt_acct_read, NULL); +#endif +#elif CONFIG_GRKERNSEC_PROC_USER +#ifdef CONFIG_NET_CLS_ROUTE + create_proc_read_entry("net/rt_acct", S_IRUSR, 0, ip_rt_acct_read, NULL); +#endif +#else #ifdef CONFIG_NET_CLS_ROUTE create_proc_read_entry("net/rt_acct", 0, 0, ip_rt_acct_read, NULL); +#endif #endif } diff -urN linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- linux/net/ipv4/tcp_ipv4.c Wed Apr 25 14:57:39 2001 +++ linux/net/ipv4/tcp_ipv4.c Sun Jun 3 06:22:35 2001 @@ -63,6 +63,10 @@ #include #include +#ifdef CONFIG_LIDS +#include +#endif + extern int sysctl_ip_dynaddr; /* Check TCP sequence numbers in ICMP packets. */ @@ -177,12 +181,22 @@ int high = sysctl_local_port_range[1]; int remaining = (high - low) + 1; int rover; +#ifdef CONFIG_GRKERNSEC_RANDSRC + unsigned long longrover; +#endif spin_lock(&tcp_portalloc_lock); +#ifdef CONFIG_GRKERNSEC_RANDSRC + remaining = 32767; + do { + get_random_bytes(&longrover,sizeof(longrover)); + rover=low+(longrover % (high - low)); +#else rover = tcp_port_rover; do { rover++; if ((rover < low) || (rover > high)) rover = low; +#endif head = &tcp_bhash[tcp_bhashfn(rover)]; spin_lock(&head->lock); for (tb = head->chain; tb; tb = tb->next) @@ -192,7 +206,26 @@ next: spin_unlock(&head->lock); } while (--remaining > 0); +#ifndef CONFIG_GRKERNSEC_RANDSRC tcp_port_rover = rover; +#endif +#ifdef CONFIG_GRKERNSEC_RANDSEC + remaining = (high - low) + 1; + rover = tcp_port_rover; + do { rover++; + if ((rover < low) || (rover > high)) + rover = low; + head = &tcp_bhash[tcp_bhashfn(rover)]; + spin_lock(&head->lock); + for (tb = head->chain; tb; tb = tb->next) + if (tb->port == rover) + goto next2; + break; + next2: + spin_unlock(&head->lock); + } while (--remaining > 0); + tcp_port_rover = rover; +#endif spin_unlock(&tcp_portalloc_lock); /* Exhausted local port range during search? */ @@ -1031,7 +1064,9 @@ struct tcphdr *th = skb->h.th; struct tcphdr rth; struct ip_reply_arg arg; - +#ifdef CONFIG_GRKERNSEC_STEALTH_RST + return; +#endif /* Never send a reset in response to a reset. */ if (th->rst) return; @@ -1608,6 +1643,16 @@ if (th->doff < sizeof(struct tcphdr)/4) goto bad_packet; +#ifdef CONFIG_GRKERNSEC_STEALTH_FLAGS + if(th->fin && th->syn) + goto discard_it; + + if(!(th->ack || th->syn || th->rst) || th->res1) + goto discard_it; + + if(th->fin && th->psh && th->urg) + goto discard_it; +#endif if (!pskb_may_pull(skb, th->doff*4)) goto discard_it; @@ -1657,6 +1702,9 @@ return ret; no_tcp_socket: +#ifdef CONFIG_LIDS_PORT_SCAN_DETECTOR + lids_check_scan(skb->nh.iph->saddr,ntohs(th->dest)); +#endif if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); diff -urN linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- linux/net/ipv4/udp.c Thu Apr 12 12:11:39 2001 +++ linux/net/ipv4/udp.c Sun Jun 3 06:22:36 2001 @@ -94,6 +94,9 @@ #include #include +#ifdef CONFIG_LIDS +#include +#endif /* * Snmp MIB for the UDP layer */ @@ -909,13 +912,17 @@ sock_put(sk); return 0; } - /* No socket. Drop packet silently, if checksum is wrong */ +#ifdef CONFIG_LIDS_PORT_SCAN_DETECTOR + lids_check_scan(saddr,ntohs(uh->dest)); +#endif if (udp_checksum_complete(skb)) goto csum_error; UDP_INC_STATS_BH(UdpNoPorts); +#ifndef CONFIG_GRKERNSEC_STEALTH_UDP icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); +#endif /* * Hmm. We got an UDP packet to a port to which we diff -urN linux/net/netsyms.c linux/net/netsyms.c --- linux/net/netsyms.c Fri Apr 27 14:15:01 2001 +++ linux/net/netsyms.c Sun Jun 3 06:22:36 2001 @@ -561,6 +561,7 @@ EXPORT_SYMBOL(nf_setsockopt); EXPORT_SYMBOL(nf_getsockopt); EXPORT_SYMBOL(ip_ct_attach); +EXPORT_SYMBOL(nf_drop_okfn); #endif EXPORT_SYMBOL(register_gifconf); diff -urN linux/net/socket.c linux/net/socket.c --- linux/net/socket.c Wed Apr 25 16:13:50 2001 +++ linux/net/socket.c Sun Jun 3 06:22:36 2001 @@ -329,8 +329,11 @@ * with shared fd spaces, we cannot solve is inside kernel, * but we take care of internal coherence yet. */ - +#ifdef CONFIG_LIDS +int sock_map_fd(struct socket *sock) +#else static int sock_map_fd(struct socket *sock) +#endif { int fd; struct qstr this; @@ -912,7 +915,17 @@ { int retval; struct socket *sock; - +#ifdef CONFIG_GRKERNSEC_SOCKET_ALL + if((in_group_p(CONFIG_GRKERNSEC_ALL_GID)) && (family != AF_UNIX) && (family != AF_LOCAL)){ + security_alert("attempted socket(%d,%d,%d) by (%.16s:%d), " + "UID(%d), EUID(%d), parent (%.16s:%d), UID(%d), " + "EUID(%d)","attempted sockets",family,type,protocol, + current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + return -EACCES; + } +#endif retval = sock_create(family, type, protocol, &sock); if (retval < 0) goto out; @@ -1009,7 +1022,17 @@ struct socket *sock; char address[MAX_SOCK_ADDR]; int err; - +#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER + if((in_group_p(CONFIG_GRKERNSEC_SERVER_GID)) && (umyaddr->sa_family != AF_UNIX) && (umyaddr->sa_family != AF_LOCAL)){ + security_alert("attempted bind() by (%.16s:%d), " + "UID(%d), EUID(%d), parent (%.16s:%d), UID(%d), " + "EUID(%d)","attempted binds", + current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + return -EACCES; + } +#endif if((sock = sockfd_lookup(fd,&err))!=NULL) { if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) @@ -1117,10 +1140,20 @@ struct socket *sock; char address[MAX_SOCK_ADDR]; int err; - sock = sockfd_lookup(fd, &err); if (!sock) goto out; +#ifdef CONFIG_GRKERNSEC_SOCKET_CLIENT + if((in_group_p(CONFIG_GRKERNSEC_CLIENT_GID)) && (uservaddr->sa_family != AF_UNIX) && (uservaddr->sa_family != AF_LOCAL)){ + security_alert("attempted connect() to fd %d by (%.16s:%d), " + "UID(%d), EUID(%d), parent (%.16s:%d), UID(%d), " + "EUID(%d)","attempted connects",fd, + current->comm,current->pid,current->uid,current->euid, + current->p_pptr->comm,current->p_pptr->pid,current->p_pptr->uid, + current->p_pptr->euid); + return -ENETUNREACH; + } +#endif err = move_addr_to_kernel(uservaddr, addrlen, address); if (err < 0) goto out_put;