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

libselinux: add build time option to drop hard dependency on libpcre2 #431

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,40 @@ jobs:
matrix:
compiler: [gcc, clang]
python-ruby-version:
- {python: '3.11', ruby: '3.1'}
- {python: '3.11', ruby: '3.1', other: 'test-flags-override'}
- {python: '3.11', ruby: '3.1', other: 'test-debug'}
- {python: '3.11', ruby: '3.1', other: 'linker-bfd'}
- {python: '3.11', ruby: '3.1', other: 'linker-gold'}
# Test several Python versions with the latest Ruby version
- {python: '3.10', ruby: '3.1'}
- {python: '3.9', ruby: '3.1'}
- {python: '3.8', ruby: '3.1'}
- {python: '3.7', ruby: '3.1'}
- {python: 'pypy3.7', ruby: '3.1'}
- {python: '3.12', ruby: '3.3'}
- {python: '3.12', ruby: '3.3', other: 'test-flags-override'}
- {python: '3.12', ruby: '3.3', other: 'test-debug'}
- {python: '3.12', ruby: '3.3', other: 'linker-bfd'}
- {python: '3.12', ruby: '3.3', other: 'linker-gold'}
- {python: '3.12', ruby: '3.3', other: 'pcre2-dlsym'}
# Test several Python versions with the latest Ruby version
- {python: '3.11', ruby: '3.3'}
- {python: '3.10', ruby: '3.3'}
- {python: '3.9', ruby: '3.3'}
- {python: '3.8', ruby: '3.3'}
- {python: '3.7', ruby: '3.3'}
- {python: 'pypy3.7', ruby: '3.3'}
# Test several Ruby versions with the latest Python version
- {python: '3.11', ruby: '3.0'}
- {python: '3.11', ruby: '2.7'}
- {python: '3.11', ruby: '2.6'}
- {python: '3.11', ruby: '2.5'}
- {python: '3.12', ruby: '3.2'}
- {python: '3.12', ruby: '3.1'}
- {python: '3.12', ruby: '3.0'}
- {python: '3.12', ruby: '2.7'}
- {python: '3.12', ruby: '2.6'}
- {python: '3.12', ruby: '2.5'}
exclude:
- compiler: clang
python-ruby-version: {python: '3.11', ruby: '3.1', other: 'linker-bfd'}
python-ruby-version: {python: '3.12', ruby: '3.3', other: 'linker-bfd'}
- compiler: clang
python-ruby-version: {python: '3.11', ruby: '3.1', other: 'linker-gold'}
python-ruby-version: {python: '3.12', ruby: '3.3', other: 'linker-gold'}
include:
- compiler: gcc
python-ruby-version: {python: '3.11', ruby: '3.1', other: 'sanitizers'}
python-ruby-version: {python: '3.12', ruby: '3.3', other: 'sanitizers'}

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-ruby-version.python }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-ruby-version.python }}

Expand Down Expand Up @@ -67,7 +71,7 @@ jobs:
swig \
xmlto

pip install flake8
pip install flake8 setuptools

- name: Install Clang
if: ${{ matrix.compiler == 'clang' }}
Expand All @@ -85,6 +89,8 @@ jobs:
CC="$CC -fuse-ld=bfd"
elif [ "${{ matrix.python-ruby-version.other }}" = "linker-gold" ] ; then
CC="$CC -fuse-ld=gold"
elif [ "${{ matrix.python-ruby-version.other }}" = "pcre2-dlsym" ] ; then
echo "USE_PCRE2_DLSYM=y" >> $GITHUB_ENV
fi
# https://bugs.ruby-lang.org/issues/18616
# https://github.com/llvm/llvm-project/issues/49958
Expand Down
10 changes: 8 additions & 2 deletions libselinux/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ endif
export DISABLE_SETRANS DISABLE_RPM DISABLE_FLAGS ANDROID_HOST DISABLE_X11 LABEL_BACKEND_ANDROID

USE_PCRE2 ?= y
USE_PCRE2_DLSYM ?= n
ifeq ($(USE_PCRE2),y)
PCRE_MODULE := libpcre2-8
PCRE_CFLAGS := -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8
ifeq ($(USE_PCRE2_DLSYM),n)
PCRE_CFLAGS := -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8
PCRE_MODULE := libpcre2-8
else
PCRE_CFLAGS := -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8 -DUSE_PCRE2_DLSYM
PCRE_MODULE :=
endif
else
PCRE_MODULE := libpcre
endif
Expand Down
56 changes: 47 additions & 9 deletions libselinux/src/regex.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string.h>

#include "regex.h"
#include "regex_dlsym.h"
#include "label_file.h"
#include "selinux_internal.h"

Expand All @@ -29,6 +30,12 @@

#endif

/**
* This constructor function allocates a buffer for a regex_data structure.
* The buffer is being initialized with zeroes.
*/
static struct regex_data *regex_data_create(void);

#ifdef USE_PCRE2
char const *regex_arch_string(void)
{
Expand Down Expand Up @@ -75,6 +82,9 @@ int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
{
memset(errordata, 0, sizeof(struct regex_error_data));

if (regex_pcre2_load() < 0)
return -1;

*regex = regex_data_create();
if (!(*regex))
return -1;
Expand Down Expand Up @@ -104,7 +114,12 @@ int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
char const *regex_version(void)
{
static char version_buf[256];
size_t len = pcre2_config(PCRE2_CONFIG_VERSION, NULL);
size_t len;

if (regex_pcre2_load() < 0)
return NULL;

len = pcre2_config(PCRE2_CONFIG_VERSION, NULL);
if (len <= 0 || len > sizeof(version_buf))
return NULL;

Expand All @@ -119,6 +134,10 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
uint32_t entry_len;

*regex_compiled = false;

if (regex_pcre2_load() < 0)
return -1;

rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
if (rc < 0)
return -1;
Expand Down Expand Up @@ -164,14 +183,17 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
return -1;
}

int regex_writef(struct regex_data *regex, FILE *fp, int do_write_precompregex)
int regex_writef(const struct regex_data *regex, FILE *fp, int do_write_precompregex)
{
int rc = 0;
size_t len;
PCRE2_SIZE serialized_size;
uint32_t to_write = 0;
PCRE2_UCHAR *bytes = NULL;

if (regex_pcre2_load() < 0)
return -1;

if (do_write_precompregex) {
/* encode the pattern for serialization */
rc = pcre2_serialize_encode((const pcre2_code **)&regex->regex,
Expand Down Expand Up @@ -206,6 +228,9 @@ int regex_writef(struct regex_data *regex, FILE *fp, int do_write_precompregex)

void regex_data_free(struct regex_data *regex)
{
if (regex_pcre2_load() < 0)
return;

if (regex) {
if (regex->regex)
pcre2_code_free(regex->regex);
Expand All @@ -224,6 +249,10 @@ int regex_match(struct regex_data *regex, char const *subject, int partial)
{
int rc;
pcre2_match_data *match_data;

if (regex_pcre2_load() < 0)
return REGEX_ERROR;

__pthread_mutex_lock(&regex->match_mutex);

#ifdef AGGRESSIVE_FREE_AFTER_REGEX_MATCH
Expand Down Expand Up @@ -269,10 +298,14 @@ int regex_match(struct regex_data *regex, char const *subject, int partial)
* Preferably, this function would be replaced with an algorithm that computes
* the equivalence of the automatons systematically.
*/
int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
int regex_cmp(const struct regex_data *regex1, const struct regex_data *regex2)
{
int rc;
size_t len1, len2;

if (regex_pcre2_load() < 0)
return SELABEL_INCOMPARABLE;

rc = pcre2_pattern_info(regex1->regex, PCRE2_INFO_SIZE, &len1);
assert(rc == 0);
rc = pcre2_pattern_info(regex2->regex, PCRE2_INFO_SIZE, &len2);
Expand All @@ -283,7 +316,7 @@ int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
return SELABEL_EQUAL;
}

struct regex_data *regex_data_create(void)
static struct regex_data *regex_data_create(void)
{
struct regex_data *regex_data =
(struct regex_data *)calloc(1, sizeof(struct regex_data));
Expand Down Expand Up @@ -407,7 +440,7 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
return -1;
}

static inline pcre_extra *get_pcre_extra(struct regex_data *regex)
static inline const pcre_extra *get_pcre_extra(const struct regex_data *regex)
{
if (!regex) return NULL;
if (regex->owned) {
Expand All @@ -419,14 +452,14 @@ static inline pcre_extra *get_pcre_extra(struct regex_data *regex)
}
}

int regex_writef(struct regex_data *regex, FILE *fp,
int regex_writef(const struct regex_data *regex, FILE *fp,
int do_write_precompregex __attribute__((unused)))
{
int rc;
size_t len;
uint32_t to_write;
size_t size;
pcre_extra *sd = get_pcre_extra(regex);
const pcre_extra *sd = get_pcre_extra(regex);

/* determine the size of the pcre data in bytes */
rc = pcre_fullinfo(regex->regex, NULL, PCRE_INFO_SIZE, &size);
Expand Down Expand Up @@ -510,7 +543,7 @@ int regex_match(struct regex_data *regex, char const *subject, int partial)
* Preferably, this function would be replaced with an algorithm that computes
* the equivalence of the automatons systematically.
*/
int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
int regex_cmp(const struct regex_data *regex1, const struct regex_data *regex2)
{
int rc;
size_t len1, len2;
Expand All @@ -524,7 +557,7 @@ int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
return SELABEL_EQUAL;
}

struct regex_data *regex_data_create(void)
static struct regex_data *regex_data_create(void)
{
return (struct regex_data *)calloc(1, sizeof(struct regex_data));
}
Expand All @@ -540,6 +573,11 @@ void regex_format_error(struct regex_error_data const *error_data, char *buffer,
size_t pos = 0;
if (!buffer || !buf_size)
return;
#ifdef USE_PCRE2
rc = regex_pcre2_load();
if (rc < 0)
return;
#endif
rc = snprintf(buffer, buf_size, "REGEX back-end error: ");
if (rc < 0)
/*
Expand Down
9 changes: 2 additions & 7 deletions libselinux/src/regex.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ char const *regex_arch_string(void) ;
* It may return NULL on error.
*/
char const *regex_version(void) ;
/**
* This constructor function allocates a buffer for a regex_data structure.
* The buffer is being initialized with zeroes.
*/
struct regex_data *regex_data_create(void) ;
/**
* This complementary destructor function frees the a given regex_data buffer.
* It also frees any non NULL member pointers with the appropriate pcreX_X_free
Expand Down Expand Up @@ -120,7 +115,7 @@ int regex_load_mmap(struct mmap_area *map_area,
* @arg do_write_precompregex If non-zero precompiled patterns are written to
* the output file (ignored by PCRE1 back-end).
*/
int regex_writef(struct regex_data *regex, FILE *fp,
int regex_writef(const struct regex_data *regex, FILE *fp,
int do_write_precompregex) ;
/**
* This function applies a precompiled pattern to a subject string and
Expand Down Expand Up @@ -149,7 +144,7 @@ int regex_match(struct regex_data *regex, char const *subject,
* the same
* @retval SELABEL_INCOMPARABLE otherwise
*/
int regex_cmp(struct regex_data *regex1, struct regex_data *regex2) ;
int regex_cmp(const struct regex_data *regex1, const struct regex_data *regex2) ;
/**
* This function takes the error data returned by regex_prepare_data and turns
* it in to a human readable error message.
Expand Down
Loading
Loading