libkmipclient: Protect from symlink-following attacks

When creating or writing files, make sure that the file is not a
sysmlink. Such files created by libkmipclient 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 <ifranzki@linux.ibm.com>
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2026-06-30 09:52:15 +02:00
committed by Jan Höppner
parent a3a2d70603
commit f0bf1985c3
3 changed files with 36 additions and 3 deletions

View File

@@ -1489,7 +1489,7 @@ retry:
}
if (i == 0 && server_cert_pem != NULL) {
fp = fopen(server_cert_pem, "w");
fp = fopen_nofollow(server_cert_pem, "w");
if (fp == NULL) {
rc = -errno;
kmip_debug(debug, "Failed to open %s for write",
@@ -1507,7 +1507,7 @@ retry:
fp = NULL;
if (server_pubkey_pem != NULL) {
fp = fopen(server_pubkey_pem, "w");
fp = fopen_nofollow(server_pubkey_pem, "w");
if (fp == NULL) {
rc = -errno;
kmip_debug(debug, "Failed to open %s "
@@ -1533,7 +1533,7 @@ retry:
if (i > 0 && cert_chain_pem != NULL) {
if (fp == NULL)
fp = fopen(cert_chain_pem, "w");
fp = fopen_nofollow(cert_chain_pem, "w");
if (fp == NULL) {
rc = -errno;
kmip_debug(debug, "Failed to open %s for write",

View File

@@ -12,9 +12,11 @@
#include <errno.h>
#include <err.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "utils.h"
#include "names.h"
@@ -726,3 +728,32 @@ enum kmip_tag kmip_find_v1_attribute_name_tag(struct kmip_node *parent)
return 0;
}
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;
}

View File

@@ -58,4 +58,6 @@ void kmip_node_dump(struct kmip_node *node, bool debug);
enum kmip_tag kmip_find_v1_attribute_name_tag(struct kmip_node *parent);
FILE *fopen_nofollow(const char *path, const char *mode);
#endif