====== General impression of RSBAC ====== * Pros * Very powerful enhancement of LINUX kernel * Nice design, which allows bunch off cool features like transaction, secure_delete, fd hiding... * Cool community, still small but efficient and reactive * Cons * The lack of documentations for some modules * You need strong knowledge of UNIX system to setup well RSBAC policies * For a best enforcement, small changes must be done to distribution (like restoring dynamic fd (/proc, /dev, shm)) * Their isn't any reference policies for now \\ ====== Howtos ====== ===== Howto protect sshd ===== ==== Setup UM ==== First we need to setup RSBAC User Management modules. In /etc/nsswitch.conf we may have '[passwd|shadow|group]: compat rsbac', and in /etc/pam.d/system-auth '[auth|account|password|session] sufficient pam_rsbac.so' before any pam_unix.so lines. Then : secoff$ rsbac_useradd -O && rsbac_groupadd -O secoff$ rsbac_passwd -n secoff ==== Grant sshd ==== Sshd must be allow to change his identity during key exchange secoff$ for user in 0 22; do for param in "" "-e" "-f"; do auth_set_cap $param FD add /usr/sbin/sshd $user done done Now we want sshd to be allow to change his identity only to an user who have been properly authenticated (by entering his password). secoff$ attr_set_fd AUTH FD auth_may_setuid 3 /usr/sbin/sshd Note: if you use CONFIG_RSBAC_AUTH_DAC_*, CONFIG_RSBAC_DAC_* you must add caps for allowed user, because they don't use the special auth_may_setuid value : 'Last Auth...' secoff$ for user in 400 "1000 3000"; do for param in "-e" "-f"; do auth_set_cap $param FD add /usr/sbin/sshd $user done done ==== Run sshd ==== Add the following parameter to sshd init script: -o "HostbasedAuthentication no" -o "PasswordAuthentication yes" -o "ChallengeResponseAuthentication no" -o "UsePAM yes" -o "UsePrivilegeSeparation yes" -o "PermitRootLogin no" ==== Test ==== ssh secoff@your_server If you use the unix password, then you'll get : 'rsbac_adf_request(): request CHANGE_OWNER, ..., prog_name sshd, prog_file /usr/sbin/sshd, uid 0, remote ip ..., target_type PROCESS, ...., attr owner, value 400, result NOT_GRANTED by AUTH'. Now you have to use the rsbac password, like that the kernel will know that secoff have been authenticate, then he'll allow sshd to change his identity. ==== Conclusion ==== This is a pretty good security measure, because even if sshd get's cracked, it won't be able to gain secoff credential without his passw ord. ===== Howto use RES module ===== RES allows to enforce user limits (ulimit). Here are somes examples: secoff$ for user in -4 root; do attr_set_user RES $user res_max fsize 250000 # user won t create file more than 1G (block size = 4096) attr_set_user RES $user res_max stack 100000 # user stack won t get bigger than 100 KB attr_set_user RES $user res_max nofile 1024 # user won t open more than 1024 fds at a time attr_set_user RES $user res_min core -1 # user will coredump by default attr_set_user RES $user res_max nproc 200 # user won t start more than 200 process attr_set_user RES $user res_max as 100000000 # user s process won t get bigger than 100MB done secoff$ attr_set_user RES root res_role 0 And that's it ! user$ ulimit -a core file size (blocks, -c) unlimited data seg size (kbytes, -d) unlimited file size (blocks, -f) 976 max locked memory (kbytes, -l) unlimited max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) 97 cpu time (seconds, -t) unlimited max user processes (-u) 200 virtual memory (kbytes, -v) 97656 file locks (-x) unlimited user$ ulimit -u 1024 -sh: ulimit: max user processes: cannot modify limit: Operation not permitted user$ for i in `seq 0 250`; do sleep 5& done .... [195] 12759 -sh: fork: Resource temporarily unavailable ===== Howto protect Kernel code against tampering ===== ==== Howto protect /boot device ==== In this example, we don't want anyone, except secoff, to be able to update kernel in /boot. First, let's protect /boot directory with RC # We create a new FD rc_type rc_set_item TYPE `rc_get_item list_unused_fd_type_nr` type_fd_name BOOT_FD # We allow secoff to access this type rc_set_item ROLE 1 type_comp_fd $BOOT_FD A # We set /boot rc_type_fd attr_set_fd RC FD rc_type_fd $BOOT_FD /boot # Repeat this last one after mounting the device: When a directory get s mounted, #its attributes are replaced by the ones of the new device's root. This is good, but root can still access boot data directly through /dev/sda1. # We create a new DEV rc_type rc_set_item TYPE `rc_get_item list_unused_dev_type_nr` type_dev_name BOOT_Device # We allow secoff to access this type rc_set_item ROLE 1 type_comp_dev $BOOT_Device A # We set /dev/sda1 rc_type attr_set_file_dir -d DEV b8:1 rc_type $BOOT_Device Finally we wan't secoff to be able to mount the device: # Let s fool mount attr_set_fd GEN FD fake_root_uid 3 /bin/mount # And allow secoff to changes files in /boot, the GEN way: attr_set_fd GEN FD linux_dac_disable 1 /boot # do that when /boot is mounted ! # or the CAP way: attr_set_user -a CAP secoff min_caps FS_MASK ===== Howto use RSBAC transactions ===== ==== How transactions works ==== RSBAC transactions works pretty much the same as SQL databases transactions... It ease policies development, for example you can do without loads of NOT_GRANTED: * set rc_type BIN_FD /bin * set roles type_comp_fd 0 -EXECUTE -MAP_EXEC * set roles type_comp_fd $BIN_FD EXECUTE MAP_EXEC * rsbac_list_ta commit There are four commands to use : * rsbac_list_ta -t 900 begin: this creates a new transaction valid for 15 minutes * rsbac_list_ta -t 900 -N ta_number refresh: this resets the transaction timeout * rsbac_list_ta -N ta_number commit: this makes all the changes effective * rsbac_list_ta -N ta_number forget: this discards all the changes done in transaction To monitor what's going on, read the '/proc/rsbac-info/gen_lists' file finally, there are two way to change attributes in a transaction, you can either * pass the transaction number to the tool: attr_set_fd -N ta_number RC FD rc_type 2 /whatever * set the environment variable RSBAC_TA `rsbac_list_ta -b -t 900 begin` rsbac_menu ... export RSBAC_TA=ta_number ==== User creation examples ==== Here is a small script which show how to use transaction for user creation purposes. #!/bin/sh function abord { echo -e "\n\e[1;33m*\e[1;32m $1\e[0;37m"; rsbac_list_ta -N $RSBAC_TA forget; exit 1 } export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin if [ -z "$1" ]; then echo "usage: $0 username"; exit 1; fi; export RSBAC_TA="`rsbac_list_ta -t 10 begin`" rsbac_useradd -x 60 -w 30 -g users -p '' $1 || myabord "Could not create user" rsbac_usermod -l 0 $1 || myabord "Could not usermod" attr_set_user RC $1 rc_def_role `rc_get_item list_roles | grep ' Remote_Users$' | awk '{print $1}'` || myabord "Could not set def role" attr_set_user CAP $1 min_caps IPC_LOCK || myabord "attr_set_user" attr_set_user CAP $1 cap_ld_env 1 || myabord "attr_set_user" rsbac_list_ta -N $RSBAC_TA commit || myabord "rsbac_list_ta" mkdir -m 700 /home/$1 chown $1 /home/$1 ===== Howto use network template ===== ==== How networks templates works ==== First some documentation. For each network access, the adf will try to match the object with a network template from lowest to highest ordering number until it matches one. So general purpose templates should have high numbers, and more detailed templates should have low numbers. * When a socket is created, it emits a CREATE request over a network object with unknown local and remote address. The template matching uses the local address. * If the socket is binded/listened, it emits a BIND/LISTEN request over a network object with the desired local address and an unknown remote address. The template matching uses the local address. Then when a client connects to the server, all matching are done with the remote address and remote port. Except for GET_STATUS_DATA request, matching is done with remote address but local port. * If the socket is connected and used with another endpoint, it emits CONNECT/SEND/RECEIVE requests, and the template matching uses the remote address. * Finally, when the socket is closed, it emits a NET_SHUTDOWN/CLOSE request, and the template matching uses the remote address ==== Web server example ==== Let's try to enforce network access of a web server First, we create network template, with rsbac_nettemp_def_menu, and for each template we create a new rc_netobj_type with the name + _NETOBJ ^ Name ^ Nr ^ Family ^ Type ^ Address ^ Protocol ^ Ports ^ | DNS_SRV | 53 | INET | DGRAM | nameserver/32 | UDP | 53:53 | | TCP | 300000 | INET | STREAM | 0.0.0.0/0 | TCP | | | UDP | 300001 | INET | DGRAM | 0.0.0.0/0 | UDP | | | NETLINK | 300002 | NETLINK | RAW | | ANY | | | HTTPS | 200443 | INET | STREAM | 0.0.0.0/0 | TCP | 443:443 | | LAN_TCP | 100000 | INET | STREAM | 192.168.0.0/16 | TCP | | \\ The NETLINK socket is a special socket family for asking network configuration to the kernel. So first, we must allow apache to access this template. Then apache will create a TCP socket. At this point the netobj is defined as follow : 'INET STREAM proto TCP local 0.0.0.0:0 remote 0.0.0.0:0'. So the TCP template will match. Then apache will bind this socket. The netobj is defined as follow: 'INET STREAM proto TCP local 0.0.0.0:443 remote 0.0.0.0:0, attr sock_type, value STREAM', aka HTTPS Finally, when a browser connects to the server, the netobj is defined as follow : 'INET STREAM proto TCP local eth0:SRV_ADDR:443 remote CLIENT_ADDR:35967' aka LAN_TCP So here is the list of necessary type_comp apache needs to be available for lan clients: ^ Netobj ^ Access ^ | NETLINK_NETOBJ | CREATE GET_STATUS_DATA BIND RECEIVE SEND | | TCP_NETOBJ | CREATE GET_STATUS_DATA MODIFY_SYSTEM_DATA | | HTTPS_NETOBJ | BIND LISTEN MODIFY_SYSTEM_DATA NET_SHUTDOWN | | LAN_TCP | ACCEPT GET_STATUS_DATA READ RECEIVE WRITE SEND NET_SHUTDOWN | | UDP_NETOBJ | CREATE GET_STATUS_DATA MODIFY_SYSTEM_DATA IOCTL NET_SHUTDOWN | | DNS_SRV_NETOBJ | CONNECT SEND RECEIVE | \\ And here you go !