core: add LUOSession= unit setting (#42530)
Acquiring a LUO session from /dev/liveupdate requires privileges, and also the device is a single-owner driver so only a single process can open it at any given time. Add a LUOSession= service settings that allows units running without privileges to get a session assigned to them. The kernel imposes a 64 chars limit on session names, which is too short to avoid clashes, so derive a hash from joining the unit name with the parameter name, that way two units using the same setting don't clash.
This commit is contained in:
+59
-2
@@ -326,9 +326,64 @@ static int do_check_hijack(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_check_sessions(int argc, char *argv[]) {
|
||||
const char *e;
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
int n_fds, n_verified = 0, r;
|
||||
|
||||
/* Verify that named LUO sessions are present in the fd store */
|
||||
e = getenv("LISTEN_FDS");
|
||||
if (!e)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "No LISTEN_FDS environment variable set!");
|
||||
|
||||
r = safe_atoi(e, &n_fds);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse LISTEN_FDS='%s': %m", e);
|
||||
|
||||
e = getenv("LISTEN_FDNAMES");
|
||||
if (e) {
|
||||
names = strv_split(e, ":");
|
||||
if (!names)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
for (int i = 2; i < argc; i++) {
|
||||
const char *session_name = argv[i];
|
||||
int fd = -EBADF;
|
||||
|
||||
/* Find the fd by name */
|
||||
STRV_FOREACH(name, names) {
|
||||
int idx = (int) (name - names);
|
||||
if (idx >= n_fds)
|
||||
break;
|
||||
if (streq(*name, session_name)) {
|
||||
fd = SD_LISTEN_FDS_START + idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
|
||||
"LUO session '%s' not found in fd store!", session_name);
|
||||
|
||||
r = fd_is_luo_session(fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to check if fd '%s' is a LUO session: %m", session_name);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"fd '%s' is not a LUO session!", session_name);
|
||||
|
||||
log_info("Verified LUO session '%s' is present and valid.", session_name);
|
||||
n_verified++;
|
||||
}
|
||||
|
||||
log_info("All %d LUO session(s) verified.", n_verified);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
if (argc < 2 || argc > 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Usage: %s store|check|store-hijack|check-hijack [PREFIX]", argv[0]);
|
||||
if (argc < 2)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Usage: %s store|check|store-hijack|check-hijack [PREFIX] | check-sessions NAME...", argv[0]);
|
||||
|
||||
const char *prefix = argc > 2 ? argv[2] : "luosession";
|
||||
|
||||
@@ -340,6 +395,8 @@ static int run(int argc, char *argv[]) {
|
||||
return do_store_hijack();
|
||||
if (streq(argv[1], "check-hijack"))
|
||||
return do_check_hijack();
|
||||
if (streq(argv[1], "check-sessions"))
|
||||
return do_check_sessions(argc, argv);
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown command: %s", argv[1]);
|
||||
}
|
||||
|
||||
@@ -1607,6 +1607,21 @@ TEST(string_is_safe) {
|
||||
ASSERT_FALSE(string_is_safe("/foo", STRING_FILENAME));
|
||||
ASSERT_FALSE(string_is_safe("foo/bar", STRING_FILENAME));
|
||||
|
||||
/* STRING_DISALLOW_WHITESPACE: rejects whitespace (space, tab, newline, carriage return). */
|
||||
ASSERT_TRUE(string_is_safe("hello", STRING_DISALLOW_WHITESPACE));
|
||||
ASSERT_TRUE(string_is_safe("foo-bar_baz", STRING_DISALLOW_WHITESPACE));
|
||||
ASSERT_TRUE(string_is_safe("über", STRING_DISALLOW_WHITESPACE)); /* valid UTF-8 still allowed */
|
||||
ASSERT_TRUE(string_is_safe("hello world", 0)); /* space accepted by default */
|
||||
ASSERT_FALSE(string_is_safe("hello world", STRING_DISALLOW_WHITESPACE)); /* but not with the flag */
|
||||
ASSERT_FALSE(string_is_safe(" ", STRING_DISALLOW_WHITESPACE));
|
||||
ASSERT_FALSE(string_is_safe("foo ", STRING_DISALLOW_WHITESPACE));
|
||||
ASSERT_FALSE(string_is_safe(" foo", STRING_DISALLOW_WHITESPACE));
|
||||
ASSERT_FALSE(string_is_safe("a\tb", STRING_DISALLOW_WHITESPACE));
|
||||
ASSERT_FALSE(string_is_safe("a\rb", STRING_DISALLOW_WHITESPACE));
|
||||
/* The flag overrides STRING_ALLOW_NEWLINES for the newline character, which is whitespace too. */
|
||||
ASSERT_TRUE(string_is_safe("a\nb", STRING_ALLOW_NEWLINES));
|
||||
ASSERT_FALSE(string_is_safe("a\nb", STRING_ALLOW_NEWLINES | STRING_DISALLOW_WHITESPACE));
|
||||
|
||||
/* Pairwise combinations. */
|
||||
ASSERT_TRUE(string_is_safe("", STRING_ALLOW_EMPTY | STRING_ASCII));
|
||||
ASSERT_FALSE(string_is_safe("über", STRING_ALLOW_EMPTY | STRING_ASCII));
|
||||
|
||||
Reference in New Issue
Block a user