ask-password: reject oversized Plymouth prompts (#43102)

Plymouth encodes the password prompt length in a single byte.
Reject prompts whose length cannot be represented instead of
wrapping the encoded length while sending the complete message.
This commit is contained in:
Armaan Sandhu
2026-07-23 19:18:13 +09:00
committed by GitHub
parent 7359f11be6
commit 92e2f70a3c
5 changed files with 74 additions and 9 deletions
+13 -9
View File
@@ -302,9 +302,9 @@ int ask_password_plymouth(
_cleanup_close_ int fd = -EBADF, inotify_fd = -EBADF;
_cleanup_free_ char *packet = NULL;
ssize_t k;
int r, n;
int r;
char buffer[LINE_MAX];
size_t p = 0;
size_t packet_size, p = 0;
assert(req);
assert(ret);
@@ -329,13 +329,16 @@ int ask_password_plymouth(
if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED)) {
packet = strdup("c");
n = 1;
} else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
packet = NULL;
packet_size = 2;
} else {
r = plymouth_build_password_packet(message, &packet, &packet_size);
if (r < 0)
return r;
}
if (!packet)
return -ENOMEM;
r = loop_write_full(fd, packet, n + 1, USEC_INFINITY);
r = loop_write_full(fd, packet, packet_size, USEC_INFINITY);
if (r < 0)
return r;
@@ -416,10 +419,11 @@ int ask_password_plymouth(
* with a normal password request */
packet = mfree(packet);
if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
return -ENOMEM;
r = plymouth_build_password_packet(message, &packet, &packet_size);
if (r < 0)
return r;
r = loop_write_full(fd, packet, n + 1, USEC_INFINITY);
r = loop_write_full(fd, packet, packet_size, USEC_INFINITY);
if (r < 0)
return r;
+29
View File
@@ -7,6 +7,35 @@
#include "plymouth-util.h"
#include "socket-util.h"
int plymouth_build_password_packet(const char *message, char **ret_packet, size_t *ret_size) {
size_t l, sz;
char *packet;
assert(message);
assert(ret_packet);
assert(ret_size);
l = strlen(message);
if (l >= UCHAR_MAX)
return -EMSGSIZE;
/* 3 byte header ('*', command, payload length), followed by the message and its NUL terminator. */
sz = 3 + l + 1;
packet = new(char, sz);
if (!packet)
return -ENOMEM;
packet[0] = '*';
packet[1] = '\x02';
packet[2] = (uint8_t) (l + 1);
memcpy(packet + 3, message, l + 1);
*ret_packet = packet;
*ret_size = sz;
return 0;
}
int plymouth_connect(int flags) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
+1
View File
@@ -5,6 +5,7 @@
#include "forward.h"
int plymouth_connect(int flags);
int plymouth_build_password_packet(const char *message, char **ret_packet, size_t *ret_size);
int plymouth_send_raw(const void *raw, size_t size, int flags);
int plymouth_send_msg(const char *text, bool pause_spinner);
int plymouth_hide_splash(void);
+1
View File
@@ -171,6 +171,7 @@ simple_tests += files(
'test-path-util.c',
'test-percent-util.c',
'test-pidref.c',
'test-plymouth-util.c',
'test-pressure.c',
'test-pretty-print.c',
'test-printf.c',
+30
View File
@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "plymouth-util.h"
#include "tests.h"
TEST(build_password_packet) {
_cleanup_free_ char *packet = NULL;
size_t size;
ASSERT_OK(plymouth_build_password_packet("Password:", &packet, &size));
ASSERT_EQ(size, 13U);
ASSERT_EQ(memcmp(packet, "*\x02\x0aPassword:\0", size), 0);
packet = mfree(packet);
char message[UCHAR_MAX];
memset(message, 'x', sizeof(message) - 1);
message[sizeof(message) - 1] = '\0';
ASSERT_OK(plymouth_build_password_packet(message, &packet, &size));
ASSERT_EQ(size, 3U + sizeof(message));
ASSERT_EQ((uint8_t) packet[2], UCHAR_MAX);
ASSERT_EQ(memcmp(packet + 3, message, sizeof(message)), 0);
packet = mfree(packet);
ASSERT_ERROR(plymouth_build_password_packet(strjoina(message, "x"), &packet, &size), EMSGSIZE);
ASSERT_NULL(packet);
}
DEFINE_TEST_MAIN(LOG_INFO);