From 446fe466539a32403d1c6976d565eb06e409021b Mon Sep 17 00:00:00 2001 From: Frank <111432253+fhofmannCF@users.noreply.github.com> Date: Fri, 19 Aug 2022 18:08:19 +0100 Subject: [PATCH] Limit KeyctlString() to DESCRIBE / GET_SECURITY KeyctlString() treats the query data buffer filled by the keyctl(2) syscall as C-Style string with a trailing NULL byte. This is only true for two cmds - KEYCTL_DESCRIBE and KEYCTL_GET_SECURITY. Both are guaranteed to return at least an empty (C) string (i.e. a one-byte-sized buffer containing only a NULL byte) if the requested attribute is not set at all. Other cmds that can be passed to the system call - KEYCTL_READ most prominently - return explicitly-sized binary data; NULL bytes have no special meaning for these queries and are _part_ of the returned data, irrespective of where in the buffer they occur. Returning nothing (zero-length) can also be permitted; example of this is a KEYCTL_READ on an empty keyring. If KeyctlString() is called with any of the keyctl(2) query commands other than the two that are guaranteed to return C-style strings, it will either: * panic (attempting to strip trailing null bytes from zero-sized buffers), or * truncate the returned data in error (for KEYCTL_READ of a key payload). Therefore, restrict the use. --- unix/syscall_linux.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go index ecb0f27fb..60f203a90 100644 --- a/unix/syscall_linux.go +++ b/unix/syscall_linux.go @@ -1381,6 +1381,13 @@ func SetsockoptTCPRepairOpt(fd, level, opt int, o []TCPRepairOpt) (err error) { // KeyctlString calls keyctl commands which return a string. // These commands are KEYCTL_DESCRIBE and KEYCTL_GET_SECURITY. func KeyctlString(cmd int, id int) (string, error) { + // Other queries - particularly KEYCTL_READ - can either return zero-length data, + // or explicitly-sized buffers of binary data (which may include NULL bytes). + // This function misbehaves then (panics or truncates returns), so explicitly + // allow only the two cmds documented to return NUL-terminated (C-type) strings. + if cmd != unix.KEYCTL_DESCRIBE || cmd != unix.KEYCTL_GET_SECURITY { + return "", EINVAL + } // We must loop as the string data may change in between the syscalls. // We could allocate a large buffer here to reduce the chance that the // syscall needs to be called twice; however, this is unnecessary as