summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJinfeng Wang <jinfeng.wang.cn@windriver.com>2025-03-19 11:14:11 +0800
committerArmin Kuster <akuster808@gmail.com>2025-03-23 15:29:29 -0400
commitf23c8d7362aa8b23a18e38ccfb22b6ed666dab07 (patch)
tree90a4537faaab4fb03cbfb77acaf189c3defa6536
parentcd1aa14313b5ade98613b7d349f320fd44e78bc9 (diff)
downloadmeta-openembedded-f23c8d7362aa8b23a18e38ccfb22b6ed666dab07.tar.gz
netplan: Fix CVE-2022-4968
Reference: https://nvd.nist.gov/vuln/detail/CVE-2022-4968 Upstream-patch: https://github.com/canonical/netplan/commit/4c39b75b5c6ae7d976bda6da68da60d9a7f085ee Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan/CVE-2022-4968.patch452
-rw-r--r--meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan_1.0.bb1
2 files changed, 453 insertions, 0 deletions
diff --git a/meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan/CVE-2022-4968.patch b/meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan/CVE-2022-4968.patch
new file mode 100644
index 0000000000..a7a3c28f3f
--- /dev/null
+++ b/meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan/CVE-2022-4968.patch
@@ -0,0 +1,452 @@
1From 9d9a67b00b18708ce190b806686065a6c7b73527 Mon Sep 17 00:00:00 2001
2From: Danilo Egea Gondolfo <danilogondolfo@gmail.com>
3Date: Wed, 22 May 2024 15:44:16 +0100
4Subject: [PATCH] libnetplan: use more restrictive file permissions
5
6A new util.c:_netplan_g_string_free_to_file_with_permissions() was added
7and accepts the owner, group and file mode as arguments. When these
8properties can't be set, when the generator is called by a non-root user
9for example, it will not hard-fail. This function is called by unit
10tests where we can't set the owner to a privileged account for example.
11
12When generating backend files, use more restrictive permissions:
13
14networkd related files will be owned by root:systemd-network and have
15mode 0640.
16
17service unit files will be owned by root:root and have mode 0640.
18udevd files will be owned by root:root with mode 0640.
19
20wpa_supplicant and Network Manager files will continue with the existing
21permissions.
22
23Autopkgtests will check if the permissions are set as expected when
24calling the generator.
25
26CVE: CVE-2022-4968
27
28Upstream-Status: Backport [https://github.com/canonical/netplan/commit/4c39b75b5c6ae7d976bda6da68da60d9a7f085ee]
29
30Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com>
31---
32 src/networkd.c | 36 +++------------
33 src/networkd.h | 2 +
34 src/nm.c | 4 +-
35 src/openvswitch.c | 2 +-
36 src/sriov.c | 4 +-
37 src/util-internal.h | 3 ++
38 src/util.c | 46 +++++++++++++++++++
39 tests/generator/test_auth.py | 2 +-
40 tests/generator/test_wifis.py | 2 +-
41 tests/integration/base.py | 85 +++++++++++++++++++++++++++++++++++
42 10 files changed, 150 insertions(+), 36 deletions(-)
43
44diff --git a/src/networkd.c b/src/networkd.c
45index 25121c4..a051c6f 100644
46--- a/src/networkd.c
47+++ b/src/networkd.c
48@@ -221,7 +221,6 @@ STATIC void
49 write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char* path)
50 {
51 GString* s = NULL;
52- mode_t orig_umask;
53
54 /* Don't write .link files for virtual devices; they use .netdev instead.
55 * Don't write .link files for MODEM devices, as they aren't supported by networkd.
56@@ -293,9 +292,7 @@ write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char
57 g_string_append_printf(s, "LargeReceiveOffload=%s\n",
58 (def->large_receive_offload ? "true" : "false"));
59
60- orig_umask = umask(022);
61- _netplan_g_string_free_to_file(s, rootdir, path, ".link");
62- umask(orig_umask);
63+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, ".link", "root", "root", 0640);
64 }
65
66 STATIC gboolean
67@@ -313,7 +310,7 @@ write_regdom(const NetplanNetDefinition* def, const char* rootdir, GError** erro
68 g_string_append(s, "\n[Service]\nType=oneshot\n");
69 g_string_append_printf(s, "ExecStart="SBINDIR"/iw reg set %s\n", def->regulatory_domain);
70
71- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
72+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
73 _netplan_safe_mkdir_p_dir(link);
74 if (symlink(path, link) < 0 && errno != EEXIST) {
75 // LCOV_EXCL_START
76@@ -493,7 +490,6 @@ STATIC void
77 write_netdev_file(const NetplanNetDefinition* def, const char* rootdir, const char* path)
78 {
79 GString* s = NULL;
80- mode_t orig_umask;
81
82 g_assert(def->type >= NETPLAN_DEF_TYPE_VIRTUAL);
83
84@@ -589,11 +585,7 @@ write_netdev_file(const NetplanNetDefinition* def, const char* rootdir, const ch
85 default: g_assert_not_reached(); // LCOV_EXCL_LINE
86 }
87
88- /* these do not contain secrets and need to be readable by
89- * systemd-networkd - LP: #1736965 */
90- orig_umask = umask(022);
91- _netplan_g_string_free_to_file(s, rootdir, path, ".netdev");
92- umask(orig_umask);
93+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, ".netdev", "root", NETWORKD_GROUP, 0640);
94 }
95
96 STATIC void
97@@ -737,7 +729,6 @@ _netplan_netdef_write_network_file(
98 g_autoptr(GString) network = NULL;
99 g_autoptr(GString) link = NULL;
100 GString* s = NULL;
101- mode_t orig_umask;
102 gboolean is_optional = def->optional;
103
104 SET_OPT_OUT_PTR(has_been_written, FALSE);
105@@ -993,11 +984,7 @@ _netplan_netdef_write_network_file(
106 if (network->len > 0)
107 g_string_append_printf(s, "\n[Network]\n%s", network->str);
108
109- /* these do not contain secrets and need to be readable by
110- * systemd-networkd - LP: #1736965 */
111- orig_umask = umask(022);
112- _netplan_g_string_free_to_file(s, rootdir, path, ".network");
113- umask(orig_umask);
114+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, ".network", "root", NETWORKD_GROUP, 0640);
115 }
116
117 SET_OPT_OUT_PTR(has_been_written, TRUE);
118@@ -1009,7 +996,6 @@ write_rules_file(const NetplanNetDefinition* def, const char* rootdir)
119 {
120 GString* s = NULL;
121 g_autofree char* path = g_strjoin(NULL, "run/udev/rules.d/99-netplan-", def->id, ".rules", NULL);
122- mode_t orig_umask;
123
124 /* do we need to write a .rules file?
125 * It's only required for reliably setting the name of a physical device
126@@ -1043,9 +1029,7 @@ write_rules_file(const NetplanNetDefinition* def, const char* rootdir)
127
128 g_string_append_printf(s, "NAME=\"%s\"\n", def->set_name);
129
130- orig_umask = umask(022);
131- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
132- umask(orig_umask);
133+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
134 }
135
136 STATIC gboolean
137@@ -1194,7 +1178,6 @@ STATIC void
138 write_wpa_unit(const NetplanNetDefinition* def, const char* rootdir)
139 {
140 g_autofree gchar *stdouth = NULL;
141- mode_t orig_umask;
142
143 stdouth = systemd_escape(def->id);
144
145@@ -1213,9 +1196,7 @@ write_wpa_unit(const NetplanNetDefinition* def, const char* rootdir)
146 } else {
147 g_string_append(s, " -Dnl80211,wext\n");
148 }
149- orig_umask = umask(022);
150- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
151- umask(orig_umask);
152+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
153 }
154
155 STATIC gboolean
156@@ -1224,7 +1205,6 @@ write_wpa_conf(const NetplanNetDefinition* def, const char* rootdir, GError** er
157 GHashTableIter iter;
158 GString* s = g_string_new("ctrl_interface=/run/wpa_supplicant\n\n");
159 g_autofree char* path = g_strjoin(NULL, "run/netplan/wpa-", def->id, ".conf", NULL);
160- mode_t orig_umask;
161
162 g_debug("%s: Creating wpa_supplicant configuration file %s", def->id, path);
163 if (def->type == NETPLAN_DEF_TYPE_WIFI) {
164@@ -1313,9 +1293,7 @@ write_wpa_conf(const NetplanNetDefinition* def, const char* rootdir, GError** er
165 }
166
167 /* use tight permissions as this contains secrets */
168- orig_umask = umask(077);
169- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
170- umask(orig_umask);
171+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0600);
172 return TRUE;
173 }
174
175diff --git a/src/networkd.h b/src/networkd.h
176index 2bd0848..36c34b3 100644
177--- a/src/networkd.h
178+++ b/src/networkd.h
179@@ -20,6 +20,8 @@
180 #include "netplan.h"
181 #include <glib.h>
182
183+#define NETWORKD_GROUP "systemd-network"
184+
185 NETPLAN_INTERNAL gboolean
186 _netplan_netdef_write_networkd(
187 const NetplanState* np_state,
188diff --git a/src/nm.c b/src/nm.c
189index 2b850af..8f1bf05 100644
190--- a/src/nm.c
191+++ b/src/nm.c
192@@ -1150,13 +1150,13 @@ netplan_state_finish_nm_write(
193
194 /* write generated NetworkManager drop-in config */
195 if (nm_conf->len > 0)
196- _netplan_g_string_free_to_file(nm_conf, rootdir, "run/NetworkManager/conf.d/netplan.conf", NULL);
197+ _netplan_g_string_free_to_file_with_permissions(nm_conf, rootdir, "run/NetworkManager/conf.d/netplan.conf", NULL, "root", "root", 0640);
198 else
199 g_string_free(nm_conf, TRUE);
200
201 /* write generated udev rules */
202 if (udev_rules->len > 0)
203- _netplan_g_string_free_to_file(udev_rules, rootdir, "run/udev/rules.d/90-netplan.rules", NULL);
204+ _netplan_g_string_free_to_file_with_permissions(udev_rules, rootdir, "run/udev/rules.d/90-netplan.rules", NULL, "root", "root", 0640);
205 else
206 g_string_free(udev_rules, TRUE);
207
208diff --git a/src/openvswitch.c b/src/openvswitch.c
209index 6eb0688..2ab77e7 100644
210--- a/src/openvswitch.c
211+++ b/src/openvswitch.c
212@@ -66,7 +66,7 @@ write_ovs_systemd_unit(const char* id, const GString* cmds, const char* rootdir,
213 g_string_append(s, "StartLimitBurst=0\n");
214 g_string_append(s, cmds->str);
215
216- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
217+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
218
219 _netplan_safe_mkdir_p_dir(link);
220 if (symlink(path, link) < 0 && errno != EEXIST) {
221diff --git a/src/sriov.c b/src/sriov.c
222index 1534c94..213f124 100644
223--- a/src/sriov.c
224+++ b/src/sriov.c
225@@ -54,7 +54,7 @@ write_sriov_rebind_systemd_unit(GHashTable* pfs, const char* rootdir, GError** e
226 g_string_truncate(interfaces, interfaces->len-1); /* cut trailing whitespace */
227 g_string_append_printf(s, "ExecStart=" SBINDIR "/netplan rebind --debug %s\n", interfaces->str);
228
229- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
230+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
231 g_string_free(interfaces, TRUE);
232
233 _netplan_safe_mkdir_p_dir(link);
234@@ -90,7 +90,7 @@ write_sriov_apply_systemd_unit(GHashTable* pfs, const char* rootdir, GError** er
235 g_string_append(s, "\n[Service]\nType=oneshot\n");
236 g_string_append_printf(s, "ExecStart=" SBINDIR "/netplan apply --sriov-only\n");
237
238- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
239+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
240
241 _netplan_safe_mkdir_p_dir(link);
242 if (symlink(path, link) < 0 && errno != EEXIST) {
243diff --git a/src/util-internal.h b/src/util-internal.h
244index 86bd1b7..7454e77 100644
245--- a/src/util-internal.h
246+++ b/src/util-internal.h
247@@ -40,6 +40,9 @@ _netplan_safe_mkdir_p_dir(const char* file_path);
248 NETPLAN_INTERNAL void
249 _netplan_g_string_free_to_file(GString* s, const char* rootdir, const char* path, const char* suffix);
250
251+void
252+_netplan_g_string_free_to_file_with_permissions(GString* s, const char* rootdir, const char* path, const char* suffix, const char* owner, const char* group, mode_t mode);
253+
254 NETPLAN_INTERNAL void
255 _netplan_unlink_glob(const char* rootdir, const char* _glob);
256
257diff --git a/src/util.c b/src/util.c
258index 36eb896..c2f9494 100644
259--- a/src/util.c
260+++ b/src/util.c
261@@ -23,6 +23,9 @@
262 #include <regex.h>
263 #include <string.h>
264 #include <sys/mman.h>
265+#include <sys/types.h>
266+#include <pwd.h>
267+#include <grp.h>
268
269 #include <glib.h>
270 #include <glib/gprintf.h>
271@@ -87,6 +90,49 @@ void _netplan_g_string_free_to_file(GString* s, const char* rootdir, const char*
272 }
273 }
274
275+void _netplan_g_string_free_to_file_with_permissions(GString* s, const char* rootdir, const char* path, const char* suffix, const char* owner, const char* group, mode_t mode)
276+{
277+ g_autofree char* full_path = NULL;
278+ g_autofree char* path_suffix = NULL;
279+ g_autofree char* contents = g_string_free(s, FALSE);
280+ GError* error = NULL;
281+ struct passwd* pw = NULL;
282+ struct group* gr = NULL;
283+ int ret = 0;
284+
285+ path_suffix = g_strjoin(NULL, path, suffix, NULL);
286+ full_path = g_build_path(G_DIR_SEPARATOR_S, rootdir ?: G_DIR_SEPARATOR_S, path_suffix, NULL);
287+ _netplan_safe_mkdir_p_dir(full_path);
288+ if (!g_file_set_contents_full(full_path, contents, -1, G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_ONLY_EXISTING, mode, &error)) {
289+ /* the mkdir() just succeeded, there is no sensible
290+ * method to test this without root privileges, bind mounts, and
291+ * simulating ENOSPC */
292+ // LCOV_EXCL_START
293+ g_fprintf(stderr, "ERROR: cannot create file %s: %s\n", path, error->message);
294+ exit(1);
295+ // LCOV_EXCL_STOP
296+ }
297+
298+ /* Here we take the owner and group names and look up for their IDs in the passwd and group files.
299+ * It's OK to fail to set the owners and mode as this code will be called from unit tests.
300+ * The autopkgtests will check if the owner/group and mode are correctly set.
301+ */
302+ pw = getpwnam(owner);
303+ if (!pw) {
304+ g_debug("Failed to determine the UID of user %s: %s", owner, strerror(errno)); // LCOV_EXCL_LINE
305+ }
306+ gr = getgrnam(group);
307+ if (!gr) {
308+ g_debug("Failed to determine the GID of group %s: %s", group, strerror(errno)); // LCOV_EXCL_LINE
309+ }
310+ if (pw && gr) {
311+ ret = chown(full_path, pw->pw_uid, gr->gr_gid);
312+ if (ret != 0) {
313+ g_debug("Failed to set owner and group for file %s: %s", full_path, strerror(errno));
314+ }
315+ }
316+}
317+
318 /**
319 * Remove all files matching given glob.
320 */
321diff --git a/tests/generator/test_auth.py b/tests/generator/test_auth.py
322index de23adb..d3d886c 100644
323--- a/tests/generator/test_auth.py
324+++ b/tests/generator/test_auth.py
325@@ -226,7 +226,7 @@ network={
326
327 with open(os.path.join(self.workdir.name, 'run/systemd/system/netplan-wpa-eth0.service')) as f:
328 self.assertEqual(f.read(), SD_WPA % {'iface': 'eth0', 'drivers': 'wired'})
329- self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o644)
330+ self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o640)
331 self.assertTrue(os.path.islink(os.path.join(
332 self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-eth0.service')))
333
334diff --git a/tests/generator/test_wifis.py b/tests/generator/test_wifis.py
335index b875172..610782a 100644
336--- a/tests/generator/test_wifis.py
337+++ b/tests/generator/test_wifis.py
338@@ -140,7 +140,7 @@ network={
339 self.workdir.name, 'run/systemd/system/netplan-wpa-wl0.service')))
340 with open(os.path.join(self.workdir.name, 'run/systemd/system/netplan-wpa-wl0.service')) as f:
341 self.assertEqual(f.read(), SD_WPA % {'iface': 'wl0', 'drivers': 'nl80211,wext'})
342- self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o644)
343+ self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o640)
344 self.assertTrue(os.path.islink(os.path.join(
345 self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-wl0.service')))
346
347diff --git a/tests/integration/base.py b/tests/integration/base.py
348index e9c366c..74f0682 100644
349--- a/tests/integration/base.py
350+++ b/tests/integration/base.py
351@@ -32,6 +32,8 @@ import shutil
352 import gi
353 import glob
354 import json
355+import pwd
356+import grp
357
358 # make sure we point to libnetplan properly.
359 os.environ.update({'LD_LIBRARY_PATH': '.:{}'.format(os.environ.get('LD_LIBRARY_PATH'))})
360@@ -367,6 +369,89 @@ class IntegrationTestsBase(unittest.TestCase):
361 if state:
362 self.wait_output(['ip', 'addr', 'show', iface], state, 30)
363
364+ # Assert file permissions
365+ self.assert_file_permissions()
366+
367+ def assert_file_permissions(self):
368+ """ Check if the generated files have the expected permissions """
369+
370+ nd_expected_mode = 0o100640
371+ nd_expected_owner = 'root'
372+ nd_expected_group = 'systemd-network'
373+
374+ sd_expected_mode = 0o100640
375+ sd_expected_owner = 'root'
376+ sd_expected_group = 'root'
377+
378+ udev_expected_mode = 0o100640
379+ udev_expected_owner = 'root'
380+ udev_expected_group = 'root'
381+
382+ nm_expected_mode = 0o100600
383+ nm_expected_owner = 'root'
384+ nm_expected_group = 'root'
385+
386+ wpa_expected_mode = 0o100600
387+ wpa_expected_owner = 'root'
388+ wpa_expected_group = 'root'
389+
390+ # Check systemd-networkd files
391+ base_path = '/run/systemd/network'
392+ files = glob.glob(f'{base_path}/*.network') + glob.glob(f'{base_path}/*.netdev')
393+ for file in files:
394+ res = os.stat(file)
395+ user = pwd.getpwuid(res.st_uid)
396+ group = grp.getgrgid(res.st_gid)
397+ self.assertEqual(res.st_mode, nd_expected_mode, f'file {file}')
398+ self.assertEqual(user.pw_name, nd_expected_owner, f'file {file}')
399+ self.assertEqual(group.gr_name, nd_expected_group, f'file {file}')
400+
401+ # Check Network Manager files
402+ base_path = '/run/NetworkManager/system-connections'
403+ files = glob.glob(f'{base_path}/*.nmconnection')
404+ for file in files:
405+ res = os.stat(file)
406+ user = pwd.getpwuid(res.st_uid)
407+ group = grp.getgrgid(res.st_gid)
408+ self.assertEqual(res.st_mode, nm_expected_mode, f'file {file}')
409+ self.assertEqual(user.pw_name, nm_expected_owner, f'file {file}')
410+ self.assertEqual(group.gr_name, nm_expected_group, f'file {file}')
411+
412+ # Check wpa_supplicant configuration files
413+ base_path = '/run/netplan'
414+ files = glob.glob(f'{base_path}/wpa-*.conf')
415+ for file in files:
416+ res = os.stat(file)
417+ user = pwd.getpwuid(res.st_uid)
418+ group = grp.getgrgid(res.st_gid)
419+ self.assertEqual(res.st_mode, wpa_expected_mode, f'file {file}')
420+ self.assertEqual(user.pw_name, wpa_expected_owner, f'file {file}')
421+ self.assertEqual(group.gr_name, wpa_expected_group, f'file {file}')
422+
423+ # Check systemd service unit files
424+ base_path = '/run/systemd/system/'
425+ files = glob.glob(f'{base_path}/netplan-*.service')
426+ files += glob.glob(f'{base_path}/systemd-networkd-wait-online.service.d/*.conf')
427+ for file in files:
428+ res = os.stat(file)
429+ user = pwd.getpwuid(res.st_uid)
430+ group = grp.getgrgid(res.st_gid)
431+ self.assertEqual(res.st_mode, sd_expected_mode, f'file {file}')
432+ self.assertEqual(user.pw_name, sd_expected_owner, f'file {file}')
433+ self.assertEqual(group.gr_name, sd_expected_group, f'file {file}')
434+
435+ # Check systemd-udevd files
436+ udev_path = '/run/udev/rules.d'
437+ link_path = '/run/systemd/network'
438+ files = glob.glob(f'{udev_path}/*-netplan*.rules') + glob.glob(f'{link_path}/*.link')
439+ for file in files:
440+ res = os.stat(file)
441+ user = pwd.getpwuid(res.st_uid)
442+ group = grp.getgrgid(res.st_gid)
443+ self.assertEqual(res.st_mode, udev_expected_mode, f'file {file}')
444+ self.assertEqual(user.pw_name, udev_expected_owner, f'file {file}')
445+ self.assertEqual(group.gr_name, udev_expected_group, f'file {file}')
446+
447 def state(self, iface, state):
448 '''Tell generate_and_settle() to wait for a specific state'''
449 return iface + '/' + state
450--
4512.44.1
452
diff --git a/meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan_1.0.bb b/meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan_1.0.bb
index cf8d6d19e7..752acc23c3 100644
--- a/meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan_1.0.bb
+++ b/meta-oe/dynamic-layers/meta-python/recipes-connectivity/netplan/netplan_1.0.bb
@@ -17,6 +17,7 @@ REQUIRED_DISTRO_FEATURES = "systemd"
17SRC_URI = "git://github.com/CanonicalLtd/netplan.git;branch=main;protocol=https \ 17SRC_URI = "git://github.com/CanonicalLtd/netplan.git;branch=main;protocol=https \
18 file://0001-meson.build-drop-unnecessary-build-dependencies.patch \ 18 file://0001-meson.build-drop-unnecessary-build-dependencies.patch \
19 file://0002-meson.build-do-not-use-Werror.patch \ 19 file://0002-meson.build-do-not-use-Werror.patch \
20 file://CVE-2022-4968.patch \
20 " 21 "
21 22
22SRC_URI:append:libc-musl = " file://0001-don-t-fail-if-GLOB_BRACE-is-not-defined.patch" 23SRC_URI:append:libc-musl = " file://0001-don-t-fail-if-GLOB_BRACE-is-not-defined.patch"