]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
image-policy: add support for restricting to specific filesystems
authorLuca Boccassi <luca.boccassi@gmail.com>
Wed, 3 Dec 2025 16:48:01 +0000 (16:48 +0000)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 19 Dec 2025 09:17:41 +0000 (09:17 +0000)
man/systemd.image-policy.xml
src/analyze/analyze-image-policy.c
src/shared/image-policy.c
src/shared/image-policy.h
src/test/test-image-policy.c

index 6d91669ef1b90c4d2c99290bf441578bdd798de2..3732d6e1ad6ee596718cc644848c9bf02060b27a 100644 (file)
     <para>In systemd, whenever a disk image (DDI) implementing the <ulink
     url="https://uapi-group.org/specifications/specs/discoverable_partitions_specification">UAPI.2
     Discoverable Partitions Specification</ulink> is activated, a policy may be specified controlling which
-    partitions to mount and what kind of cryptographic protection to require. Such a disk image dissection
-    policy is a string that contains per-partition-type rules, separated by colons
-    (<literal>:</literal>). The individual rules consist of a partition identifier, an equal sign
-    (<literal>=</literal>), and one or more flags which may be set per partition. If multiple flags are
-    specified per partition they are separated by a plus sign (<literal>+</literal>).</para>
+    partitions to mount and what kind of cryptographic protection to require, and which type of filesystem
+    is allowed. Such a disk image dissection policy is a string that contains per-partition-type rules,
+    separated by colons (<literal>:</literal>). The individual rules consist of a partition identifier, an
+    equal sign (<literal>=</literal>), and one or more flags which may be set per partition. If multiple
+    flags are specified per partition they are separated by a plus sign (<literal>+</literal>).</para>
 
     <para>The partition identifiers currently defined are: <option>root</option>, <option>usr</option>,
     <option>home</option>, <option>srv</option>, <option>esp</option>, <option>xbootldr</option>,
       image.</para></listitem>
     </itemizedlist>
 
+    <para>The following filesystem policy flags are defined that dictate which filesystem types are allowed
+    for which partition:</para>
+
+    <table>
+      <title>
+        Filesystems types supported by the policy
+      </title>
+
+      <tgroup cols='1'>
+        <thead>
+          <row>
+            <entry>Filesystem flag</entry>
+          </row>
+        </thead>
+        <tbody>
+          <row>
+            <entry><literal>btrfs</literal></entry>
+          </row>
+          <row>
+            <entry><literal>erofs</literal></entry>
+          </row>
+          <row>
+            <entry><literal>ext4</literal></entry>
+          </row>
+          <row>
+            <entry><literal>f2fs</literal></entry>
+          </row>
+          <row>
+            <entry><literal>squashfs</literal></entry>
+          </row>
+          <row>
+            <entry><literal>vfat</literal></entry>
+          </row>
+          <row>
+            <entry><literal>xfs</literal></entry>
+          </row>
+        </tbody>
+      </tgroup>
+    </table>
+
     <para>By setting a combination of the flags above, alternatives can be declared. For example the
     combination <literal>unused+absent</literal> means: the partition may exist (in which case it shall not
     be used) or may be absent. The combination of
     does not have to be, and ignores swap partitions, and uses all other partitions if they are available, possibly with encryption.</para>
 
     <programlisting>root=unprotected+encrypted:swap=absent+unused:=unprotected+encrypted+absent</programlisting>
+
+    <para>The following image policy string dictates a single root partition that can only be erofs or squashfs,
+    and ignores swap partitions, and uses all other partitions if they are available, possibly with encryption.</para>
+
+    <programlisting>root=erofs+squashfs:swap=absent+unused:=unprotected+encrypted+absent</programlisting>
   </refsect1>
 
   <refsect1>
index aa7f7445557af66707426f198fd027cf7f17d07c..65f54505979f8a5d5aac97d2335b7a448adbf9ab 100644 (file)
@@ -9,7 +9,7 @@
 #include "string-util.h"
 
 static int table_add_designator_line(Table *table, PartitionDesignator d, PartitionPolicyFlags f) {
-        _cleanup_free_ char *q = NULL;
+        _cleanup_free_ char *q = NULL, *t = NULL;
         const char *color;
         int r;
 
@@ -19,6 +19,9 @@ static int table_add_designator_line(Table *table, PartitionDesignator d, Partit
         if (partition_policy_flags_to_string(f & _PARTITION_POLICY_USE_MASK, /* simplify= */ true, &q) < 0)
                 return log_oom();
 
+        if (partition_policy_flags_to_string(f & _PARTITION_POLICY_FSTYPE_MASK, /* simplify= */ true, &t) < 0)
+                return log_oom();
+
         color = (f & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_IGNORE ? ansi_grey() :
                 ((f & (PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT)) ==
                    (PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT)) ? ansi_highlight_yellow() :
@@ -72,6 +75,11 @@ static int table_add_designator_line(Table *table, PartitionDesignator d, Partit
         if (r < 0)
                 return table_log_add_error(r);
 
+        r = table_add_many(table,
+                           TABLE_STRING, isempty(t) ? "-" : t);
+        if (r < 0)
+                return table_log_add_error(r);
+
         return 0;
 }
 
@@ -128,7 +136,7 @@ int verb_image_policy(int argc, char *argv[], void *userdata) {
                                ansi_highlight(), as_string_simplified, ansi_normal(),
                                ansi_grey(), as_string, ansi_normal());
 
-                table = table_new("partition", "mode", "read-only", "growfs");
+                table = table_new("partition", "mode", "read-only", "growfs", "fstype");
                 if (!table)
                         return log_oom();
 
index e917b03b06611fcfc7e0644ec11c5d5d402177fd..44c807f6cbb18a352b2a246bf406a4290e4fc08c 100644 (file)
@@ -207,6 +207,20 @@ static PartitionPolicyFlags policy_flag_from_string_one(const char *s) {
                 return PARTITION_POLICY_GROWFS_ON;
         if (streq(s, "growfs-off"))
                 return PARTITION_POLICY_GROWFS_OFF;
+        if (streq(s, "btrfs"))
+                return PARTITION_POLICY_BTRFS;
+        if (streq(s, "erofs"))
+                return PARTITION_POLICY_EROFS;
+        if (streq(s, "ext4"))
+                return PARTITION_POLICY_EXT4;
+        if (streq(s, "f2fs"))
+                return PARTITION_POLICY_F2FS;
+        if (streq(s, "squashfs"))
+                return PARTITION_POLICY_SQUASHFS;
+        if (streq(s, "vfat"))
+                return PARTITION_POLICY_VFAT;
+        if (streq(s, "xfs"))
+                return PARTITION_POLICY_XFS;
 
         return _PARTITION_POLICY_FLAGS_INVALID;
 }
@@ -389,7 +403,7 @@ int image_policy_from_string(const char *s, bool graceful, ImagePolicy **ret) {
 
 int partition_policy_flags_to_string(PartitionPolicyFlags flags, bool simplify, char **ret) {
         _cleanup_free_ char *buf = NULL;
-        const char *l[CONST_LOG2U(_PARTITION_POLICY_MASK + 1) + 1]; /* one string per known flag at most */
+        const char *l[CONST_LOG2U(_PARTITION_POLICY_MASK + _PARTITION_POLICY_FSTYPE_MASK + 1) + 1]; /* one string per known flag at most */
         size_t m = 0;
 
         assert(ret);
@@ -449,6 +463,23 @@ int partition_policy_flags_to_string(PartitionPolicyFlags flags, bool simplify,
                         l[m++] = "growfs-on";
         }
 
+        /* These flags must translate to the literal fstype name of each filesystem, as accepted by
+         * `mount -t`. */
+        if (flags & PARTITION_POLICY_BTRFS)
+                l[m++] = "btrfs";
+        if (flags & PARTITION_POLICY_EROFS)
+                l[m++] = "erofs";
+        if (flags & PARTITION_POLICY_EXT4)
+                l[m++] = "ext4";
+        if (flags & PARTITION_POLICY_F2FS)
+                l[m++] = "f2fs";
+        if (flags & PARTITION_POLICY_SQUASHFS)
+                l[m++] = "squashfs";
+        if (flags & PARTITION_POLICY_VFAT)
+                l[m++] = "vfat";
+        if (flags & PARTITION_POLICY_XFS)
+                l[m++] = "xfs";
+
         if (m == 0)
                 buf = strdup("-");
         else {
@@ -461,7 +492,7 @@ int partition_policy_flags_to_string(PartitionPolicyFlags flags, bool simplify,
                 return -ENOMEM;
 
         *ret = TAKE_PTR(buf);
-        return 0;
+        return (int) m;
 }
 
 static bool partition_policy_flags_extended_equal(PartitionPolicyFlags a, PartitionPolicyFlags b) {
index 30d319ed698dd54ca4754913f9da78f7c36da390..8023eb31aebc09f683bd41ad9997e5097fa88121 100644 (file)
@@ -36,6 +36,19 @@ typedef enum PartitionPolicyFlags {
 
         _PARTITION_POLICY_MASK                   = _PARTITION_POLICY_USE_MASK|_PARTITION_POLICY_READ_ONLY_MASK|_PARTITION_POLICY_GROWFS_MASK,
 
+        /* Policies can impose filesystem type requirements on images. These flags translate to the literal
+         * fstype name of each filesystem. */
+        PARTITION_POLICY_BTRFS                   = 1 << 11,
+        PARTITION_POLICY_EROFS                   = 1 << 12,
+        PARTITION_POLICY_EXT4                    = 1 << 13,
+        PARTITION_POLICY_F2FS                    = 1 << 14,
+        PARTITION_POLICY_SQUASHFS                = 1 << 15,
+        PARTITION_POLICY_VFAT                    = 1 << 16,
+        PARTITION_POLICY_XFS                     = 1 << 17,
+        _PARTITION_POLICY_FSTYPE_MASK            = PARTITION_POLICY_BTRFS|PARTITION_POLICY_EROFS|PARTITION_POLICY_EXT4|
+                                                   PARTITION_POLICY_F2FS|PARTITION_POLICY_SQUASHFS|
+                                                   PARTITION_POLICY_VFAT|PARTITION_POLICY_XFS,
+
         _PARTITION_POLICY_FLAGS_INVALID          = -EINVAL,
         _PARTITION_POLICY_FLAGS_ERRNO_MAX        = -ERRNO_MAX, /* Ensure the whole errno range fits into this enum */
 } PartitionPolicyFlags;
index 512df19078afe367fe15c94838a208789d8431f9..01c0417900f28be9afde8f16ca762233643c388d 100644 (file)
@@ -92,6 +92,10 @@ TEST_RET(test_image_policy_to_string) {
         test_policy_string("swap=open:root=signed+read-only-on+growfs-off:=absent");
         test_policy_string("=-");
         test_policy_string("=");
+        test_policy_string("root=ext4+squashfs+verity");
+        test_policy_string("usr=encrypted+erofs+read-only-off");
+        test_policy_string("home=unprotected+btrfs");
+        test_policy_string("=vfat+erofs");
 
         test_policy_equiv("", image_policy_equiv_ignore);
         test_policy_equiv("-", image_policy_equiv_ignore);