]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
keyring-util: Use reported key size to resize buf
authorAdrian Vovk <adrianvovk@gmail.com>
Thu, 1 Feb 2024 22:53:01 +0000 (17:53 -0500)
committerLuca Boccassi <luca.boccassi@gmail.com>
Thu, 15 Feb 2024 11:13:34 +0000 (11:13 +0000)
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.

src/shared/keyring-util.c

index 655cf5241d2937d6db9bba37d9dbe9e357051a86..fadd90ebcce465ab7efbcf4f55ba9a564034497c 100644 (file)
@@ -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;
         }
 }