commit: 766ac14e269fda699f11549bedb14c77c2c8c623
Author: Mike Gilbert <floppym <AT> gentoo <DOT> org>
AuthorDate: Fri Feb 14 21:50:16 2025 +0000
Commit: Mike Gilbert <floppym <AT> gentoo <DOT> org>
CommitDate: Sat Feb 15 01:43:20 2025 +0000
URL: https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=766ac14e
Optimize prefix loading
Reduce the number of malloc/mmap calls needed by storing each set of
prefixes in a single chunk of memory.
Signed-off-by: Mike Gilbert <floppym <AT> gentoo.org>
libsandbox/libsandbox.c | 132 ++++++++++++++----------------------------------
libsandbox/libsandbox.h | 2 +
libsandbox/memory.c | 11 ++++
3 files changed, 52 insertions(+), 93 deletions(-)
diff --git a/libsandbox/libsandbox.c b/libsandbox/libsandbox.c
index f5b3e62..5764cf6 100644
--- a/libsandbox/libsandbox.c
+++ b/libsandbox/libsandbox.c
@@ -31,18 +31,12 @@ typedef struct {
bool show_access_violation, on, active, testing, verbose, debug;
sandbox_method_t method;
char *ld_library_path;
- char **prefixes[5];
- int num_prefixes[5];
+ char *prefixes[5];
#define deny_prefixes prefixes[0]
-#define num_deny_prefixes num_prefixes[0]
#define read_prefixes prefixes[1]
-#define num_read_prefixes num_prefixes[1]
#define write_prefixes prefixes[2]
-#define num_write_prefixes num_prefixes[2]
#define predict_prefixes prefixes[3]
-#define num_predict_prefixes num_prefixes[3]
#define write_denied_prefixes prefixes[4]
-#define num_write_denied_prefixes num_prefixes[4]
#define MAX_DYN_PREFIXES 4 /* the first 4 are dynamic */
} sbcontext_t;
static sbcontext_t sbcontext;
@@ -58,8 +52,6 @@ int (*sbio_faccessat)(int, const char *, int, int) =
sb_unwrapped_faccessat;
int (*sbio_open)(const char *, int, mode_t) = sb_unwrapped_open;
FILE *(*sbio_popen)(const char *, const char *) = sb_unwrapped_popen;
-static int check_prefixes(char **, int, const char *);
-static void clean_env_entries(char ***, int *);
static void sb_process_env_settings(void);
const char *sbio_message_path;
@@ -190,41 +182,27 @@ static bool write_logfile(const char *logfile, const char
*func, const char *pat
return ret;
}
-static void clean_env_entries(char ***prefixes_array, int *prefixes_num)
+static size_t strv_append(char **basep, size_t offset, const char *value)
{
- if (*prefixes_array == NULL)
- return;
+ char *base = *basep;
+ size_t bsize = malloc_size(base);
+ size_t vsize = strlen(value) + 1;
- size_t i;
- save_errno();
+ if (offset + vsize >= bsize)
+ *basep = base = xrealloc(base, offset + vsize + 1);
- for (i = 0; i < *prefixes_num; ++i) {
- if (NULL != (*prefixes_array)[i]) {
- free((*prefixes_array)[i]);
- (*prefixes_array)[i] = NULL;
- }
- }
- if (NULL != *prefixes_array)
- free(*prefixes_array);
- *prefixes_array = NULL;
- *prefixes_num = 0;
+ memcpy(base + offset, value, vsize);
+ offset += vsize;
+ base[offset] = '\0';
- restore_errno();
+ return offset;
}
-#define pfx_num (*prefixes_num)
-#define pfx_array (*prefixes_array)
-#define pfx_item ((*prefixes_array)[(*prefixes_num)])
-#define pfx_prev ((*prefixes_array)[(*prefixes_num) - 1])
-
-static void init_env_entries(char ***prefixes_array, int *prefixes_num, const
char *env, const char *prefixes_env, int warn)
+static void init_env_entries(char **prefixes, const char *env, const char
*prefixes_env)
{
char *token = NULL;
char *buffer = NULL;
char *buffer_ptr = NULL;
- int prefixes_env_length = strlen(prefixes_env);
- int num_delimiters = 0;
- int i = 0;
int old_errno = errno;
if (NULL == prefixes_env) {
@@ -234,23 +212,10 @@ static void init_env_entries(char ***prefixes_array, int
*prefixes_num, const ch
fprintf(stderr,
"libsandbox: The '%s' env variable is not
defined!\n",
env);
- if (pfx_array) {
- for (i = 0; i < pfx_num; i++)
- free(pfx_item);
- free(pfx_array);
- }
- pfx_num = 0;
goto done;
}
- for (i = 0; i < prefixes_env_length; i++) {
- if (':' == prefixes_env[i])
- num_delimiters++;
- }
-
- /* num_delimiters might be 0, and we need 2 entries at least */
- pfx_array = xmalloc(((num_delimiters * 2) + 2) * sizeof(char *));
buffer = xstrdup(prefixes_env);
buffer_ptr = buffer;
@@ -260,19 +225,18 @@ static void init_env_entries(char ***prefixes_array, int
*prefixes_num, const ch
token = strtok(buffer_ptr, ":");
#endif
+ size_t offset = 0;
+
while (token && strlen(token) > 0) {
char buf[SB_PATH_MAX];
if (sb_abspathat(AT_FDCWD, token, buf, sizeof(buf))) {
- pfx_item = xstrdup(buf);
- ++pfx_num;
+ size_t prev_offset = offset;
+ offset = strv_append(prefixes, offset, buf);
/* Now add the realpath if it exists and
* are not a duplicate */
- if (sb_realpathat(AT_FDCWD, token, buf, sizeof(buf), 0,
false)) {
- if (strcmp(buf, pfx_prev)) {
- pfx_item = xstrdup(buf);
- ++pfx_num;
- }
- }
+ if (sb_realpathat(AT_FDCWD, token, buf, sizeof(buf), 0,
false))
+ if (strcmp(buf, *prefixes + prev_offset))
+ offset = strv_append(prefixes, offset,
buf);
}
#ifdef HAVE_STRTOK_R
@@ -311,14 +275,12 @@ static void sb_process_env_settings(void)
!cached_env_vars[i] ||
strcmp(cached_env_vars[i], sb_env) != 0)
{
- clean_env_entries(&sbcontext.prefixes[i],
&sbcontext.num_prefixes[i]);
-
- if (cached_env_vars[i])
- free(cached_env_vars[i]);
+ free(sbcontext.prefixes[i]);
+ sbcontext.prefixes[i] = NULL;
+ free(cached_env_vars[i]);
if (sb_env) {
- init_env_entries(&sbcontext.prefixes[i],
&sbcontext.num_prefixes[i],
- sb_env_names[i], sb_env, 1);
+ init_env_entries(sbcontext.prefixes + i,
sb_env_names[i], sb_env);
cached_env_vars[i] = xstrdup(sb_env);
} else
cached_env_vars[i] = NULL;
@@ -326,33 +288,31 @@ static void sb_process_env_settings(void)
}
}
-static int check_prefixes(char **prefixes, int num_prefixes, const char *path)
+static bool check_prefixes(char *prefixes, const char *path)
{
if (!prefixes)
- return 0;
+ return false;
- size_t i;
- for (i = 0; i < num_prefixes; ++i) {
- if (unlikely(!prefixes[i]))
- continue;
+ size_t prefix_len;
+
+ for (const char *prefix = prefixes; *prefix; prefix += prefix_len + 1) {
+ prefix_len = strlen(prefix);
- size_t prefix_len = strlen(prefixes[i]);
/* Start with a regular prefix match for speed */
- if (strncmp(path, prefixes[i], prefix_len))
+ if (strncmp(path, prefix, prefix_len))
continue;
/* Now, if prefix did not end with a slash, we need to make sure
* we are not matching in the middle of a filename. So check
* whether the match is followed by a slash, or NUL.
*/
- if (prefixes[i][prefix_len-1] != '/'
- && path[prefix_len] != '/' && path[prefix_len]
!= '\0')
+ if (prefix[prefix_len - 1] != '/' && path[prefix_len] != '/' &&
path[prefix_len] != '\0')
continue;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
@@ -360,7 +320,6 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr,
const char *func,
{
int old_errno = errno;
int result = 0;
- int retval;
/* Do not check non-filesystem objects like pipes and sockets */
/* Allow operations on memfd objects #910561 */
@@ -369,15 +328,11 @@ static int check_access(sbcontext_t *sbcontext, int
sb_nr, const char *func,
goto out;
}
- retval = check_prefixes(sbcontext->deny_prefixes,
- sbcontext->num_deny_prefixes, abs_path);
- if (1 == retval)
+ if (check_prefixes(sbcontext->deny_prefixes, abs_path))
/* Fall in a read/write denied path, Deny Access */
goto out;
- retval = check_prefixes(sbcontext->deny_prefixes,
- sbcontext->num_deny_prefixes, resolv_path);
- if (1 == retval)
+ if (check_prefixes(sbcontext->deny_prefixes, resolv_path))
/* Fall in a read/write denied path, Deny Access */
goto out;
@@ -397,9 +352,7 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr,
const char *func,
sb_nr == SB_NR_EXECVPE ||
sb_nr == SB_NR_FEXECVE))
{
- retval = check_prefixes(sbcontext->read_prefixes,
- sbcontext->num_read_prefixes,
resolv_path);
- if (1 == retval) {
+ if (check_prefixes(sbcontext->read_prefixes, resolv_path)) {
/* Fall in a readable path, Grant Access */
result = 1;
goto out;
@@ -478,16 +431,11 @@ static int check_access(sbcontext_t *sbcontext, int
sb_nr, const char *func,
sb_nr == SB_NR___XMKNODAT)
{
- retval = check_prefixes(sbcontext->write_denied_prefixes,
- sbcontext->num_write_denied_prefixes,
- resolv_path);
- if (1 == retval)
+ if (check_prefixes(sbcontext->write_denied_prefixes,
resolv_path))
/* Falls in a write denied path, Deny Access */
goto out;
- retval = check_prefixes(sbcontext->write_prefixes,
- sbcontext->num_write_prefixes,
resolv_path);
- if (1 == retval) {
+ if (check_prefixes(sbcontext->write_prefixes, resolv_path)) {
/* Falls in a writable path, Grant Access */
result = 1;
goto out;
@@ -519,9 +467,7 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr,
const char *func,
goto out;
}
- retval = check_prefixes(sbcontext->predict_prefixes,
- sbcontext->num_predict_prefixes,
resolv_path);
- if (1 == retval) {
+ if (check_prefixes(sbcontext->predict_prefixes, resolv_path)) {
/* Is a known access violation, so deny access,
* and do not log it */
sbcontext->show_access_violation = false;
diff --git a/libsandbox/libsandbox.h b/libsandbox/libsandbox.h
index d1a8e7e..22c5535 100644
--- a/libsandbox/libsandbox.h
+++ b/libsandbox/libsandbox.h
@@ -97,6 +97,8 @@ bool sb_realpathat(int dirfd, const char *restrict path, char
*buf, size_t bufsi
/* most linux systems use ENAMETOOLONG, but some (ia64) use ERANGE, as do some
BSDs */
#define errno_is_too_long() (errno == ENAMETOOLONG || errno == ERANGE)
+size_t malloc_size(void *ptr);
+
#include "sbutil.h"
/* glibc sometimes redefines this crap on us */
diff --git a/libsandbox/memory.c b/libsandbox/memory.c
index b6f7f80..1446116 100644
--- a/libsandbox/memory.c
+++ b/libsandbox/memory.c
@@ -127,6 +127,17 @@ void *realloc(void *ptr, size_t size)
return sp + ALIGN_FACTOR;
}
+size_t malloc_size(void *ptr)
+{
+ if (!ptr)
+ return 0;
+
+ size_t *sp = ptr;
+ sp -= 2;
+
+ return *sp - ALIGN_SIZE;
+}
+
char *strdup(const char *s)
{
size_t len;