Skip to content

Commit

Permalink
[Auditbeat] Package dataset: Make librpm code compatible across CentO…
Browse files Browse the repository at this point in the history
…S 6.x, 7.x, and Fedora 29 (elastic#10796)

Librpm version 4.14.2.1 on Fedora 29 no longer contains the `headerGetEntry` method we are currently using. It was deprecated and then removed in version 4.14 (rpm-software-management/rpm@c68fa9a).

Also, the much older version 4.8.0 of librpm on CentOS 6.10 (Final) does not yet contain newer data structures for tags like `rpm_tag_t/rpmTag/rpmTagVal`.

This PR makes two changes that should allow this code to work on all three distros (CentOS 6.x, 7.x, Fedora 29 - and hopefully anything in between):

1. Use `headerGetString/headerGetNumber` instead of `headerGetEntry`.
2. Use `int32_t` instead of `rpm_tag_t/rpmTag/rpmTagVal`. Luckily, this seems to work on all three distros. I'd prefer something like a typedef, but unfortunately, C99 does not allow repeating a typedef (C11 does) and so backporting them is not easily possible.

It also makes the code more lenient with errors during data collection: Only when no package name can be found do we return an error.

Together with elastic#10694 this will hopefully allow RPM package collection to work well.
  • Loading branch information
Christoph Wurm committed Feb 20, 2019
1 parent 3950fc6 commit e7ea5d7
Showing 1 changed file with 44 additions and 66 deletions.
110 changes: 44 additions & 66 deletions x-pack/auditbeat/module/system/package/rpm_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package pkg

import (
"errors"
"fmt"
"runtime"
"time"
Expand Down Expand Up @@ -65,28 +66,32 @@ my_headerLink(void *f, Header h) {
return headerLink(h);
}
int
my_headerGetEntry(void *f, Header h, rpm_tag_t tag, char **p) {
int (*headerGetEntry)(Header, rpm_tag_t, rpm_tagtype_t*, rpm_data_t*, rpm_count_t*);
headerGetEntry = (int (*)(Header, rpm_tag_t, rpm_tagtype_t*, rpm_data_t*, rpm_count_t*))f;
// Note: Using int32_t instead of rpmTag/rpmTagVal in definitions
// to make it work on CentOS 6.x, 7.x, and Fedora 29.
const char *
my_headerGetString(void *f, Header h, int32_t tag) {
const char * (*headerGetString)(Header, int32_t);
headerGetString = (const char * (*)(Header, int32_t))f;
return headerGetEntry(h, tag, NULL, (void**)p, NULL);
return headerGetString(h, tag);
}
int
my_headerGetEntryInt(void *f, Header h, rpm_tag_t tag, int **p) {
int (*headerGetEntry)(Header, rpm_tag_t, rpm_tagtype_t*, rpm_data_t*, rpm_count_t*);
headerGetEntry = (int (*)(Header, rpm_tag_t, rpm_tagtype_t*, rpm_data_t*, rpm_count_t*))f;
// Note: Using int32_t instead of rpmTag/rpmTagVal in definitions
// to make it work on CentOS 6.x, 7.x, and Fedora 29.
uint64_t
my_headerGetNumber(void *f, Header h, int32_t tag) {
uint64_t (*headerGetNumber)(Header, int32_t);
headerGetNumber = (uint64_t (*)(Header, int32_t))f;
return headerGetEntry(h, tag, NULL, (void**)p, NULL);
return headerGetNumber(h, tag);
}
void
my_headerFree(void *f, Header h) {
Header (*headerFree)(Header);
Header (*headerFree)(Header);
headerFree = (Header (*)(Header))f;
headerFree(h);
headerFree(h);
}
void
Expand Down Expand Up @@ -160,7 +165,8 @@ type cFunctions struct {
rpmtsInitIterator unsafe.Pointer
rpmdbNextIterator unsafe.Pointer
headerLink unsafe.Pointer
headerGetEntry unsafe.Pointer
headerGetString unsafe.Pointer
headerGetNumber unsafe.Pointer
headerFree unsafe.Pointer
rpmdbFreeIterator unsafe.Pointer
rpmtsFree unsafe.Pointer
Expand Down Expand Up @@ -206,7 +212,12 @@ func dlopenCFunctions() (*cFunctions, error) {
return nil, err
}

cFun.headerGetEntry, err = librpm.GetSymbolPointer("headerGetEntry")
cFun.headerGetString, err = librpm.GetSymbolPointer("headerGetString")
if err != nil {
return nil, err
}

cFun.headerGetNumber, err = librpm.GetSymbolPointer("headerGetNumber")
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -306,65 +317,32 @@ func packageFromHeader(header C.Header, cFun *cFunctions) (*Package, error) {

pkg := Package{}

var name *C.char
res := C.my_headerGetEntry(cFun.headerGetEntry, header, RPMTAG_NAME, &name)
if res != 1 {
return nil, fmt.Errorf("Failed to call headerGetEntry(name): %d", res)
}
pkg.Name = C.GoString(name)

var version *C.char
res = C.my_headerGetEntry(cFun.headerGetEntry, header, RPMTAG_VERSION, &version)
if res != 1 {
return nil, fmt.Errorf("Failed to call headerGetEntry(version): %d", res)
name := C.my_headerGetString(cFun.headerGetString, header, RPMTAG_NAME)
if name != nil {
pkg.Name = C.GoString(name)
} else {
return nil, errors.New("Failed to get package name")
}
pkg.Version = C.GoString(version)

var release *C.char
res = C.my_headerGetEntry(cFun.headerGetEntry, header, RPMTAG_RELEASE, &release)
if res != 1 {
return nil, fmt.Errorf("Failed to call headerGetEntry(release): %d", res)
version := C.my_headerGetString(cFun.headerGetString, header, RPMTAG_VERSION)
if version != nil {
pkg.Version = C.GoString(version)
} else {
pkg.Error = errors.New("Failed to get package version")
}
pkg.Release = C.GoString(release)

var license *C.char
res = C.my_headerGetEntry(cFun.headerGetEntry, header, RPMTAG_LICENSE, &license)
if res != 1 {
return nil, fmt.Errorf("Failed to call headerGetEntry(license): %d", res)
}
pkg.License = C.GoString(license)

var arch *C.char
res = C.my_headerGetEntry(cFun.headerGetEntry, header, RPMTAG_ARCH, &arch)
if res == 1 { // not always successful
pkg.Arch = C.GoString(arch)
}

var url *C.char
res = C.my_headerGetEntry(cFun.headerGetEntry, header, RPMTAG_URL, &url)
if res == 1 { // not always successful
pkg.URL = C.GoString(url)
}

var summary *C.char
res = C.my_headerGetEntry(cFun.headerGetEntry, header, RPMTAG_SUMMARY, &summary)
if res == 1 { // not always successful
pkg.Summary = C.GoString(summary)
}
pkg.Release = C.GoString(C.my_headerGetString(cFun.headerGetString, header, RPMTAG_RELEASE))
pkg.License = C.GoString(C.my_headerGetString(cFun.headerGetString, header, RPMTAG_LICENSE))
pkg.Arch = C.GoString(C.my_headerGetString(cFun.headerGetString, header, RPMTAG_ARCH))
pkg.URL = C.GoString(C.my_headerGetString(cFun.headerGetString, header, RPMTAG_URL))
pkg.Summary = C.GoString(C.my_headerGetString(cFun.headerGetString, header, RPMTAG_SUMMARY))

var size *C.int
res = C.my_headerGetEntryInt(cFun.headerGetEntry, header, RPMTAG_SIZE, &size)
if res != 1 {
return nil, fmt.Errorf("Failed to call headerGetEntry(size): %d", res)
}
pkg.Size = uint64(*size)
pkg.Size = uint64(C.my_headerGetNumber(cFun.headerGetNumber, header, RPMTAG_SIZE))

var installTime *C.int
res = C.my_headerGetEntryInt(cFun.headerGetEntry, header, RPMTAG_INSTALLTIME, &installTime)
if res != 1 {
return nil, fmt.Errorf("Failed to call headerGetEntry(installTime): %d", res)
installTime := C.my_headerGetNumber(cFun.headerGetNumber, header, RPMTAG_INSTALLTIME)
if installTime != 0 {
pkg.InstallTime = time.Unix(int64(installTime), 0)
}
pkg.InstallTime = time.Unix(int64(*installTime), 0)

return &pkg, nil
}

0 comments on commit e7ea5d7

Please sign in to comment.