Skip to content

Commit dbd0634

Browse files
committed
Switch the file backend over to memfd
Created and sealed a memfd snapshot when loading the file backend so the descriptor is ready for database consumers. Streamed trust entries into a provided memfd, and tracked the active descriptor for directory traversal to avoid redundant asprintf allocations
1 parent 5d09baf commit dbd0634

3 files changed

Lines changed: 67 additions & 31 deletions

File tree

src/library/file-backend.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@
2626

2727
#include "config.h"
2828

29+
#include <errno.h>
2930
#include <stddef.h>
31+
#include <string.h>
32+
#include <fcntl.h>
33+
#include <sys/mman.h>
34+
#include <unistd.h>
3035

3136
#include "fapolicyd-backend.h"
3237
#include "llist.h"
@@ -56,7 +61,31 @@ static int file_load_list(const conf_t *conf)
5661
{
5762
msg(LOG_DEBUG, "Loading file backend");
5863
list_empty(&file_backend.list);
59-
trust_file_load_all(&file_backend.list);
64+
65+
/* Close any previous snapshot before rebuilding the backend view. */
66+
if (file_backend.memfd != -1) {
67+
close(file_backend.memfd);
68+
file_backend.memfd = -1;
69+
file_backend.entries = -1;
70+
}
71+
72+
int memfd = memfd_create("file_snapshot",
73+
MFD_CLOEXEC | MFD_ALLOW_SEALING);
74+
if (memfd < 0) {
75+
msg(LOG_WARNING, "memfd_create failed for file backend (%s)",
76+
strerror(errno));
77+
return 1;
78+
}
79+
80+
trust_file_load_all(&file_backend.list, memfd);
81+
82+
/* Seal the snapshot so readers see a stable view. */
83+
if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK |
84+
F_SEAL_GROW | F_SEAL_WRITE) == -1)
85+
msg(LOG_WARNING, "Failed to seal file backend memfd (%s)",
86+
strerror(errno));
87+
file_backend.memfd = memfd;
88+
6089
return 0;
6190
}
6291

src/library/trust-file.c

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "config.h"
2727

2828
#include <ctype.h>
29+
#include <errno.h>
2930
#include <fcntl.h>
3031
#include <ftw.h>
3132
#include <stddef.h>
@@ -64,6 +65,7 @@
6465
list_t _list;
6566
char *_path;
6667
int _count;
68+
int _memfd = -1;
6769

6870
struct trust_seen_entry {
6971
const char *path;
@@ -174,7 +176,7 @@ int trust_file_append(const char *fpath, list_t *list)
174176
{
175177
list_t content;
176178
list_init(&content);
177-
int rc = trust_file_load(fpath, &content);
179+
int rc = trust_file_load(fpath, &content, -1);
178180
// if trust file does not exist, we ignore it as it will be created while writing
179181
if (rc == 2) {
180182
// exit on parse error, we dont want invalid entries to be autoremoved
@@ -258,7 +260,7 @@ static int parse_line_backwards(char *line, char *path, unsigned long *size, cha
258260
* @param list Trust file will be loaded into this list
259261
* @return 0 on success, 1 if file can't be open, 2 on parsing error
260262
*/
261-
int trust_file_load(const char *fpath, list_t *list)
263+
int trust_file_load(const char *fpath, list_t *list, int memfd)
262264
{
263265
char buffer[BUFFER_SIZE];
264266
int escaped = 0;
@@ -271,7 +273,8 @@ int trust_file_load(const char *fpath, list_t *list)
271273
return 1;
272274

273275
while (fgets(buffer, BUFFER_SIZE, file)) {
274-
char name[4097], sha[65], *index = NULL, *data = NULL;
276+
char name[4097], sha[65], *index = NULL;
277+
char data_buf[BUFFER_SIZE];
275278
unsigned long sz;
276279
unsigned int tsource = SRC_FILE_DB;
277280

@@ -289,19 +292,17 @@ int trust_file_load(const char *fpath, list_t *list)
289292
goto out;
290293
}
291294

292-
if (asprintf(&data, DATA_FORMAT, tsource, sz, sha) == -1)
293-
data = NULL;
295+
int len = snprintf(data_buf, sizeof(data_buf),
296+
DATA_FORMAT, tsource, sz, sha);
297+
if (len < 0 || len >= (int)sizeof(data_buf)) {
298+
msg(LOG_ERR, "Entry too large in %s", fpath);
299+
continue;
300+
}
294301

295-
// if old format unescape
302+
/* If the legacy format was used, unescape the stored path. */
296303
index = escaped ? unescape(name) : strdup(name);
297304
if (index == NULL) {
298305
msg(LOG_ERR, "Could not unescape %s from %s", name, fpath);
299-
free(data);
300-
continue;
301-
}
302-
303-
if (data == NULL) {
304-
free(index);
305306
continue;
306307
}
307308

@@ -311,28 +312,25 @@ int trust_file_load(const char *fpath, list_t *list)
311312
if (entry) {
312313
msg(LOG_WARNING, "%s contains a duplicate %s", fpath, index);
313314
free(index);
314-
free(data);
315315
continue;
316316
}
317317

318318
entry = malloc(sizeof(*entry));
319319
if (!entry) {
320320
msg(LOG_ERR, "Out of memory tracking %s", index);
321321
free(index);
322-
free(data);
323322
rc = 3;
324323
goto out;
325324
}
326325

327326
entry->path = index;
328-
HASH_ADD_KEYPTR(hh, seen, entry->path, strlen(entry->path), entry);
327+
HASH_ADD_KEYPTR(hh, seen, entry->path,
328+
strlen(entry->path), entry);
329329

330-
if (list_append(list, index, data)) {
331-
HASH_DEL(seen, entry);
332-
free(entry);
333-
free(index);
334-
free(data);
335-
}
330+
if (dprintf(memfd, "%s %s\n", index, data_buf) < 0)
331+
msg(LOG_ERR,
332+
"dprintf failed writing %s to memfd (%s)",
333+
index, strerror(errno));
336334
}
337335

338336
out:
@@ -342,17 +340,20 @@ int trust_file_load(const char *fpath, list_t *list)
342340

343341
HASH_ITER(hh, seen, item, tmp) {
344342
HASH_DEL(seen, item);
343+
if (memfd >= 0)
344+
free((char *)item->path);
345345
free(item);
346346
}
347347

348348
return rc;
349349
}
350350

351+
351352
int trust_file_delete_path(const char *fpath, const char *path)
352353
{
353354
list_t list;
354355
list_init(&list);
355-
int rc = trust_file_load(fpath, &list);
356+
int rc = trust_file_load(fpath, &list, -1);
356357
switch (rc) {
357358
case 1:
358359
msg(LOG_ERR, "Cannot open %s", fpath);
@@ -400,7 +401,7 @@ int trust_file_update_path(const char *fpath, const char *path)
400401
{
401402
list_t list;
402403
list_init(&list);
403-
int rc = trust_file_load(fpath, &list);
404+
int rc = trust_file_load(fpath, &list, -1);
404405
switch (rc) {
405406
case 1:
406407
msg(LOG_ERR, "Cannot open %s", fpath);
@@ -434,7 +435,7 @@ int trust_file_rm_duplicates(const char *fpath, list_t *list)
434435
{
435436
list_t trust_file;
436437
list_init(&trust_file);
437-
int rc = trust_file_load(fpath, &trust_file);
438+
int rc = trust_file_load(fpath, &trust_file, -1);
438439
switch (rc) {
439440
case 1:
440441
msg(LOG_ERR, "Cannot open %s", fpath);
@@ -464,7 +465,7 @@ static int ftw_load(const char *fpath,
464465
struct FTW *ftwbuf __attribute__ ((unused)))
465466
{
466467
if (typeflag == FTW_F)
467-
trust_file_load(fpath, &_list);
468+
trust_file_load(fpath, &_list, _memfd);
468469
return FTW_CONTINUE;
469470
}
470471

@@ -502,12 +503,18 @@ static int ftw_rm_duplicates(const char *fpath,
502503

503504

504505

505-
void trust_file_load_all(list_t *list)
506+
void trust_file_load_all(list_t *list, int memfd)
506507
{
507508
list_empty(&_list);
508-
trust_file_load(TRUST_FILE_PATH, &_list);
509+
_memfd = memfd;
510+
/* Populate either the in-memory list or the memfd snapshot. */
511+
trust_file_load(TRUST_FILE_PATH, &_list, memfd);
509512
nftw(TRUST_DIR_PATH, &ftw_load, FTW_NOPENFD, FTW_FLAGS);
510-
list_merge(list, &_list);
513+
if (memfd < 0)
514+
list_merge(list, &_list);
515+
else
516+
list_empty(&_list);
517+
_memfd = -1;
511518
}
512519

513520
int trust_file_delete_path_all(const char *path)

src/library/trust-file.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
#define TRUST_DIR_PATH "/etc/fapolicyd/trust.d/"
3232

3333
int trust_file_append(const char *fpath, list_t *list);
34-
int trust_file_load(const char *fpath, list_t *list);
34+
int trust_file_load(const char *fpath, list_t *list, int memfd);
3535
int trust_file_update_path(const char *fpath, const char *path);
3636
int trust_file_delete_path(const char *fpath, const char *path);
3737
int trust_file_rm_duplicates(const char *fpath, list_t *list);
3838

39-
void trust_file_load_all(list_t *list);
39+
void trust_file_load_all(list_t *list, int memfd);
4040
int trust_file_update_path_all(const char *path);
4141
int trust_file_delete_path_all(const char *path);
4242
void trust_file_rm_duplicates_all(list_t *list);

0 commit comments

Comments
 (0)