Skip to content

Commit 7b18cbc

Browse files
committed
Improve macOS and FreeBSD portability in build and probes
Guard Linux-specific compiler/linker assumptions in CMake and add platform-compatible fallbacks in Unix probes and common utilities. Add Darwin handling for sysctl collection, memory usage, and MAC address resolution. Add unsupported-path behavior for runlevel on platforms where runlevels are not applicable. Handle missing fgetpwent environments in password/shadow probe paths so builds complete and offline evaluation remains functional.
1 parent 88a6a29 commit 7b18cbc

8 files changed

Lines changed: 188 additions & 5 deletions

File tree

CMakeLists.txt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ check_function_exists(memalign HAVE_MEMALIGN)
205205
check_function_exists(fts_open HAVE_FTS_OPEN)
206206
check_function_exists(strsep HAVE_STRSEP)
207207
check_function_exists(strptime HAVE_STRPTIME)
208+
check_function_exists(fgetpwent HAVE_FGETPWENT)
208209

209210
check_include_file(syslog.h HAVE_SYSLOG_H)
210211
check_include_file(stdio_ext.h HAVE_STDIO_EXT_H)
@@ -529,8 +530,16 @@ if (MSVC)
529530
endif()
530531

531532
if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
532-
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -W -Wall -Wnonnull -Wshadow -Wformat -Wundef -Wno-unused-parameter -Wmissing-prototypes -Wno-unknown-pragmas -Wno-int-conversion -Werror=implicit-function-declaration -D_GNU_SOURCE -DRBT_IMPLICIT_LOCKING=1 -std=c99")
533-
add_link_options(-Wl,-z,now)
533+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -W -Wall -Wnonnull -Wshadow -Wformat -Wundef -Wno-unused-parameter -Wmissing-prototypes -Wno-unknown-pragmas -Wno-int-conversion -Werror=implicit-function-declaration -DRBT_IMPLICIT_LOCKING=1 -std=c99")
534+
# -D_GNU_SOURCE exposes GNU extensions but changes function signatures on non-glibc
535+
# platforms (e.g. strerror_r on macOS becomes XSI). Only set it on glibc systems.
536+
if(NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
537+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE")
538+
endif()
539+
# -Wl,-z,now is a Linux/ELF linker flag; not supported on macOS (uses -bind_at_load)
540+
if(NOT APPLE)
541+
add_link_options(-Wl,-z,now)
542+
endif()
534543
endif()
535544
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
536545
add_link_options(-lkvm -lm -lprocstat)

config.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
#cmakedefine HAVE_STRSEP
8686
#cmakedefine HAVE_FLOCK
8787
#cmakedefine HAVE_STRPTIME
88+
#cmakedefine HAVE_FGETPWENT
8889

8990
#cmakedefine OPENSCAP_PROBE_INDEPENDENT_ENVIRONMENTVARIABLE
9091
#cmakedefine OPENSCAP_PROBE_INDEPENDENT_ENVIRONMENTVARIABLE58

src/OVAL/probes/unix/password_probe.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,51 @@
6767
#include <probe/option.h>
6868
#include "password_probe.h"
6969

70+
/*
71+
* fgetpwent() is a GNU/glibc extension; provide a portable fallback.
72+
* This parses a standard /etc/passwd-format file one entry at a time.
73+
*/
74+
#ifndef HAVE_FGETPWENT
75+
static struct passwd *oscap_fgetpwent(FILE *fp)
76+
{
77+
static char line[2048];
78+
static struct passwd pw;
79+
char *fields[7], *p;
80+
int f;
81+
82+
while (fgets(line, sizeof(line), fp) != NULL) {
83+
if (line[0] == '#' || line[0] == '\n')
84+
continue;
85+
f = 0;
86+
p = line;
87+
while (f < 7) {
88+
fields[f++] = p;
89+
p = strchr(p, ':');
90+
if (p)
91+
*p++ = '\0';
92+
else
93+
break;
94+
}
95+
if (f < 7)
96+
continue;
97+
/* strip trailing newline from shell field */
98+
size_t n = strlen(fields[6]);
99+
if (n > 0 && fields[6][n - 1] == '\n')
100+
fields[6][n - 1] = '\0';
101+
pw.pw_name = fields[0];
102+
pw.pw_passwd = fields[1];
103+
pw.pw_uid = (uid_t)atoi(fields[2]);
104+
pw.pw_gid = (gid_t)atoi(fields[3]);
105+
pw.pw_gecos = fields[4];
106+
pw.pw_dir = fields[5];
107+
pw.pw_shell = fields[6];
108+
return &pw;
109+
}
110+
return NULL;
111+
}
112+
#define fgetpwent oscap_fgetpwent
113+
#endif
114+
70115
/* Convenience structure for the results being reported */
71116
struct result_info {
72117
const char *username;

src/OVAL/probes/unix/runlevel_probe.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,10 @@ static int get_runlevel (struct runlevel_req *req, struct runlevel_rep **rep)
468468
_A(rep != NULL);
469469
return GET_RUNLEVEL(LINUX_DISTRO, req, rep);
470470
}
471-
#elif defined(OS_FREEBSD)
471+
#elif defined(OS_FREEBSD) || defined(OS_APPLE)
472472
static int get_runlevel (struct runlevel_req *req, struct runlevel_rep **rep)
473473
{
474+
/* SysV runlevels are a Linux/Solaris concept; not applicable on BSD/macOS */
474475
_A(req != NULL);
475476
_A(rep != NULL);
476477
return (-1);

src/OVAL/probes/unix/shadow_probe.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@
6262
#include "shadow_probe.h"
6363

6464
#ifndef HAVE_SHADOW_H
65+
int shadow_probe_offline_mode_supported()
66+
{
67+
return PROBE_OFFLINE_NONE;
68+
}
69+
6570
int shadow_probe_main(probe_ctx *ctx, void *arg)
6671
{
6772
SEXP_t *item_sexp;

src/OVAL/probes/unix/sysctl_probe.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
#include "common/debug_priv.h"
4545

4646
#define SYSCTL_CMD "/sbin/sysctl -ae"
47+
#elif defined(OS_APPLE)
48+
#include <stdio.h>
49+
#include <stdlib.h>
50+
#include <limits.h>
51+
#include <string.h>
52+
53+
#include "common/debug_priv.h"
54+
55+
/* On macOS sysctl(8) lives under /usr/sbin */
56+
#define SYSCTL_CMD "/usr/sbin/sysctl -ae"
4757
#endif
4858

4959
#if defined(OS_LINUX)
@@ -305,7 +315,7 @@ int sysctl_probe_main(probe_ctx *ctx, void *probe_arg)
305315
return (0);
306316
}
307317

308-
#elif defined(OS_FREEBSD)
318+
#elif defined(OS_FREEBSD) || defined(OS_APPLE)
309319

310320
int sysctl_probe_offline_mode_supported(void)
311321
{

src/XCCDF/result.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@
7070
#include <sys/sockio.h>
7171
#endif
7272

73+
#if defined(OS_APPLE)
74+
#include <arpa/inet.h>
75+
#include <ifaddrs.h>
76+
#include <net/if.h>
77+
#include <net/if_dl.h>
78+
#include <netdb.h>
79+
#include <netinet/in.h>
80+
#include <sys/socket.h>
81+
#endif
82+
7383
#include "item.h"
7484
#include "helpers.h"
7585
#include "xccdf_impl.h"
@@ -468,6 +478,58 @@ void xccdf_result_fill_sysinfo(struct xccdf_result *result)
468478
out1:
469479
freeifaddrs(ifaddr);
470480
}
481+
#elif defined(OS_APPLE)
482+
if (!probe_root) {
483+
struct ifaddrs *ifaddr, *ifa;
484+
if (getifaddrs(&ifaddr) == -1)
485+
return;
486+
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
487+
int family;
488+
char hostip[NI_MAXHOST];
489+
490+
if (!ifa->ifa_addr)
491+
continue;
492+
family = ifa->ifa_addr->sa_family;
493+
494+
if (family == AF_INET || family == AF_INET6) {
495+
if (family == AF_INET) {
496+
if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in),
497+
hostip, sizeof(hostip), NULL, 0, NI_NUMERICHOST))
498+
continue;
499+
} else {
500+
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
501+
if (!inet_ntop(family, &sin6->sin6_addr, hostip, sizeof(hostip)))
502+
continue;
503+
}
504+
xccdf_result_add_target_address(result, hostip);
505+
fact = xccdf_target_fact_new();
506+
xccdf_target_fact_set_name(fact, family == AF_INET ?
507+
"urn:xccdf:fact:asset:identifier:ipv4" :
508+
"urn:xccdf:fact:asset:identifier:ipv6");
509+
xccdf_target_fact_set_string(fact, hostip);
510+
_xccdf_result_add_target_fact_uniq(result, fact);
511+
} else if (family == AF_LINK) {
512+
/* macOS exposes MAC addresses as AF_LINK entries in getifaddrs */
513+
struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
514+
if (sdl->sdl_alen == 6) {
515+
unsigned char *mac = (unsigned char *)LLADDR(sdl);
516+
char macbuf[20];
517+
snprintf(macbuf, sizeof(macbuf),
518+
"%02X:%02X:%02X:%02X:%02X:%02X",
519+
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
520+
fact = xccdf_target_fact_new();
521+
xccdf_target_fact_set_name(fact, "urn:xccdf:fact:ethernet:MAC");
522+
xccdf_target_fact_set_string(fact, macbuf);
523+
_xccdf_result_add_target_fact_uniq(result, fact);
524+
fact = xccdf_target_fact_new();
525+
xccdf_target_fact_set_name(fact, "urn:xccdf:fact:asset:identifier:mac");
526+
xccdf_target_fact_set_string(fact, macbuf);
527+
_xccdf_result_add_target_fact_uniq(result, fact);
528+
}
529+
}
530+
}
531+
freeifaddrs(ifaddr);
532+
}
471533
#elif defined(OS_WINDOWS)
472534

473535
#define VERSION_LEN 32

src/common/memusage.c

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@
5050
#define GET_VM_ACT_PAGE_COUNT "vm.stats.vm.v_active_count"
5151

5252
#define BYTES_TO_KIB(x) (x >> 10)
53-
#endif
53+
#endif /* OS_FREEBSD */
54+
55+
#if defined(OS_APPLE)
56+
#include <mach/mach.h>
57+
#include <sys/sysctl.h>
58+
#define BYTES_TO_KIB(x) ((x) >> 10)
59+
#endif /* OS_APPLE */
5460

5561
#include "debug_priv.h"
5662
#include "memusage.h"
@@ -305,6 +311,32 @@ int oscap_sys_memusage(struct sys_memusage *mu)
305311
#elif defined(OS_FREEBSD)
306312
if (freebsd_sys_memusage(mu))
307313
return -1;
314+
#elif defined(OS_APPLE)
315+
{
316+
vm_statistics64_data_t vm_stat;
317+
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
318+
vm_size_t page_size;
319+
host_page_size(mach_host_self(), &page_size);
320+
if (host_statistics64(mach_host_self(), HOST_VM_INFO64,
321+
(host_info64_t)&vm_stat, &count) != KERN_SUCCESS) {
322+
errno = EOPNOTSUPP;
323+
return -1;
324+
}
325+
mu->mu_free = BYTES_TO_KIB((uint64_t)vm_stat.free_count * page_size);
326+
mu->mu_active = BYTES_TO_KIB((uint64_t)vm_stat.active_count * page_size);
327+
mu->mu_inactive = BYTES_TO_KIB((uint64_t)vm_stat.inactive_count * page_size);
328+
mu->mu_buffers = 0;
329+
mu->mu_cached = 0;
330+
mu->mu_realfree = mu->mu_free + mu->mu_inactive;
331+
/* Query total physical RAM via sysctl HW_MEMSIZE */
332+
int mib[2] = { CTL_HW, HW_MEMSIZE };
333+
uint64_t memsize = 0;
334+
size_t len = sizeof(memsize);
335+
if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0)
336+
mu->mu_total = BYTES_TO_KIB(memsize);
337+
else
338+
mu->mu_total = 0;
339+
}
308340
#else
309341
errno = EOPNOTSUPP;
310342
return -1;
@@ -326,6 +358,24 @@ int oscap_proc_memusage(struct proc_memusage *mu)
326358
#elif defined(OS_FREEBSD)
327359
if (freebsd_proc_memusage(mu))
328360
return -1;
361+
#elif defined(OS_APPLE)
362+
{
363+
struct task_basic_info info;
364+
mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
365+
if (task_info(mach_task_self(), TASK_BASIC_INFO,
366+
(task_info_t)&info, &count) != KERN_SUCCESS) {
367+
errno = EOPNOTSUPP;
368+
return -1;
369+
}
370+
mu->mu_rss = info.resident_size / 1024;
371+
mu->mu_data = info.virtual_size / 1024;
372+
/* TASK_BASIC_INFO doesn't expose peak RSS; use current as approximation */
373+
mu->mu_hwm = mu->mu_rss;
374+
mu->mu_text = 0;
375+
mu->mu_stack = 0;
376+
mu->mu_lib = 0;
377+
mu->mu_lock = 0;
378+
}
329379
#else
330380
errno = EOPNOTSUPP;
331381
return -1;

0 commit comments

Comments
 (0)