Blob Blame History Raw
From ee9b9b1241a427732781173caf9db611757c5152 Mon Sep 17 00:00:00 2001
From: Daniel Molkentin <dmolkentin@suse.com>
Date: Thu, 1 Oct 2020 17:12:26 +0200
Subject: [PATCH] dracut-install: fix edge-case regression with weak modules

This was introduced with 6dafdda4a6bdb8721133e4267553c5d86564f9e8, but
is actually caused by the fact that modules that have already been
installed cause dracut_install() to return without adding the module
to the hashmap. This can happen if an earlier-run dracut module chose
to install the same module. Now modprobe statements like:

softdep usb_storage post: uas
softdep uas pre: usb_storage

(which look weird, but are perfectly valid), cause
dracut_install() to enter an infinite recursion if and only if
at least one of the files has previously been installed by another
module.

Fix this by also adding already installed modules to the hashmap.
---
 install/dracut-install.c | 176 +++++++++++++++++++++++------------------------
 1 file changed, 88 insertions(+), 88 deletions(-)

diff --git a/install/dracut-install.c b/install/dracut-install.c
index ea0668b8..97c75dbd 100644
--- a/install/dracut-install.c
+++ b/install/dracut-install.c
@@ -810,123 +810,123 @@ static int dracut_install(const char *orig_src, const char *orig_dst, bool isdir
                         log_debug("'%s' already exists", fulldstpath);
 
                 /* dst does already exist */
-                return ret;
-        }
+        } else {
 
-        /* check destination directory */
-        fulldstdir = strdup(fulldstpath);
-        if (!fulldstdir) {
-                log_error("Out of memory!");
-                return 1;
-        }
-        fulldstdir[dir_len(fulldstdir)] = '\0';
+                /* check destination directory */
+                fulldstdir = strdup(fulldstpath);
+                if (!fulldstdir) {
+                        log_error("Out of memory!");
+                        return 1;
+                }
+                fulldstdir[dir_len(fulldstdir)] = '\0';
 
-        ret = stat(fulldstdir, &db);
+                ret = stat(fulldstdir, &db);
 
-        if (ret < 0) {
-                _cleanup_free_ char *dname = NULL;
+                if (ret < 0) {
+                        _cleanup_free_ char *dname = NULL;
 
-                if (errno != ENOENT) {
-                        log_error("ERROR: stat '%s': %m", fulldstdir);
-                        return 1;
-                }
-                /* create destination directory */
-                log_debug("dest dir '%s' does not exist", fulldstdir);
-                dname = strdup(dst);
-                if (!dname)
-                        return 1;
+                        if (errno != ENOENT) {
+                                log_error("ERROR: stat '%s': %m", fulldstdir);
+                                return 1;
+                        }
+                        /* create destination directory */
+                        log_debug("dest dir '%s' does not exist", fulldstdir);
+                        dname = strdup(dst);
+                        if (!dname)
+                                return 1;
 
-                dname[dir_len(dname)] = '\0';
-                ret = dracut_install(dname, dname, true, false, true);
+                        dname[dir_len(dname)] = '\0';
+                        ret = dracut_install(dname, dname, true, false, true);
 
-                if (ret != 0) {
-                        log_error("ERROR: failed to create directory '%s'", fulldstdir);
-                        return 1;
+                        if (ret != 0) {
+                                log_error("ERROR: failed to create directory '%s'", fulldstdir);
+                                return 1;
+                        }
                 }
-        }
 
-        if (src_isdir) {
-                if (dst_exists) {
-                        if (S_ISDIR(sb.st_mode)) {
-                                log_debug("dest dir '%s' already exists", fulldstpath);
-                                return 0;
+                if (src_isdir) {
+                        if (dst_exists) {
+                                if (S_ISDIR(sb.st_mode)) {
+                                        log_debug("dest dir '%s' already exists", fulldstpath);
+                                        return 0;
+                                }
+                                log_error("dest dir '%s' already exists but is not a directory", fulldstpath);
+                                return 1;
                         }
-                        log_error("dest dir '%s' already exists but is not a directory", fulldstpath);
-                        return 1;
-                }
 
-                log_info("mkdir '%s'", fulldstpath);
-                ret = dracut_mkdir(fulldstpath);
-                if (ret == 0) {
-                        i = strdup(dst);
-                        if (!i)
-                                return -ENOMEM;
+                        log_info("mkdir '%s'", fulldstpath);
+                        ret = dracut_mkdir(fulldstpath);
+                        if (ret == 0) {
+                                i = strdup(dst);
+                                if (!i)
+                                        return -ENOMEM;
 
-                        hashmap_put(items, i, i);
+                                hashmap_put(items, i, i);
+                        }
+                        return ret;
                 }
-                return ret;
-        }
 
-        /* ready to install src */
+                /* ready to install src */
 
-        if (src_islink) {
-                _cleanup_free_ char *abspath = NULL;
+                if (src_islink) {
+                        _cleanup_free_ char *abspath = NULL;
 
-                abspath = get_real_file(src, false);
+                        abspath = get_real_file(src, false);
 
-                if (abspath == NULL)
-                        return 1;
+                        if (abspath == NULL)
+                                return 1;
 
-                if (dracut_install(abspath, abspath, false, resolvedeps, hashdst)) {
-                        log_debug("'%s' install error", abspath);
-                        return 1;
-                }
+                        if (dracut_install(abspath, abspath, false, resolvedeps, hashdst)) {
+                                log_debug("'%s' install error", abspath);
+                                return 1;
+                        }
 
-                if (lstat(abspath, &sb) != 0) {
-                        log_debug("lstat '%s': %m", abspath);
-                        return 1;
-                }
+                        if (lstat(abspath, &sb) != 0) {
+                                log_debug("lstat '%s': %m", abspath);
+                                return 1;
+                        }
 
-                if (lstat(fulldstpath, &sb) != 0) {
-                        _cleanup_free_ char *absdestpath = NULL;
+                        if (lstat(fulldstpath, &sb) != 0) {
+                                _cleanup_free_ char *absdestpath = NULL;
 
-                        ret = asprintf(&absdestpath, "%s/%s", destrootdir, (abspath[0]=='/' ? (abspath+1) : abspath) + sysrootdirlen);
-                        if (ret < 0) {
-                                log_error("Out of memory!");
-                                exit(EXIT_FAILURE);
+                                ret = asprintf(&absdestpath, "%s/%s", destrootdir, (abspath[0]=='/' ? (abspath+1) : abspath) + sysrootdirlen);
+                                if (ret < 0) {
+                                        log_error("Out of memory!");
+                                        exit(EXIT_FAILURE);
+                                }
+
+                                ln_r(absdestpath, fulldstpath);
                         }
 
-                        ln_r(absdestpath, fulldstpath);
-                }
+                        if (arg_hmac) {
+                                /* copy .hmac files also */
+                                hmac_install(src, dst, NULL);
+                        }
 
-                if (arg_hmac) {
-                        /* copy .hmac files also */
-                        hmac_install(src, dst, NULL);
+                        return 0;
                 }
 
-                return 0;
-        }
-
-        if (src_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
-                if (resolvedeps)
-                        ret += resolve_deps(fullsrcpath + sysrootdirlen);
-                if (arg_hmac) {
-                        /* copy .hmac files also */
-                        hmac_install(src, dst, NULL);
+                if (src_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+                        if (resolvedeps)
+                                ret += resolve_deps(fullsrcpath + sysrootdirlen);
+                        if (arg_hmac) {
+                                /* copy .hmac files also */
+                                hmac_install(src, dst, NULL);
+                        }
                 }
-        }
 
-        log_debug("dracut_install ret = %d", ret);
+                log_debug("dracut_install ret = %d", ret);
 
-        if (arg_hostonly && !arg_module)
-                mark_hostonly(dst);
+                if (arg_hostonly && !arg_module)
+                        mark_hostonly(dst);
 
-        if (isdir) {
-                log_info("mkdir '%s'", fulldstpath);
-                ret += dracut_mkdir(fulldstpath);
-        } else {
-                log_info("cp '%s' '%s'", fullsrcpath, fulldstpath);
-                ret += cp(fullsrcpath, fulldstpath);
+                if (isdir) {
+                        log_info("mkdir '%s'", fulldstpath);
+                        ret += dracut_mkdir(fulldstpath);
+                } else {
+                        log_info("cp '%s' '%s'", fullsrcpath, fulldstpath);
+                        ret += cp(fullsrcpath, fulldstpath);
+                }
         }
 
         if (ret == 0) {