This post appeared originally in our sysadvent series and has been moved here following the discontinuation of the sysadvent microsite

I’ve always had a bad conscience about the audit trail on the servers I manage. Sure, we use personal accounts and sudo, so we know who ran every command. Unfortunately, the command in the sudo log is often just “bash”.

The reason for this is simple: It is quite awkward to work in the shell when TAB completion doesn’t work. You want to read the error log in /var/log/httpd? Too bad, the directory is off limits for normal users. So what is the filename? Well, first run “sudo ls” on it, then cut and paste the filename after “sudo less”. No, that will make me go mad. “sudo -i” it is.

After lamenting about this recently I had a lightning bulb moment: Isn’t this the sort of thing Linux capabilities(7) set out to handle? And lo and behold:

CAP_DAC_OVERRIDE
    Bypass file read, write, and execute permission checks.  (DAC is
    an abbreviation of "discretionary access control".)

CAP_DAC_READ_SEARCH
    * Bypass file read permission checks and directory read and exe‐
    cute permission checks;

The first one is really powerful - it allows all read and write access to files, as if you were root.

The other one is exactly what we need. It allows all getdents(2) and stat(2) calls as if you were root.

How do capabilities work?

Capabilities are a set of permissions which are granted to an executable. Not a process, not a user, not a session. The original use case for capabilities was tcpdump, shortly followed by ping. Let’s have a look:

$ ls -l /bin/ping
-rwxr-xr-x. 1 root root 44752 Nov 19  2015 /bin/ping*

The period after r-x indicates the file has extended attributes, and capabilities are among them. Other than that there are no other special features.

$ getcap /bin/ping
/bin/ping = cap_net_admin,cap_net_raw+ep

This is what grants ping the ability to send raw ICMP packets on the network, even if the user isn’t root. Before capabilities came along, ping was typically setuid root. In ping’s case, we don’t mind that every user gets access to this ability, but for a shell it would raise privacy issues.

Applying capabilities to bash

Let’s try it out:

cp /bin/bash /tmp/testsh
chmod 700 /tmp/testsh
sudo setcap CAP_DAC_READ_SEARCH=ep /tmp/testsh

=ep means effective and permissive. Don’t blame me for obtuse syntax :-).

If you run /tmp/testsh now, you will be able to use TAB-completion within /var/log/httpd/ or wherever else you like. Try it out! Go wild! You will still need sudo to do destructive operations. You can check the capabilities of a process like this:

$ grep CapPrm /proc/$$/status
CapPrm:  0000000000000004

Notice that bit 4 is set. Compare with:

$ grep CapPrm /proc/self/status
CapPrm:  0000000000000000

Here /proc/self is the grep process spawned by the shell, so this demonstrates that the capability is not inherited by child processes.

Adding tabashco!

Having your own personal /tmp/testsh is fine, but it would be better to share it with your sysadmin colleagues.

As mentioned earlier, the capability is granted to the program, so we need to use Unix permissions to restrict access to these super powers. A common denominator for access could be membership in the group “wheel”.

Basically, we create a copy of /bin/bash, chmod it to 550 and change its group. After a brief brainstorming (“adminbash”, “tab-bash”, etc.), I ended up with “tabashco” (not a trademark - yet).

The Puppet code to make this copy looks like this:

class baseconfig::tabashco(
  $path = '/usr/local/bin',
  $group = 'wheel',
)
{
  file { "${path}/tabashco":
    source => '/bin/bash',
    owner  => 'root',
    group  => $group,
    mode   => '0550',
  }

  exec { "setcap cap_dac_read_search=ep ${path}/tabashco":
    path        => '/usr/sbin:/sbin',
    refreshonly => true,
    subscribe   => File["${path}/tabashco"]
  }
}

Puppet will make sure that tabascho is updated whenever /bin/bash changes.

Finally, you need to put code like this in your ~/.bash_profile (or in a file in /etc/profile.d)

if [ -x /usr/local/bin/tabashco ]; then
    case $0 in
        *tabashco) : ;;
        *) echo "Spicing up your shell!"
           exec tabashco "$@" ;;
    esac
fi

PS: Don’t let the PHP users know that they can do setcap CAP_DAC_OVERRIDE=ep /usr/sbin/httpd On the other hand, perhaps you should - after all it is better than chmod -R a+rwx /)

Kjetil Homme

Senior Systems Consultant at Redpill Linpro

Kjetil works with infrastructure at Redpill Linpro. He's been with Redpill Linpro for 8 years, and is currently working on automating our IT operations through Puppet, our storage solutions and backup rig. Kjetil been working with Linux since the early 90's and has made several contributions to the kernel and other associated projects.

Just-Make-toolbox

make is a utility for automating builds. You specify the source and the build file and make will determine which file(s) have to be re-built. Using this functionality in make as an all-round tool for command running as well, is considered common practice. Yes, you could write Shell scripts for this instead and they would be probably equally good. But using make has its own charm (and gets you karma points).

Even this ... [continue reading]

Containerized Development Environment

Published on February 28, 2024

Ansible-runner

Published on February 27, 2024