I was asked, what is the correct way to drop privileges in Linux.

So here is a list of things I usually do, when implementing unprivileged sub process:

  • fork
  • in some cases you would also want to do these:
    • clear the environment(leave only the required variables)
    • close all file descriptors(except the ones you need)
    • clear memory regions that are not supposed to be accessible by the child
    • change the inheritable capabilities
    • change namespaces or control groups
  • clear all groups
  • chroot, if it is used(I suggest using it)
  • setgid
  • setuid

In certain cases it may be a good idea to also call setsid() in the child, so your child will become a session leader.

Posted by HackMan
Dated: 10th July 2020
Filled Under: Uncategorized
Comments: Post the 1st one!

If you need to SNAT local processes over a specific interface(for example a tunnel) there are a few things you have to do and this artical describes the required steps.

= Sysctls =
More specific, you need to disable the rp_filter over the interface you are receiving the traffic. For tunnels this usually is tun[0-9]

Note: ”’Without the above changes, traffic goes out the interface and comes back to the machine, but it is NEVER delivered to the process. ”’

= Routing =
You need a separate routing table. I will be using the sg table with id 100:
root@enot:~# cat /etc/iproute2/rt_tables
# reserved values
255 local
254 main
253 default
100 sg
0 unspec
In this table you have to have default gw via the tunnel device and routing to the ip that is sending the traffic:
root@enot:~# ip r l t sg
default via dev tun0 dev tun0 scope link src

Finally you have to route traffic via this table. Since we have to select specific processes and not the whole server, we will use FWMARKs to achieve that.
root@enot:~# ip ru a fwmark 10 t sg
The result should be something like this:
root@enot:~# ip ru l
0: from all lookup local
32765: from all fwmark 0xa lookup sg
32766: from all lookup main
32767: from all lookup default

= iptables =
Now in order to select certain processes we can either use a specific pid(this is supported with the “-m owner –pid-owner PID” option but its available only with newer iptables.)
iptables -t mangle -A OUTPUT -j MARK --set-mark 10 -m owner --pid-owner 1012
Where 1012 is the pid of the process who’s traffic we want to mark and put inside the sg routing tables.

On older linuxes we can use “-m owner –uid-owner username”.
iptables -t mangle -A OUTPUT -j MARK --set-mark 10 -m owner --uid-owner site
Where “site” is the actual linux username. Now all outgoing traffic of processes started by user site will be marked with mark 10 and thus go trough the sg routing table.

You could also use the “-m owner –gid-owner groupname” option for a whole group.
iptables -t mangle -A OUTPUT -j MARK --set-mark 10 -m owner --gid-owner users

Note: ”’The above rules are in the mangle table, so the traffic can be marked before a routing decision is taken. The rules are valid in the nat table, but does not work there!”’

Now the final step is to SNAT the traffic to the IP form the tun interface:
root@enot:~# ip a l tun0
3: tun0: mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 500
inet scope global tun0
valid_lft forever preferred_lft forever

Add the NAT rule:
iptables -t nat -A POSTROUTING -j SNAT -o tun0 --to

We need the SNAT, because otherwise the traffic may leave our machine via the tun0 interface but with wrong source IP and obviously, never come back to us.

Posted by HackMan
Dated: 13th December 2019
Filled Under: Uncategorized
Comments: Post the 1st one!

At the office we have this joke, that the shortest program, that produces “Segmentation fault” is:

$ echo Segmentation fault (core dumped)
Segmentation fault (core dumped)

We had this joke, after a collegue of ours debugged that exact program for 20min, before he realized that it actually printed sefgault :)

However, one of the collegues decided to challenge that and he wrote this piece of code:

$ echo 'int main() { int *i=0; *i=0; }' | g++ -x c++ - ; ./a.out
Segmentation fault (core dumped)

At that point I jumped in, and “optimized it” :) :

$ echo 'int main(){int *i;*i=0;}'|g++ -x c++ -;./a.out

We had another “optimization”:

$ echo 'main(){int*i;*i=0;}'|g++ -x c++ -;./a.out

Then the first collegue decided that it would be easier in shell:

sh -c 'kill -11 $$'

I manged to make another optimization :) :

$ sh $(kill -11 $$)

In the end, one college from our Plovdiv office decided to share with us, this link :)

Posted by HackMan
Dated: 4th November 2019
Filled Under: Uncategorized
Comments: Post the 1st one!

My new expensive toy just came to life :)

localhost#show version
Arista DCS-7050QX-32-F
Hardware version:    02.11
Serial number:       JPE1523XXXX
System MAC address:  001c.73XX.XXXX

Software image version: 4.14.5FX.2
Architecture:           i386
Internal build version: 4.14.5FX.2-2328441.4145FX2
Internal build ID:      5f369972-3e94-403c-aee9-dd4cfba34d46

Uptime:                 2 hours and 45 minutes
Total memory:           3981332 kB
Free memory:            1292296 kB

Me and Vasil are planing to use this for our ISP project :)

After setting up the IP and looking around in the CLI, the first actual configuration change that I did was prompt %h%p%s, because the stupid CLI interface doesn’t leave a space between the prompt and the commands :)

Posted by HackMan
Dated: 26th September 2017
Filled Under: Uncategorized
Comments: Post the 1st one!

If you want to do A/B split testing with nginx, you usually are directed to the split clients module.

However, most of us don’t have this module compiled into their nginx installations and this usually results in using our code to do the actual A/B spliting.

Here is how you can do that, without the addition of other modules.

First you need to create a map that will hold your two URLs:

map $time_local $split_redirect {
# 27/Jul/2017:02:33:06 -0500
    "~[13579] \-.*$" @location1;
    "~[02468] \-.*$" @location2;

As you can see, I’m using the $time_local variable for the split. Everyone that access the site on even seconds will go to @location1 and the others to @location2. That is all the “magic” that you would need :)

Then you have two options :) First is to use if, but we know if is evil, so the second option is to use internal error redirects :)

    location ~ ^/page {
        recursive_error_pages on;
        error_page 412 = $split_redirect;
        return 412;

    location @location1 {
        return 301 http://site/page1.html;

    location @location2 {
        return 301 http://site/page2.html;

if you decide to go the if route, here is how you should do it.

You need to change the map to have your locations:

map $time_local $split_redirect {
# 27/Jul/2017:02:33:06 -0500
    "~[13579] \-.*$" http://site/page1.html;;
    "~[02468] \-.*$" http://site/page2.html;;

and then simply add this if to your config:

    if ($split_redirect) {
        rewrite ^ $split_redirect permanent;
Posted by HackMan
Dated: 27th July 2017
Filled Under: Uncategorized
Comments: Post the 1st one!

I’m using bird on my routers for a few years now, and every time I setup a new router I add these shell functions to help me monitor and debug network issues:

function bgp_states {
    for i in $(birdc show protocols|sed 's/\s\+/|/g'|grep BGP); do
        a=(${i//|/ })
        echo ${a[*]}|awk '{printf "%-16s\t%s\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4, $5, $6;}'
        birdc show protocol all ${a[0]}|grep Routes

function show_route {
    if [[ $1 == for ]]; then range=$2; fi
    if [[ $1 == all ]]; then all='all'; range=$2; fi
    if [[ $range =~ [a-z] ]]; then
        range=$(host -t A $range|head -n1|cut -d ' ' -f 4)
    birdc show route $all for $range table main

function bgp_info {
    birdc "show protocols all $1"
Posted by HackMan
Dated: 5th April 2017
Filled Under: Uncategorized
Comments: Post the 1st one!

I was featured at PerlAdvent calendar 2016 with my article about controlling Linux Containers with Perl

The PerlAdvent calendar is a very nice way to countdown the days till Christmas :)

Posted by HackMan
Dated: 20th December 2016
Filled Under: Uncategorized
Comments: Post the 1st one!

Since CentOS 6.x is an old distro it lacks newer GCC and thus you can’t use things like stack protector and some of the PAX security stuff :(
What you can do however, is to install the SCL repo and from there the devtoolset-4:

# yum install centos-release-scl.noarch centos-release-scl-rh.noarch
# yum install devtoolset-4 devtoolset-4-gcc-plugin-devel.x86_64

The above will install gcc and g++ 5.2. But before jumping into building your kernel you need to also install:

# yum install libmpc-devel.x86_64 libmpc.x86_64

Which is needed for proper gcc-plugins support.
Now you can simply start building your kernel:

# scl enable devtoolset-4 bash
# cd /usr/src/kernels/linux-4.4.34
# make

Posted by HackMan
Dated: 22nd November 2016
Filled Under: CentOS, Linux General, Technology
Comments: Post the 1st one!

After yum or apt-get upgrade you are left with services that need to be restarted in order to start using the new libraries you have just upgraded.
Sometimes you know what to restart but if you haven’t done upgrade in a while it is highly possible that you can miss a service.
The following simple two liner will help you find the services you need to restart:

function check_restart() {
  all_maps=$(grep deleted /proc/[0-9]*/maps|grep -vE '\/(SYSV|dev\/)'|cut -d ':' -f1|sort|uniq)
  for i in $all_maps; do pid=${i/\/maps}; echo "${pid/*\/} $(cat ${i/maps/cmdline}|tr '\0' ' ')"; done|sort|uniq
Posted by HackMan
Dated: 22nd November 2016
Filled Under: Linux General, Technology
Comments: Post the 1st one!

Yesterday I had a very interesting conversation about congestion control and how it affects long lived connections.
So I decided to do a very simple comparison. I created a 100MB file(dd if=/dev/zero of=test-file bs=1M count=100).

  • Scalable:
  • test-file  100%[==============================================>] 100.00M 5.13MB/s in 23s
    2016-02-28 19:40:55 (4.35 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Illinois:
  • test-file  100%[==============================================>] 100.00M 4.20MB/s in 24s
    2016-02-28 19:21:57 (4.13 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Yeah:
  • test-file  100%[==============================================>] 100.00M 5.03MB/s in 25s
    2016-02-28 19:34:01 (4.02 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Bic:
  • test-file  100%[==============================================>] 100.00M 1.98MB/s in 31s
    2016-02-28 19:39:34 (3.21 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Htcp:
  • test-file  100%[==============================================>] 100.00M 2.76MB/s in 34s
    2016-02-28 19:36:12 (2.93 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Cubic:
  • test-file  100%[==============================================>] 100.00M 1.54MB/s in 45s
    2016-02-28 19:30:23 (2.21 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Hybla:
  • test-file  100%[==============================================>] 100.00M 1.52MB/s in 50s
    2016-02-28 19:38:31 (2.01 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Westwood:
  • test-file  100%[==============================================>] 100.00M 2.81MB/s in 53s
    2016-02-28 19:35:26 (1.90 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Reno:
  • test-file  100%[=============================================>] 100.00M 1.48MB/s in 62s
    2016-02-28 19:27:38 (1.62 MB/s) - ‘test-file’ saved [104857600/104857600]
  • Veno:
  • test-file  100%[=============================================>] 100.00M 1.22MB/s in 64s
    2016-02-28 19:23:14 (1.56 MB/s) - ‘test-file’ saved [104857600/104857600]
  • LP:
  • test-file  100%[=============================================>] 100.00M 1.24MB/s in 95s
    2016-02-28 19:32:54 (1.05 MB/s) - ‘test-file’ saved [104857600/104857600]

Some information on the best algorithms:

Posted by HackMan
Dated: 29th February 2016
Filled Under: Linux General, Networking, Technology
Comments: Post the 1st one!