title: File capabilities do not transfer to process once executed
body: <p>I'm trying to write a program which requires elevated capabilities (rather than simply run it with sudo).  However, none of the capabilities I set using setcap seem to transfer into the process once executed.  This problem occurs across multiple executables and using different capabilities.</p>
  
  <p>This code uses cap_set_file() to give the CAP_NET_RAW capability to a file passed as a CLA. (Don't ask me why I need this.) </p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;sys/prctl.h&gt;
  #include &lt;sys/capability.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;string.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;unistd.h&gt;
  
  #define handle_error(msg) \ 
      do { printf("%s: %s\n", msg, strerror(errno)); exit(EXIT_FAILURE); } while (0)
  
  void print_cap_buf(cap_t cur) {
      char *buf;
      buf = cap_to_text(cur, NULL);
      printf("%s\n", buf);
      cap_free(buf);
  }
  
  void get_and_print_cap_buf() {
      cap_t cur = cap_get_proc();
      print_cap_buf(cur);
      cap_free(cur);
  }
  
  int main(int argc, char *argv[]) {
      cap_t file_cap;
  
      printf("Process capabilities: ");
      get_and_print_cap_buf(); // Print the current process capability list.
  
      file_cap = cap_from_text("cap_net_raw=ep");
      if (file_cap == NULL) handle_error("cap_from_text");
  
      printf("Capabilities to set in file: "); print_cap_buf(file_cap);
  
      if (argc == 2) {
          if ( cap_set_file(argv[1], file_cap) != 0) handle_error("cap_set_file");
      } else printf("No file specified.\n");
  
      cap_free(file_cap);
      return 0;
  }
  </code></pre>
  
  <p>After compiling with gcc:    </p>
  
  <pre><code>gcc -Wall -pedantic -std=gnu99 test.c -o tt -lcap
  </code></pre>
  
  <p>I give it the capabilities with:</p>
  
  <pre><code>sudo setcap "cap_setfcap,cap_fowner,cap_net_raw=eip" tt 
  </code></pre>
  
  <p>and using getcap tt, the output is:</p>
  
  <pre><code> $ getcap tt
  tt = cap_fowner,cap_net_raw,cap_setfcap+eip
  </code></pre>
  
  <p>However, when I run the program, I get the following output (test-client is an executable which creates a raw Ethernet socket):</p>
  
  <pre><code> $ ./tt test-client
  Process capabilities: =
  Capabilities to set in file: = cap_net_raw+ep
  cap_set_file: Operation not permitted
  </code></pre>
  
  <p>HOWEVER... when I run the program with sudo, all process capabilities come through just fine.</p>
  
  <pre><code> $ sudo ./tt test-client
  Process capabilities: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37+ep
  Capabilities to set in file: = cap_net_raw+ep
  </code></pre>
  
  <p>and the target file "test-client" gets its capabilities set properly.</p>
  
  <p>However, even with CAP_NET_RAW, the client fails on its socket() call with EPERM. I've tried setting CAP_NET_ADMIN in case it needed that as well; same issue. I've tried using CAP_SETPCAP on the program above; no dice. I'm fairly sure I've narrowed it down to some disconnect where the executable file's capabilities aren't getting into the running process.</p>
  
  <p>What am I missing here?</p>
  
  <hr>
  
  <p>EDIT, the next morning:</p>
  
  <p>Okay, so I've done some more testing and it turns out this code works just fine on a Raspberry Pi. I'm running Lubuntu 16.04 with LXTerminal on my primary machine and that's the one that's failing.  It fails inside LXTerminal and also in a text-only shell. Maybe it's an OS bug?</p>
  
  <p>The Lubuntu machine (cat /proc/version):</p>
  
  <pre><code>Linux version 4.4.0-34-generic (buildd@lgw01-20) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1) ) #53-Ubuntu SMP Wed Jul 27 16:06:39 UTC 2016
  </code></pre>
  
  <p>The pi:</p>
  
  <pre><code>Linux version 4.4.11-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #888 SMP Mon May 23 20:10:33 BST 2016
  </code></pre>
  
  <p>EDIT AGAIN: --</p>
  
  <p>Tested on a different machine with the same USB key I used to install. Slightly different /proc/version:</p>
  
  <pre><code>Linux version 4.4.0-31-generic (buildd@lgw01-16) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1) ) #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016
  </code></pre>
  
  <p>Works fine. I'm so confused.</p>