From 226728731c556891f67b1a3d21b6fb8faa2f909b Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Tue, 30 Jun 2026 09:50:45 +0200 Subject: [PATCH] libseckey: Protect from symlink-following attacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When creating or writing files, make sure that the file is not a sysmlink. Such files created by libseckey are typically stored inside the zkey repository and the owner and mode of them are changed to. allow read/write for the owner user and the 'zkeyadm' group. It would allow a symlink-following attack if the file being created are symlinks. Make sure to open such files with the 'O_NOFOLLOW' flag. Assisted-by: IBM Bob:2.0.0 Signed-off-by: Ingo Franzki Reviewed-by: Finn Callies Signed-off-by: Jan Höppner --- libseckey/sk_utilities.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/libseckey/sk_utilities.c b/libseckey/sk_utilities.c index afaa8c52..88a12b89 100644 --- a/libseckey/sk_utilities.c +++ b/libseckey/sk_utilities.c @@ -10,10 +10,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -811,6 +813,35 @@ out: return rc; } +static inline FILE *fopen_nofollow(const char *path, const char *mode) +{ + int flags = O_NOFOLLOW; + int fd; + FILE *fp; + + /* Determine flags based on mode */ + if (mode[0] == 'r') + flags |= (mode[1] == '+') ? O_RDWR : O_RDONLY; + else if (mode[0] == 'w') + flags |= O_CREAT | O_TRUNC | + ((mode[1] == '+') ? O_RDWR : O_WRONLY); + else if (mode[0] == 'a') + flags |= O_CREAT | O_APPEND | + ((mode[1] == '+') ? O_RDWR : O_WRONLY); + else + return NULL; + + fd = open(path, flags, 0600); + if (fd < 0) + return NULL; + + fp = fdopen(fd, mode); + if (fp == NULL) { + close(fd); + return NULL; + } + return fp; +} /** * Reads a X.509 certificate from the specified PEM file. @@ -863,7 +894,7 @@ int SK_UTIL_write_x509_certificate(const char *pem_filename, X509 *cert) if (pem_filename == NULL || cert == NULL) return -EINVAL; - fp = fopen(pem_filename, "w"); + fp = fopen_nofollow(pem_filename, "w"); if (fp == NULL) return -errno; @@ -898,7 +929,7 @@ int SK_UTIL_write_x509_request(const char *pem_filename, X509_REQ *req, if (pem_filename == NULL || req == NULL) return -EINVAL; - fp = fopen(pem_filename, "w"); + fp = fopen_nofollow(pem_filename, "w"); if (fp == NULL) return -errno; @@ -982,7 +1013,7 @@ int SK_UTIL_write_key_blob(const char *filename, unsigned char *key_blob, if (filename == NULL || key_blob == NULL || key_blob_len == 0) return -EINVAL; - fp = fopen(filename, "w"); + fp = fopen_nofollow(filename, "w"); if (fp == NULL) return -errno; @@ -1047,7 +1078,7 @@ int SK_UTIL_write_public_key(const char *pem_filename, EVP_PKEY *pkey) if (pem_filename == NULL || pkey == NULL) return -EINVAL; - fp = fopen(pem_filename, "w"); + fp = fopen_nofollow(pem_filename, "w"); if (fp == NULL) return -errno;