====== 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 !