CAP_DAC_OVERRIDE usage in Samba on SELinux enabled systems

Most of us might have heard about capabilities from POSIX world in general. They are normally associated with processes with the purpose of performing permission checks. Traditionally in UNIX processes are either run as privileged or unprivileged. Privileged process are those with superuser power which can bypass permission checks imposed by the kernel. These privileges can further be fine grained into distinct units, known as capabilities, which can then be independently enabled or disabled on a per-thread basis. Following are some among the many capabilities available on Linux:

  • CAP_AUDIT_CONTROL
  • CAP_CHECKPOINT_RESTORE
  • CAP_CHOWN
  • CAP_DAC_OVERRIDE
  • CAP_FOWNER
  • CAP_KILL
  • CAP_LINUX_IMMUTABLE

You can find more details on all available capabilities from manual page for capabilities(7). But we rather focus on CAP_DAC_OVERRIDE.

DAC, DAC override and CAP_DAC_OVERRIDE

DAC or Discretionary Access Control is commonly used in conjunction with permissions on files. They point towards the basic read, write and execute permissions(rwx) for user, group and others(ugo). The process of bypassing such permission checks is widely termed as DAC override and we have a particular capability which allows us to achieve this goal for unprivileged processes called CAP_DAC_OVERRIDE. Capabilities were initially designed in such a way that not every process become root to perform a subset of tasks a superuser can do. Thus acquiring CAP_DAC_OVERRIDE does not mean you are on top of the world. But it definitely helps us to avoid permission checks without the cost of becoming root.

SELinux beyond capabilities

Security-Enhanced Linux (SELinux) is a mandatory access control (MAC) security mechanism implemented in the kernel. Under a strict enforcing mode it denies everything and goes through the predefined set of exception policies to give each element of the system(service, program or user) only the access required to complete its action. Accordingly we have 3 different modes in which SELinux operates in a system:

  • Enforcing: enforces the already written security policy and deny everything else
  • Permissive: even though enabled it is not enforced; instead warn and log actions
  • Disabled: completely turned off

All processes and files have an SELinux security context. Access is only allowed between similar types. Any attempt outside existing security policy results in denial or warn based on the SELinux mode under which it operates. On those systems where SELinux is enabled it is the highest authority in maintaining access via various types and contexts i.e, DAC alone can’t give you guaranteed access. You can look at SELinux docs from Red Hat, Fedoraproject etc to better understand the concept and configuration. Since we concentrate more on CAP_DAC_OVERRIDE I can only suggest going through following blog articles from Dan and Lukas which explains the interaction with SELinux in detail.

Situation with Samba

Samba is a free software implementation of SMB protocol providing file and print services capable of integrating with Windows server domain as a Domain Controller or as a domain member. You can grab more details from Samba project page. Authentication being an integral part of SMB protocol the main Samba daemon(smbd) is usually forked per client connection and assumes correspondingly mapped user ID to perform various file system operations. But there are circumstances under which special superuser privileges are necessary to carry out actions outside unprivileged namespace. One such example is the case where Security Descriptors(SD) from Windows clients are stored in extended attributes under security namespace on files. This is done to avoid the lossy mapping from SMB ACLs to POSIX ACLs where limited fine grained access control is the roadblock.

In such a situation ACLs are written into an extended attribute “security.NTACL“. Usually with DAC only root user is allowed to access/read from security namespace of extended attributes. On the other side smbd is run as the actual authenticated user. But there are differences where the file system ACLs would deny access that is still required for correctly implementing SMB semantics. Thus Samba’s become_root() mechanism is widely used in those cases for a brief time to make things correct. The problem with become_root() is, that it is an expensive operation. In addition to that we don’t require the whole superuser privileges to bypass basic permission checks.

Recently a change came in to prefer CAP_DAC_OVERRIDE over become_root(). This way it is likely a lot cheaper. On the contrary in a SELinux enabled system we encountered direct failures. It was due to the fact that smbd is not allowed to acquire CAP_DAC_OVERRIDE capability with following denial entries in logs:

type=AVC msg=audit(1700643404.314:3644): avc: denied { dac_override } for pid=83444 comm="smbd[192.168.12" capability=1 scontext=system_u:system_r:smbd_t:s0 tcontext=system_u:system_r:smbd_t:s0 tclass=capability permissive=0
type=SYSCALL msg=audit(1700643404.314:3644): arch=c000003e syscall=191 success=no exit=-61 a0=7ffea4096890 a1=7f5809ce635a a2=561c6dfe9d90 a3=1000 items=1 ppid=76437 pid=83444 auid=4294967295 uid=2001 gid=0 euid=2001 suid=0 fsuid=2001 egid=2001 sgid=0 fsgid=2001 tty=(none) ses=4294967295 comm="smbd[192.168.12" exe="/usr/sbin/smbd" subj=system_u:system_r:smbd_t:s0 key=(null)ARCH=x86_64 SYSCALL=getxattr AUID="unset" UID="test1" GID="root" EUID="test1" SUID="root" FSUID="test1" EGID="test1" SGID="root" FSGID="test1"
type=CWD msg=audit(1700643404.314:3644): cwd="/samba"
type=PATH msg=audit(1700643404.314:3644): item=0 name="/proc/self/fd/32" inode=144 dev=fc:10 mode=0100775 ouid=2001 ogid=2001 rdev=00:00 obj=system_u:object_r:mnt_t:s0 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0OUID="test1" OGID="test1"

Above entries clearly indicate that the current security policy doesn’t allow smbd to perform with CAP_DAC_OVERRIDE capability. Reading over though various hyperlinks you might already know why SELinux prefers to not allow CAP_DAC_OVERRIDE for the process domain. In most cases the DAC override requirement can be a programmer error but here smbd is not trying to bypass wrongly setup filesystem permissions rather queries the real permissions for the authenticated user.

The way forward

Considering the situation we are in following solutions can be thought of:

  1. Changing the extended attribute namespace from security
    In Samba with this special configuration we do have an additional parameter which can be used to define the extended attribute name in which ACLs are stored. Suppose we configure it to “user.NTACL“, the immediate problem is solved as it can be accessed by unprivileged user provided read access is present on the file. In a setup where client access can only happen via SMB we should be least bothered about the exposure of “user.NTACL” since any other access to it is specially(and correctly) treated by Samba.
  2. Make CAP_DAC_OVERRIDE configurable
    With SELinux supported platforms in place we could even optionally build Samba to prefer the old approach of becoming root to avoid failures. A merge request along those lines is already proposed and being discussed.
  3. Add dac_override allow rule for smbd
    Another possibility is to include an allow rule in the following format to allow smbd to acquire CAP_DAC_OVERRIDE and proceed:
   allow smbd_t self:capability dac_override

Leave a comment