all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* [bug#68162] [PATCH] initrd: Parse kernel command line and pass module parameters
@ 2023-12-31  4:14 nathan via Guix-patches via
  0 siblings, 0 replies; only message in thread
From: nathan via Guix-patches via @ 2023-12-31  4:14 UTC (permalink / raw)
  To: 68162

[-- Attachment #1: Type: text/plain, Size: 747 bytes --]

GUIX's initrd code ignores the kernel command line and always passes no parameters to the modules it loads.
This fixes it with command line parsing code that is accurate to what modprobe does.
The user's module options, like somemodule.param=val, are properly passed now.
It also allows the modprobe.blacklist option to optionally be quoted and normalizes the module names given in the blacklist.
modprobe.blacklist="module1,mod-ule2" -> '("module1" "mod_ule2")

I tested passing module options with the command line in a VM and on my real system.
Tested blacklist code in a VM.

I've also attached my code I used to test the commandline parsing function manually.

fix bug#55907
https://lists.gnu.org/archive/html/bug-guix/2022-06/msg00157.html


[-- Attachment #2: 0001-linux-modules-Allow-parameters-to-be-passed-to-kerne.patch --]
[-- Type: text/x-patch, Size: 3130 bytes --]

From 626930cbad11e7f5546589fc290b2c95fee97b80 Mon Sep 17 00:00:00 2001
Message-ID: <626930cbad11e7f5546589fc290b2c95fee97b80.1703992381.git.nathan_mail@nborghese.com>
From: nathan <nathan_mail@nborghese.com>
Date: Sat, 30 Dec 2023 22:10:26 -0500
Subject: [PATCH 1/3] linux-modules: Allow parameters to be passed to kernel
 modules

* gnu/build/linux-modules.scm (load-linux-module*): New parameter,
  `get-options', for getting kernel module parameters to give to Linux.

Change-Id: I8c4629a1404270fe641fef02a9fbbaeac4360e65
---
 gnu/build/linux-modules.scm | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/gnu/build/linux-modules.scm b/gnu/build/linux-modules.scm
index 12cb9c4ba6..c4950ea6d2 100644
--- a/gnu/build/linux-modules.scm
+++ b/gnu/build/linux-modules.scm
@@ -332,12 +332,15 @@ (define* (load-linux-module* file
                              #:key
                              (recursive? #t)
                              (lookup-module dot-ko)
-                             (black-list (module-black-list)))
+                             (black-list (module-black-list))
+                             (get-options (const "")))
   "Load Linux module from FILE, the name of a '.ko[.gz|.xz]' file; return true
 on success, false otherwise.  When RECURSIVE? is true, load its dependencies
 first (à la 'modprobe'.)  The actual files containing modules depended on are
 obtained by calling LOOKUP-MODULE with the module name.  Modules whose name
-appears in BLACK-LIST are not loaded."
+appears in BLACK-LIST are not loaded. GET-OPTIONS is a procedure that takes a
+normalized module name string input and returns a string containing the complete
+parameters to pass to the module. See init_module(2) for the parameters format."
   (define (black-listed? module)
     (let ((result (member module black-list)))
       (when result
@@ -350,20 +353,23 @@ (define* (load-linux-module* file
     (let ((dependencies (module-dependencies file)))
       (every (cut load-linux-module* <>
                   #:lookup-module lookup-module
-                  #:black-list black-list)
+                  #:black-list black-list
+                  #:get-options get-options)
              (map lookup-module dependencies))))
 
   (and (not (black-listed? (file-name->module-name file)))
        (or (not recursive?)
            (load-dependencies file))
-       (let ((fd #f))
+       (let ((fd #f)
+             (options (get-options (file-name->module-name file))))
          (format (current-module-debugging-port)
-                 "loading Linux module from '~a'...~%" file)
+                 "loading Linux module from '~a' with options '~a'...~%" file
+                 options)
 
          (catch 'system-error
            (lambda ()
              (set! fd (open-fdes file O_RDONLY))
-             (load-linux-module/fd fd)
+             (load-linux-module/fd fd options)
              (close-fdes fd)
              #t)
            (lambda args

base-commit: f24b14767d362a84e6469682b4fe303b50f4b589
-- 
2.41.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-linux-modules-Parse-kernel-command-line-and-pass-mod.patch --]
[-- Type: text/x-patch, Size: 6709 bytes --]

From 903b2d5bcb1fa28121ffd46e70f6503559c0ec95 Mon Sep 17 00:00:00 2001
Message-ID: <903b2d5bcb1fa28121ffd46e70f6503559c0ec95.1703992381.git.nathan_mail@nborghese.com>
In-Reply-To: <626930cbad11e7f5546589fc290b2c95fee97b80.1703992381.git.nathan_mail@nborghese.com>
References: <626930cbad11e7f5546589fc290b2c95fee97b80.1703992381.git.nathan_mail@nborghese.com>
From: nathan <nathan_mail@nborghese.com>
Date: Sat, 30 Dec 2023 22:11:35 -0500
Subject: [PATCH 2/3] linux-modules: Parse kernel command line and pass module
 arguments

* gnu/build/linux-modules.scm
(parse-kernel-cmdline): New procedure.
(load-linux-modules-from-directory): Use parse-kernel-cmdline to parse command
line and supply options to load-linux-module*.

Change-Id: I11a181670d0da5ea08965a80c396358e50bf5048
---
 gnu/build/linux-modules.scm | 98 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)

diff --git a/gnu/build/linux-modules.scm b/gnu/build/linux-modules.scm
index c4950ea6d2..a54616b2d4 100644
--- a/gnu/build/linux-modules.scm
+++ b/gnu/build/linux-modules.scm
@@ -305,6 +305,93 @@ (define (modules-loaded)
       (((modules . _) ...)
        modules))))
 
+(define (parse-kernel-cmdline base)
+  "Input is the entire kernel command line, which is a space-delimited list of
+modulename.parameter=value parts.  The exact allowed syntax for the string is
+based on the kmod_config_parse_kcmdline function from modprobe.  Output is a
+vhash where the key is the module name as a string and the value is a list of
+strings in the form param=val (maybe with quotes in val).
+`normalize-module-name' is applied to the module names.
+
+Duplicate parameters are not removed.  The hyphen and underscore normalization
+in parameter names is not applied.  Empty module names are allowed."
+  (define (get-quoted start)
+    "It's similar to string-tokenize, but quoting is supported.  Two values
+are returned. First is the chunk of characters, second is the unused remainder
+of the string.  returns (values \"\" \"\") if the input string is just
+whitespace or there's an unterminated quote"
+    ;; strip whitespace at the start
+    (let ((start (substring
+                  start
+                  (or
+                   (string-skip start char-set:whitespace)
+                   (string-length start)))))
+      (let lp ((s start) (quoted? #f))
+        (if quoted?
+            (if (string-null? s)
+                (values "" "")
+                (lp (substring s 1) (not (eqv? (string-ref s 0) #\"))))
+            (if (or (string-null? s) (char-whitespace? (string-ref s 0)))
+                (values
+                 (substring start 0 (- (string-length start) (string-length s)))
+                 s)
+                (lp (substring s 1) (eqv? (string-ref s 0) #\")))))))
+  (let lp ((s base) (table vlist-null))
+    (call-with-values (lambda () (get-quoted s))
+      (lambda (strblock rest)
+        (if (string-null? strblock)
+            table
+            ;; get parameter name. it is mandatory.
+            (let ((dotpos (string-index strblock #\.)))
+              (if dotpos
+                  (let* ((equalpos (string-index strblock #\= dotpos))
+                         ;; modprobe allows a string like:
+                         ;; "modulename.param=val"
+                         ;; and then it converts it to
+                         ;; modulename.param="val"
+                         ;; This is the only case where a quote is
+                         ;; allowed outside of the value part.
+                         (is-bad-quoting (eqv? (string-ref strblock 0) #\"))
+                         (modulename
+                          (substring strblock (if is-bad-quoting 1 0) dotpos))
+                         (parampart
+                          (substring
+                           strblock
+                           (1+ dotpos)
+                           (or equalpos (string-length strblock)))))
+                    ;; whitespace is only allowed in value
+                    ;; no quotes allows in param segment
+                    ;; param cant have dot
+                    ;; module cant have equals
+                    (if (or
+                         (string-any (char-set-union
+                                      char-set:whitespace
+                                      (char-set #\" #\.))
+                                     parampart)
+                         (string-any (char-set-union
+                                      char-set:whitespace
+                                      (char-set #\=))
+                                     modulename))
+                        (lp rest table) ;; ignore and recur
+                        ;; add it to the table
+                        (let ((modulename (normalize-module-name modulename)))
+                          (lp rest
+                              (let ((oldval (vhash-assoc modulename table)))
+                                (vhash-cons
+                                 modulename
+                                 (cons
+                                  (if is-bad-quoting
+                                      (string-append
+                                       (substring strblock
+                                                  (1+ dotpos)
+                                                  (1+ equalpos))
+                                       "\"" (substring strblock (1+ equalpos)))
+                                      (substring strblock (1+ dotpos)))
+                                  (if oldval (cdr oldval) '()))
+                                 (vhash-delete modulename table)))))))
+                  (lp rest table))) ;; ignore and recur
+            )))))
+
 (define (module-black-list)
   "Return the black list of modules that must not be loaded.  This black list
 is specified using 'modprobe.blacklist=MODULE1,MODULE2,...' on the kernel
@@ -387,10 +474,19 @@ (define (load-linux-modules-from-directory modules directory)
 needed."
   (define module-name->file-name
     (module-name-lookup directory))
+  (define options-list
+    (parse-kernel-cmdline
+     (call-with-input-file "/proc/cmdline" get-string-all)))
+  (define (get-options modulename)
+    (let ((pair (vhash-assoc modulename options-list)))
+      (if pair
+          (string-join (cdr pair) " ")
+          "")))
 
   (for-each (lambda (module)
               (load-linux-module* (module-name->file-name module)
-                                  #:lookup-module module-name->file-name))
+                                  #:lookup-module module-name->file-name
+                                  #:get-options get-options))
             modules))
 
 \f
-- 
2.41.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-linux-modules-Rewrite-module-black-list-with-parse-k.patch --]
[-- Type: text/x-patch, Size: 2684 bytes --]

From 0cd4f6fb19c96a6be4a0d0851e1cf6dfd7046a27 Mon Sep 17 00:00:00 2001
Message-ID: <0cd4f6fb19c96a6be4a0d0851e1cf6dfd7046a27.1703992381.git.nathan_mail@nborghese.com>
In-Reply-To: <626930cbad11e7f5546589fc290b2c95fee97b80.1703992381.git.nathan_mail@nborghese.com>
References: <626930cbad11e7f5546589fc290b2c95fee97b80.1703992381.git.nathan_mail@nborghese.com>
From: nathan <nathan_mail@nborghese.com>
Date: Sat, 30 Dec 2023 22:12:19 -0500
Subject: [PATCH 3/3] linux-modules: Rewrite module-black-list with
 parse-kernel-cmdline

* gnu/build/linux-modules.scm
(module-black-list): Use parse-kernel-cmdline. Strip quotes from module names.
Normalize module names so they can be properly compared with strings from
file-name->module-name.

Change-Id: I318006f98844593863246fc89ed1703767794702
---
 gnu/build/linux-modules.scm | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/gnu/build/linux-modules.scm b/gnu/build/linux-modules.scm
index a54616b2d4..cbce3394e2 100644
--- a/gnu/build/linux-modules.scm
+++ b/gnu/build/linux-modules.scm
@@ -397,18 +397,25 @@ (define (module-black-list)
 is specified using 'modprobe.blacklist=MODULE1,MODULE2,...' on the kernel
 command line; it is honored by libkmod for users that pass
 'KMOD_PROBE_APPLY_BLACKLIST', which includes 'modprobe --use-blacklist' and
-udev."
-  (define parameter
-    "modprobe.blacklist=")
-
-  (let ((command (call-with-input-file "/proc/cmdline"
-                   get-string-all)))
-    (append-map (lambda (arg)
-                  (if (string-prefix? parameter arg)
-                      (string-tokenize (string-drop arg (string-length parameter))
-                                       %not-comma)
-                      '()))
-                (string-tokenize command))))
+udev.  The names in the returned list are normalized with `normalize-module-name'."
+  (define target-parameter "blacklist=")
+
+  (let* ((cmdline (parse-kernel-cmdline (call-with-input-file "/proc/cmdline"
+                                          get-string-all)))
+         (modprobe-pair (vhash-assoc "modprobe" cmdline)))
+    (if modprobe-pair
+        (map normalize-module-name
+         (append-map
+          (lambda (param)
+            (if (string-prefix? target-parameter param)
+                (string-tokenize
+                 (string-delete
+                  #\"
+                  (string-drop param (string-length target-parameter)))
+                 %not-comma)
+                '()))
+          (cdr modprobe-pair)))
+        '())))
 
 (define (module-loaded? module)
   "Return #t if MODULE is already loaded.  MODULE must be a Linux module name,
-- 
2.41.0


[-- Attachment #5: manual testing code --]
[-- Type: application/octet-stream, Size: 1980 bytes --]

;; test kernel command line parsing

(use-modules (ice-9 vlist))
(use-modules (rnrs base) (srfi srfi-1) (rnrs sorting))

;; test normal
;; test quoted
;; test strange quoted
;; test invalid quote in module name
;; test invalid space in parameter
;; test invalid space in module name
;; test invalid dot in parameter name
;; test newline support and multiple quotes in a single value
;; test missing value, but still using quotes. (this is invalid)
;; test empty value (with qutes)
;; test no-value option
;; test normalized module name
(define cmdline
  "
mod.test1=1
mod.test2=\"a b c\"
\"mod.test3=a b c\"
\"invalid.p\"=3
\"invalid.d d=5\"
\"inval id.de=5\"
\"invalid.d.e=5\"
\"inval=id.d.e=5\"
\"mod2.test4=abc
def\"\"ghi\"jkl\"n
nop\"q

\"invalid.param\"

\"mod.test4=\"

gnu.repl

znormalize-me.test=1"
  )

(define parse-kernel-cmdline (@@ (gnu build linux-modules) parse-kernel-cmdline))

(define myalist (vlist->list (parse-kernel-cmdline cmdline)))
;; nothing for the "invalid" module should pass
(assert (not (any (lambda (a) (string-prefix? "inv" (car a))) myalist)))

(let ((parsedargs
       ;; sort the alist entries by their keys
       (list-sort
        (lambda (a b) (string< (car a) (car b)))
        ;; sort the values of each alist entry
        (map
         (lambda (b)
           (cons (car b) (list-sort string< (cdr b))))
         myalist))))
  ;;((@ (ice-9 pretty-print) pretty-print) parsedargs)
  (assert
   (equal?
    parsedargs
    '(
      ("gnu" "repl")
      ("mod" "test1=1" "test2=\"a b c\"" "test3=\"a b c\"" "test4=\"\"")
      ("mod2"
       "test4=\"abc
def\"\"ghi\"jkl\"n
nop\"q")
      ("znormalize_me" "test=1")
      ))))

;; fail because unterminated quote
(assert (equal?
         (vlist->list (parse-kernel-cmdline "aaa.bbb=\"ccc"))
         '()))

;; test proper parsing when end of string is reached
(assert (equal?
         (vlist->list (parse-kernel-cmdline "aaa.bbb=ccc"))
         '(("aaa" "bbb=ccc"))))

(display "passed\n")

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2023-12-31  4:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-31  4:14 [bug#68162] [PATCH] initrd: Parse kernel command line and pass module parameters nathan via Guix-patches via

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.