Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include Macports applications in the syscollector (inventory) and vulnerability detector #15726

Closed
fgont opened this issue Dec 20, 2022 · 2 comments

Comments

@fgont
Copy link

fgont commented Dec 20, 2022

Wazuh version Component Install type Install method Platform
4.3.10-1 syscollector Manager/agent Packages Mac OS

I'd like that syscollector be able to learn Macports-pased packages (https://www.macports.org/), and that the package list/versions be employed by the vulnerability detector.

I blieve the issue is similar to the current issues with "brew"?

@MiguelazoDS
Copy link
Member

MiguelazoDS commented Dec 21, 2022

Overview MacPorts package manager

Environment

Macos Catalina 10.15.7

MacPorts package data

Database structure

The installed packages (ports in MacPorts slang) are stored in an SQLite database in the following path

2022-12-21_16-57

As a quick test, the following packages were installed

  • Neovim
  • Ranger
  • Htop

The database tables are:

image

Where the most important is the ports table.

The information for those 3 packages is shown below:

Click to expand

image

Syscollector package fields.

Click to expand

name
version
vendor
install_time
location
architecture
groups
description
size
priority
multiarch
source
format
checksum
item_id
db_status_field_dm

Translation

Click to expand
Syscollector package field ports table attribute
name name
version version
vendor *
install_time date
location location
architecture archs
groups *
description *
size *
priority *
multiarch *
source *
format *
checksum -
item_id -
db_status_field_dm -

Note: The fields represented by "-" are for internal use.
Note: format field can be hardcoded as "macports" or similar
Note: There's no vendor information, so consider the approach followed here #15199. It is necessary a deeper look at this to evaluate how modules that consume this information could be affected.
As specified here: https://guide.macports.org/#development.examples there's no vendor information in the Portfile of every port.
Note: Size may be obtained using the API registry::fileinfo_for_file {fname}
Note: Something interesting to consider is that port is capable to manage multiple versions of the same package

MacPorts has a unique ability to allow multiple versions, revisions, and variants of the same port to be installed at the same time, so you may test new port versions without uninstalling a previous working version.

https://guide.macports.org/#internals.images

Table schemas

ports table

Click to expand
0|id|INTEGER|0||1
1|name|TEXT|0||0
2|portfile|TEXT|0||0
3|location|TEXT|0||0
4|epoch|INTEGER|0||0
5|version|TEXT|0||0
6|revision|INTEGER|0||0
7|variants|TEXT|0||0
8|requested_variants|TEXT|0||0
9|state|TEXT|0||0
10|date|DATETIME|0||0
11|installtype|TEXT|0||0
12|archs|TEXT|0||0
13|requested|INTEGER|0||0
14|os_platform|TEXT|0||0
15|os_major|INTEGER|0||0
16|cxx_stdlib|TEXT|0||0
17|cxx_stdlib_overridden|INTEGER|0||0

sys_programs table

Click to expand
0|scan_id|INTEGER|0||1
1|scan_time|TEXT|0||0
2|format|TEXT|1||0
3|name|TEXT|0||2
4|priority|TEXT|0||0
5|section|TEXT|0||0
6|size|INTEGER|0||0
7|vendor|TEXT|0||0
8|install_time|TEXT|0||0
9|version|TEXT|0||3
10|architecture|TEXT|0||4
11|multiarch|TEXT|0||0
12|source|TEXT|0||0
13|description|TEXT|0||0
14|location|TEXT|0||0
15|triaged|INTEGER(1)|0||0
16|cpe|TEXT|0||0
17|msu_name|TEXT|0||0
18|checksum|TEXT|1||0
19|item_id|TEXT|0||0

Attributes data types

ports sys_programs
name/name TEXT TEXT
version/version TEXT TEXT
date/install_time DATETIME TEXT
location/location TEXT TEXT
archs/architecture TEXT TEXT

Note: It must be checked that archs can have multiple values and whether or not that affects the implementation.
Note: DATETIME is a numeric data type (https://www.sqlite.org/datatype3.html).

API

The direct manipulation of the database may compromise its integrity, the MacPorts project exposes an API that performs the locks and unlocks of the database.

The API is implemented with the TCL script language being the important one for this task, the MacPorts API (https://guide.macports.org/#internals.apis.macports).

The implementation is under base/src/macports1.0 but it is not easily available for external client developments.

The approach is to use the TCL library and the MacPorts TCL module. This small script works to obtain the available package information in the registry database.

Simple TCL script

Click to expand
#!/opt/local/libexec/macports/bin/tclsh8.6

package require macports

if {[catch {mportinit} result]} {
    puts $::errorInfo
    fatal "Failed to initialize MacPorts, $result"
}

set ivariable [registry::installed]
foreach i $ivariable {
    set iname [lindex $i 0]
    set iversion [lindex $i 1]
    set irevision [lindex $i 2]
    set ivariants [lindex $i 3]
    set ref [registry::open_entry $iname $iversion $irevision $ivariants]
    set location [registry::property_retrieve $ref location]
    set archs [registry::property_retrieve $ref archs]
    set date [registry::property_retrieve $ref date]
    puts "Package name: $iname"
    puts "Version: $iversion" 
    puts "Location: $location" 
    puts "Arch: $archs" 
    puts "Date: $date"
    puts ""
}

Information about TCL API for C can be found here: https://www.tcl.tk/man/tcl8.6/TclLib/contents.html

Conclusion

An internal library is used while executing the command port installed that provides a function to get the active ports.

image
Note: For this example, sources were compiled on Linux

But it was found that during the execution of that command, no locker was acquired like the one mentioned here.

Furthermore, access to the registry may be locked using .registry.lock with the registry::exclusive_lock and registry::exclusive_unlock APIs.

The Lock was only acquired during the use of port install <port_name>, which indicates that the database is not locked on read, only on write.

This leads us to notice that the database is in WAL mode, which allows more concurrency since writers do not block readers and vice-versa.

image

https://www.sqlite.org/wal.html

This lets us implement a feature that directly queries the database without compromising the integrity of the database or the data received.

POC

The following code was used to test whether the approach is valid or not.

Expand code
#include<iostream>
#include<sqlite3.h>

const std::string dbName {"/opt/local/var/macports/registry/registry.db"};
const std::string TABLE {"PORTS"};
const std::string QUERY {"SELECT name, version, date, location, archs FROM " + TABLE};

int main(int argc, char **argv){
    sqlite3 *db = nullptr;
    sqlite3_stmt *stmt = nullptr;

    sqlite3_open_v2(dbName.c_str(), &db, SQLITE_OPEN_READONLY, nullptr);
    sqlite3_prepare_v2(db, QUERY.c_str(), -1, &stmt, NULL);

    while(sqlite3_step(stmt) == SQLITE_ROW) {
        std::cout << sqlite3_column_text(stmt, 0) << std::endl;
        std::cout << sqlite3_column_text(stmt, 1) << std::endl;
        std::cout << sqlite3_column_text(stmt, 2) << std::endl;
        std::cout << sqlite3_column_text(stmt, 3) << std::endl;
        std::cout << sqlite3_column_text(stmt, 4) << std::endl;
    }

    sqlite3_finalize(stmt);
    sqlite3_close(db);

    return 0;
}
demo.mp4

As the SQLite documentation reports, it is possible to get SQLITE_BUSY state while reading a database if an exclusive lock was acquired over the database. Although it was not needed in this POC a retry logic should be implemented to be prepared for that situation.

image

More information here: https://guide.macports.org/

@Dwordcito
Copy link
Member

The implementation will be covered by:

#15877

@Dwordcito Dwordcito closed this as not planned Won't fix, can't repro, duplicate, stale May 31, 2023
@Dwordcito Dwordcito added type/research and removed type/enhancement New feature or request platform/macos module/data provider Data Provider library labels May 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants