summaryrefslogtreecommitdiffstats
path: root/src/shared/keyring-util.c
diff options
context:
space:
mode:
authorAdrian Vovk <adrianvovk@gmail.com>2024-02-01 23:53:01 +0100
committerLuca Boccassi <luca.boccassi@gmail.com>2024-02-15 12:13:34 +0100
commitd0aef638ac43ad64df920d8b3f6c2d835db7643c (patch)
treeb9762934bc7f31f572eed07da5f07a17e47e0285 /src/shared/keyring-util.c
parentnspawn: add support for owneridmap bind option (diff)
downloadsystemd-d0aef638ac43ad64df920d8b3f6c2d835db7643c.tar.xz
systemd-d0aef638ac43ad64df920d8b3f6c2d835db7643c.zip
keyring-util: Use reported key size to resize buf
According to keyctl(2), the return value for KEYCTL_READ is: The amount of data that is available in the key, irrespective of the provided buffer size So, we could pass in a NULL buffer to query the size, then allocate the exact right amount of space, then call keyctl again to get the key data. However, we must still keep the for loop to avoid TOCTOU issues: the key might have been replaced with something bigger while we're busy allocating the buffer to store it. Thus, we can actually save a syscall by picking some reasonable default buffer size and skipping the NULL call to keyctl. If our default is big enough, we're done and have saved a syscall! If not, then the first call behaves essentially the same as the NULL call, and we use the size it returns to reallocate the buffer appropriately.
Diffstat (limited to '')
-rw-r--r--src/shared/keyring-util.c21
1 files changed, 9 insertions, 12 deletions
diff --git a/src/shared/keyring-util.c b/src/shared/keyring-util.c
index 655cf5241d..fadd90ebcc 100644
--- a/src/shared/keyring-util.c
+++ b/src/shared/keyring-util.c
@@ -5,34 +5,31 @@
#include "missing_syscall.h"
int keyring_read(key_serial_t serial, void **ret, size_t *ret_size) {
- size_t m = 100;
+ size_t bufsize = 100;
for (;;) {
- _cleanup_(erase_and_freep) uint8_t *p = NULL;
+ _cleanup_(erase_and_freep) uint8_t *buf = NULL;
long n;
- p = new(uint8_t, m+1);
- if (!p)
+ buf = new(uint8_t, bufsize + 1);
+ if (!buf)
return -ENOMEM;
- n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
+ n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) buf, (unsigned long) bufsize, 0);
if (n < 0)
return -errno;
- if ((size_t) n <= m) {
- p[n] = 0; /* NUL terminate, just in case */
+ if ((size_t) n <= bufsize) {
+ buf[n] = 0; /* NUL terminate, just in case */
if (ret)
- *ret = TAKE_PTR(p);
+ *ret = TAKE_PTR(buf);
if (ret_size)
*ret_size = n;
return 0;
}
- if (m > (SIZE_MAX-1) / 2) /* overflow check */
- return -ENOMEM;
-
- m *= 2;
+ bufsize = (size_t) n;
}
}