Note: This is a public test instance of Red Hat Bugzilla. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback at bugzilla.redhat.com.

Bug 1352066

Summary: New use of capng_have_capability() exposes bug in cap-ng breaking libvirt when starting KVM guests
Product: [Fedora] Fedora Reporter: Daniel BerrangĂ© <berrange>
Component: auditAssignee: Steve Grubb <sgrubb>
Status: CLOSED DUPLICATE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: high Docs Contact:
Priority: unspecified    
Version: rawhideCC: extras-qa, sgrubb
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: 1352064 Environment:
Last Closed: 2016-07-01 14:47:10 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 1352064    
Bug Blocks: 1351995    

Description Daniel Berrangé 2016-07-01 14:24:58 UTC
+++ This bug was initially created as a clone of Bug #1352064 +++

Description of problem:
The latest version of audit-libs has started using capng_have_capability() before sending audit messages.

This has in turn exposed a bug in libcap-ng's use of thread local state.

Specifically, if you call any capng_* function and then call fork(), the 

static __thread struct cap_ng m

will get initialized with the current PID.

If you then fork() and call another capng API, (for example, you're trying to drop caps for a child process you're spawning), this thread local doesn't get reset. 

As a result capng_apply() will try to set capabilities on the parent PID and gets an error

strace clearly shows the problem:

[pid 26690] capset({_LINUX_CAPABILITY_VERSION_3, 26689}, {0, 0, 0}) = -1 EPERM (Operation not permitted)


not it is runing pid 26690 but setting caps on 26689.

AFAICT, this bug has existed forever. The new audit-libs 2.6.1 has just started calling capng_have_capability() which has in turn broken libvirt which uses capng when spawning processes after fork.

The following demo shows the problem

#include <libaudit.h>
#include <cap-ng.h>

#include <stdio.h>
#include <sys/wait.h>


int main(int argc, char **argv)
{
  int fd = audit_open();

  if (fd < 0) {
    perror("audit_open");
    return 1;
  }

  audit_log_user_message(fd, AUDIT_VIRT_CONTROL, "test", NULL,
			 NULL, NULL, 1);

  close(fd);

  pid_t child = fork();

  if (child == 0) {
    capng_clear(CAPNG_SELECT_CAPS);
    if (capng_apply(CAPNG_SELECT_CAPS) < 0) {
      perror("capng_apply");
      _exit(1);
    }
    
    _exit(0);
  }

  int status = 0;
  waitpid(child, &status, 0);

  fprintf(stderr, "Child exited %d\n", status);
  return 0;
}


$ gcc -lcap-ng -laudit -o cap cap.c
[berrange@t530wlan ~]$ ./cap
capng_apply: Operation not permitted
Child exited 256


If you downgrade to audit-libs-2.6 the problem goes away, though clearly the bug in cap-ng still exists.


Version-Release number of selected component (if applicable):
audit-libs-2.6.1-1.fc24.x86_64
audit-libs-2.6.1-1.fc24.i686
libcap-ng-0.7.7-4.fc24.x86_64
libcap-ng-0.7.7-4.fc24.i686

Comment 1 Steve Grubb 2016-07-01 14:47:10 UTC

*** This bug has been marked as a duplicate of bug 1351954 ***