Merge pull request #26935 from keszybz/test-parse_aux

Add test for auxv parsing
This commit is contained in:
Luca Boccassi
2023-03-23 23:13:42 +00:00
committed by GitHub
17 changed files with 228 additions and 126 deletions
+5 -69
View File
@@ -49,7 +49,6 @@
#include "sync-util.h"
#include "tmpfile-util.h"
#include "uid-alloc-range.h"
#include "unaligned.h"
#include "user-util.h"
/* The maximum size up to which we process coredumps. We use 1G on 32bit systems, and 32G on 64bit systems */
@@ -336,66 +335,6 @@ static int make_filename(const Context *context, char **ret) {
return 0;
}
#define _DEFINE_PARSE_AUXV(size, type, unaligned_read) \
static int parse_auxv##size( \
const void *auxv, \
size_t size_bytes, \
int *at_secure, \
uid_t *uid, \
uid_t *euid, \
gid_t *gid, \
gid_t *egid) { \
\
assert(auxv || size_bytes == 0); \
\
if (size_bytes % (2 * sizeof(type)) != 0) \
return log_warning_errno(SYNTHETIC_ERRNO(EIO), \
"Incomplete auxv structure (%zu bytes).", \
size_bytes); \
\
size_t words = size_bytes / sizeof(type); \
\
/* Note that we set output variables even on error. */ \
\
for (size_t i = 0; i + 1 < words; i += 2) { \
type key, val; \
\
key = unaligned_read((uint8_t*) auxv + i * sizeof(type)); \
val = unaligned_read((uint8_t*) auxv + (i + 1) * sizeof(type)); \
\
switch (key) { \
case AT_SECURE: \
*at_secure = val != 0; \
break; \
case AT_UID: \
*uid = val; \
break; \
case AT_EUID: \
*euid = val; \
break; \
case AT_GID: \
*gid = val; \
break; \
case AT_EGID: \
*egid = val; \
break; \
case AT_NULL: \
if (val != 0) \
goto error; \
return 0; \
} \
} \
error: \
return log_warning_errno(SYNTHETIC_ERRNO(ENODATA), \
"AT_NULL terminator not found, cannot parse auxv structure."); \
}
#define DEFINE_PARSE_AUXV(size)\
_DEFINE_PARSE_AUXV(size, uint##size##_t, unaligned_read_ne##size)
DEFINE_PARSE_AUXV(32);
DEFINE_PARSE_AUXV(64);
static int grant_user_access(int core_fd, const Context *context) {
int at_secure = -1;
uid_t uid = UID_INVALID, euid = UID_INVALID;
@@ -430,14 +369,11 @@ static int grant_user_access(int core_fd, const Context *context) {
return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Core file has non-native endianness, not adjusting permissions.");
if (elf[EI_CLASS] == ELFCLASS64)
r = parse_auxv64(context->meta[META_PROC_AUXV],
context->meta_size[META_PROC_AUXV],
&at_secure, &uid, &euid, &gid, &egid);
else
r = parse_auxv32(context->meta[META_PROC_AUXV],
context->meta_size[META_PROC_AUXV],
&at_secure, &uid, &euid, &gid, &egid);
r = parse_auxv(LOG_WARNING,
/* elf_class= */ elf[EI_CLASS],
context->meta[META_PROC_AUXV],
context->meta_size[META_PROC_AUXV],
&at_secure, &uid, &euid, &gid, &egid);
if (r < 0)
return r;
+92
View File
@@ -1,9 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <elf.h>
#include "coredump-util.h"
#include "extract-word.h"
#include "fileio.h"
#include "string-table.h"
#include "unaligned.h"
#include "virt.h"
static const char *const coredump_filter_table[_COREDUMP_FILTER_MAX] = {
@@ -65,6 +68,95 @@ int coredump_filter_mask_from_string(const char *s, uint64_t *ret) {
return 0;
}
#define _DEFINE_PARSE_AUXV(size, type, unaligned_read) \
static int parse_auxv##size( \
int log_level, \
const void *auxv, \
size_t size_bytes, \
int *at_secure, \
uid_t *uid, \
uid_t *euid, \
gid_t *gid, \
gid_t *egid) { \
\
assert(auxv || size_bytes == 0); \
assert(at_secure); \
assert(uid); \
assert(euid); \
assert(gid); \
assert(egid); \
\
if (size_bytes % (2 * sizeof(type)) != 0) \
return log_full_errno(log_level, \
SYNTHETIC_ERRNO(EIO), \
"Incomplete auxv structure (%zu bytes).", \
size_bytes); \
\
size_t words = size_bytes / sizeof(type); \
\
/* Note that we set output variables even on error. */ \
\
for (size_t i = 0; i + 1 < words; i += 2) { \
type key, val; \
\
key = unaligned_read((uint8_t*) auxv + i * sizeof(type)); \
val = unaligned_read((uint8_t*) auxv + (i + 1) * sizeof(type)); \
\
switch (key) { \
case AT_SECURE: \
*at_secure = val != 0; \
break; \
case AT_UID: \
*uid = val; \
break; \
case AT_EUID: \
*euid = val; \
break; \
case AT_GID: \
*gid = val; \
break; \
case AT_EGID: \
*egid = val; \
break; \
case AT_NULL: \
if (val != 0) \
goto error; \
return 0; \
} \
} \
error: \
return log_full_errno(log_level, \
SYNTHETIC_ERRNO(ENODATA), \
"AT_NULL terminator not found, cannot parse auxv structure."); \
}
#define DEFINE_PARSE_AUXV(size) \
_DEFINE_PARSE_AUXV(size, uint##size##_t, unaligned_read_ne##size)
DEFINE_PARSE_AUXV(32);
DEFINE_PARSE_AUXV(64);
int parse_auxv(int log_level,
uint8_t elf_class,
const void *auxv,
size_t size_bytes,
int *at_secure,
uid_t *uid,
uid_t *euid,
gid_t *gid,
gid_t *egid) {
switch (elf_class) {
case ELFCLASS64:
return parse_auxv64(log_level, auxv, size_bytes, at_secure, uid, euid, gid, egid);
case ELFCLASS32:
return parse_auxv32(log_level, auxv, size_bytes, at_secure, uid, euid, gid, egid);
default:
return log_full_errno(log_level, SYNTHETIC_ERRNO(EPROTONOSUPPORT),
"Unknown ELF class %d.", elf_class);
}
}
int set_coredump_filter(uint64_t value) {
char t[STRLEN("0xFFFFFFFF")];
+10
View File
@@ -26,5 +26,15 @@ const char* coredump_filter_to_string(CoredumpFilter i) _const_;
CoredumpFilter coredump_filter_from_string(const char *s) _pure_;
int coredump_filter_mask_from_string(const char *s, uint64_t *ret);
int parse_auxv(int log_level,
uint8_t elf_class,
const void *auxv,
size_t size_bytes,
int *at_secure,
uid_t *uid,
uid_t *euid,
gid_t *gid,
gid_t *egid);
int set_coredump_filter(uint64_t value);
void disable_coredumps(void);
+92
View File
@@ -1,7 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <elf.h>
#include "alloc-util.h"
#include "coredump-util.h"
#include "fileio.h"
#include "fd-util.h"
#include "format-util.h"
#include "macro.h"
#include "tests.h"
@@ -64,4 +69,91 @@ TEST(coredump_filter_mask_from_string) {
1 << COREDUMP_FILTER_SHARED_DAX)));
}
static void test_parse_auxv_two(
uint8_t elf_class,
size_t offset,
const char *data,
size_t data_size,
int expect_at_secure,
uid_t expect_uid,
uid_t expect_euid,
gid_t expect_gid,
gid_t expect_egid) {
int at_secure;
uid_t uid, euid;
gid_t gid, egid;
assert_se(parse_auxv(LOG_ERR, elf_class, data, data_size,
&at_secure, &uid, &euid, &gid, &egid) == 0);
log_debug("[offset=%zu] at_secure=%d, uid="UID_FMT", euid="UID_FMT", gid="GID_FMT", egid="GID_FMT,
offset,
at_secure, uid, euid, gid, egid);
assert_se(uid == expect_uid);
assert_se(euid == expect_euid);
assert_se(gid == expect_gid);
assert_se(egid == expect_egid);
}
static void test_parse_auxv_one(
uint8_t elf_class,
int dir_fd,
const char *filename,
int expect_at_secure,
uid_t expect_uid,
uid_t expect_euid,
gid_t expect_gid,
gid_t expect_egid) {
_cleanup_free_ char *buf;
const char *data;
size_t data_size;
log_info("Parsing %s…", filename);
assert_se(read_full_file_at(dir_fd, filename, &buf, &data_size) >= 0);
for (size_t offset = 0; offset < 8; offset++) {
_cleanup_free_ char *buf2 = NULL;
if (offset == 0)
data = buf;
else {
assert_se(buf2 = malloc(offset + data_size));
memcpy(buf2 + offset, buf, data_size);
data = buf2 + offset;
}
test_parse_auxv_two(elf_class, offset, data, data_size,
expect_at_secure, expect_uid, expect_euid, expect_gid, expect_egid);
}
}
TEST(test_parse_auxv) {
_cleanup_free_ char *dir = NULL;
_cleanup_close_ int dir_fd = -EBADF;
assert_se(get_testdata_dir("auxv", &dir) >= 0);
dir_fd = open(dir, O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_PATH);
assert_se(dir_fd >= 0);
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
test_parse_auxv_one(ELFCLASS32, dir_fd, "resolved.arm32", 0, 193, 193, 193, 193);
test_parse_auxv_one(ELFCLASS64, dir_fd, "bash.riscv64", 0, 1001, 1001, 1001, 1001);
test_parse_auxv_one(ELFCLASS32, dir_fd, "sleep.i686", 0, 1000, 1000, 1000, 1000);
/* after chgrp and chmod g+s */
test_parse_auxv_one(ELFCLASS32, dir_fd, "sleep32.i686", 1, 1000, 1000, 1000, 10);
test_parse_auxv_one(ELFCLASS64, dir_fd, "sleep64.amd64", 1, 1000, 1000, 1000, 10);
test_parse_auxv_one(ELFCLASS64, dir_fd, "sudo.aarch64", 1, 1494200408, 0, 1494200408, 1494200408);
test_parse_auxv_one(ELFCLASS64, dir_fd, "sudo.amd64", 1, 1000, 0, 1000, 1000);
/* Those run unprivileged, but start as root. */
test_parse_auxv_one(ELFCLASS64, dir_fd, "dbus-broker-launch.amd64", 0, 0, 0, 0, 0);
test_parse_auxv_one(ELFCLASS64, dir_fd, "dbus-broker-launch.aarch64", 0, 0, 0, 0, 0);
test_parse_auxv_one(ELFCLASS64, dir_fd, "polkitd.aarch64", 0, 0, 0, 0, 0);
} else {
test_parse_auxv_one(ELFCLASS64, dir_fd, "cat.s390x", 0, 3481, 3481, 3481, 3481);
}
}
DEFINE_TEST_MAIN(LOG_INFO);
+3
View File
@@ -0,0 +1,3 @@
/*.* -whitespace
/*.* binary
/*.* generated
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+26 -57
View File
@@ -3,63 +3,32 @@
if install_tests
testdata_dir = testsdir + '/testdata/'
install_subdir('journal-data',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('test-execute',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('test-fstab-generator',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('test-path',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('test-path-util',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('test-umount',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('test-network-generator-conversion',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-03.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-04.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-06.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-10.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-11.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-16.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-28.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-30.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-52.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-63.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
install_subdir('testsuite-80.units',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
foreach subdir : [
'auxv',
'journal-data',
'units',
'test-execute',
'test-fstab-generator',
'test-path',
'test-path-util',
'test-umount',
'test-network-generator-conversion',
'testsuite-03.units',
'testsuite-04.units',
'testsuite-06.units',
'testsuite-10.units',
'testsuite-11.units',
'testsuite-16.units',
'testsuite-28.units',
'testsuite-30.units',
'testsuite-52.units',
'testsuite-63.units',
'testsuite-80.units',
]
install_subdir(subdir,
exclude_files : '.gitattributes',
install_dir : testdata_dir)
endforeach
install_data(kbd_model_map,
install_dir : testdata_dir + '/test-keymap-util')