Skip to content

Commit

Permalink
fix(dracut-util): avoid memory leak
Browse files Browse the repository at this point in the history
The content of the kernel command line is assigned via `strdup`, but not freed
on exit. This happens after each call to `getarg(s)`, what makes an interesting
amount of bytes not released at every boot.

```
master> grep -r -o -e getarg -e getargs modules.d | wc -l
457
master> export CMDLINE=$(< /proc/cmdline)
master> echo ${#CMDLINE}
130
afeijoo@localhost:~/src/dracut/opensuse-fork/master> valgrind --leak-check=full --show-leak-kinds=all ./dracut-getarg security
==24270== Memcheck, a memory error detector
==24270== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==24270== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==24270== Command: ./dracut-getarg security
==24270==
apparmor
==24270==
==24270== HEAP SUMMARY:
==24270==     in use at exit: 131 bytes in 1 blocks
==24270==   total heap usage: 2 allocs, 1 frees, 1,155 bytes allocated
==24270==
==24270== 131 bytes in 1 blocks are definitely lost in loss record 1 of 1
==24270==    at 0x4838744: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==24270==    by 0x490D839: strdup (in /lib64/libc-2.31.so)
==24270==    by 0x108AF6: getarg (util.c:188)
==24270==    by 0x108AF6: main (util.c:300)
==24270==
==24270== LEAK SUMMARY:
==24270==    definitely lost: 131 bytes in 1 blocks
==24270==    indirectly lost: 0 bytes in 0 blocks
==24270==      possibly lost: 0 bytes in 0 blocks
==24270==    still reachable: 0 bytes in 0 blocks
==24270==         suppressed: 0 bytes in 0 blocks
==24270==
==24270== For lists of detected and suppressed errors, rerun with: -s
==24270== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
```
  • Loading branch information
aafeijoo-suse committed Jan 16, 2024
1 parent 4980bad commit 217bcfd
Showing 1 changed file with 32 additions and 16 deletions.
48 changes: 32 additions & 16 deletions src/util/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

// Parts are copied from the linux kernel

#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

// CODE FROM LINUX KERNEL START

Expand Down Expand Up @@ -56,6 +57,13 @@ static char *skip_spaces(const char *str)
return (char *)str;
}

#define _cleanup_(x) __attribute__((cleanup(x)))
static inline void freep(void *p)

Check notice

Code scanning / CodeQL

Unused static function Note

Static function freep is unreachable
{
free(*(void **)p);
}
#define _cleanup_free_ _cleanup_(freep)

/*
* Parse a string to get a param value pair.
* You can use " around spaces, but can't escape ".
Expand Down Expand Up @@ -179,17 +187,20 @@ static int getarg(int argc, char **argv)
char *search_value;
char *end_value = NULL;
bool bool_value = false;
char *cmdline = NULL;
_cleanup_free_ char *cmdline = NULL;
char *args = NULL;

if (argc != 2) {
usage(GETARG, EXIT_FAILURE, "Number of arguments invalid");
}

char *p = getenv("CMDLINE");
if (p == NULL) {
usage(GETARG, EXIT_FAILURE, "CMDLINE env not set");
}
cmdline = strdup(p);

if (argc != 2) {
usage(GETARG, EXIT_FAILURE, "Number of arguments invalid");
}
if (!cmdline)
return -ENOMEM;

search_key = argv[1];

Expand All @@ -204,9 +215,10 @@ static int getarg(int argc, char **argv)
if (strlen(search_key) == 0)
usage(GETARG, EXIT_FAILURE, "search key undefined");

args = cmdline;
do {
char *key = NULL, *value = NULL;
cmdline = next_arg(cmdline, &key, &value);
args = next_arg(args, &key, &value);
if (strcmp(key, search_key) == 0) {
if (value) {
end_value = value;
Expand All @@ -216,7 +228,7 @@ static int getarg(int argc, char **argv)
bool_value = true;
}
}
} while (cmdline[0]);
} while (args[0]);

if (search_value) {
if (end_value && strcmp(end_value, search_value) == 0) {
Expand All @@ -243,17 +255,20 @@ static int getargs(int argc, char **argv)
char *search_key;
char *search_value;
bool found_value = false;
char *cmdline = NULL;
_cleanup_free_ char *cmdline = NULL;
char *args = NULL;

if (argc != 2) {
usage(GETARGS, EXIT_FAILURE, "Number of arguments invalid");
}

char *p = getenv("CMDLINE");
if (p == NULL) {
usage(GETARGS, EXIT_FAILURE, "CMDLINE env not set");
}
cmdline = strdup(p);

if (argc != 2) {
usage(GETARGS, EXIT_FAILURE, "Number of arguments invalid");
}
if (!cmdline)
return -ENOMEM;

search_key = argv[1];

Expand All @@ -268,9 +283,10 @@ static int getargs(int argc, char **argv)
if (strlen(search_key) == 0)
usage(GETARGS, EXIT_FAILURE, "search key undefined");

args = cmdline;
do {
char *key = NULL, *value = NULL;
cmdline = next_arg(cmdline, &key, &value);
args = next_arg(args, &key, &value);
if (strcmp(key, search_key) == 0) {
if (search_value) {
if (strcmp(value, search_value) == 0) {
Expand All @@ -286,7 +302,7 @@ static int getargs(int argc, char **argv)
found_value = true;
}
}
} while (cmdline[0]);
} while (args[0]);
return found_value ? EXIT_SUCCESS : EXIT_FAILURE;
}

Expand Down

0 comments on commit 217bcfd

Please sign in to comment.