* [PATCH net-next v3 5/5] dpll: zl3073x: add ref-sync pair support
From: Ivan Vecera @ 2026-04-08 10:27 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Arkadiusz Kubalewski, Jiri Pirko,
Michal Schmidt, Simon Horman, Vadim Fedorenko, linux-kernel,
Conor Dooley, Krzysztof Kozlowski, Rob Herring, devicetree,
Pasi Vaananen
In-Reply-To: <20260408102716.443099-1-ivecera@redhat.com>
Add support for ref-sync pair registration using the 'ref-sync-sources'
phandle property from device tree. A ref-sync pair consists of a clock
reference and a low-frequency sync signal where the DPLL locks to the
clock reference but phase-aligns to the sync reference.
The implementation:
- Stores fwnode handle in zl3073x_dpll_pin during pin registration
- Adds ref_sync_get/set callbacks to read and write the sync control
mode and pair registers
- Validates ref-sync frequency constraints: sync signal must be 8 kHz
or less, clock reference must be 1 kHz or more and higher than sync
- Excludes sync source from automatic reference selection by setting
its priority to NONE on connect; on disconnect the priority is left
as NONE and the user must explicitly make the pin selectable again
- Iterates ref-sync-sources phandles to register declared pairings
via dpll_pin_ref_sync_pair_add()
Reviewed-by: Petr Oros <poros@redhat.com>
Reviewed-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/dpll.c | 207 +++++++++++++++++++++++++++++++++++-
1 file changed, 206 insertions(+), 1 deletion(-)
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index dc649cf103cb4..c95e93ef3ab04 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/sprintf.h>
@@ -30,6 +31,7 @@
* @dpll: DPLL the pin is registered to
* @dpll_pin: pointer to registered dpll_pin
* @tracker: tracking object for the acquired reference
+ * @fwnode: firmware node handle
* @label: package label
* @dir: pin direction
* @id: pin id
@@ -46,6 +48,7 @@ struct zl3073x_dpll_pin {
struct zl3073x_dpll *dpll;
struct dpll_pin *dpll_pin;
dpll_tracker tracker;
+ struct fwnode_handle *fwnode;
char label[8];
enum dpll_pin_direction dir;
u8 id;
@@ -186,6 +189,109 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
return zl3073x_ref_state_set(zldev, ref_id, &ref);
}
+static int
+zl3073x_dpll_input_pin_ref_sync_get(const struct dpll_pin *dpll_pin,
+ void *pin_priv,
+ const struct dpll_pin *ref_sync_pin,
+ void *ref_sync_pin_priv,
+ enum dpll_pin_state *state,
+ struct netlink_ext_ack *extack)
+{
+ struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
+ struct zl3073x_dpll_pin *pin = pin_priv;
+ struct zl3073x_dpll *zldpll = pin->dpll;
+ struct zl3073x_dev *zldev = zldpll->dev;
+ const struct zl3073x_ref *ref;
+ u8 ref_id, mode, pair;
+
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = zl3073x_ref_state_get(zldev, ref_id);
+ mode = zl3073x_ref_sync_mode_get(ref);
+ pair = zl3073x_ref_sync_pair_get(ref);
+
+ if (mode == ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR &&
+ pair == zl3073x_input_pin_ref_get(sync_pin->id))
+ *state = DPLL_PIN_STATE_CONNECTED;
+ else
+ *state = DPLL_PIN_STATE_DISCONNECTED;
+
+ return 0;
+}
+
+static int
+zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin,
+ void *pin_priv,
+ const struct dpll_pin *ref_sync_pin,
+ void *ref_sync_pin_priv,
+ const enum dpll_pin_state state,
+ struct netlink_ext_ack *extack)
+{
+ struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
+ struct zl3073x_dpll_pin *pin = pin_priv;
+ struct zl3073x_dpll *zldpll = pin->dpll;
+ struct zl3073x_dev *zldev = zldpll->dev;
+ u8 mode, ref_id, sync_ref_id;
+ struct zl3073x_chan chan;
+ struct zl3073x_ref ref;
+ int rc;
+
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ sync_ref_id = zl3073x_input_pin_ref_get(sync_pin->id);
+ ref = *zl3073x_ref_state_get(zldev, ref_id);
+
+ if (state == DPLL_PIN_STATE_CONNECTED) {
+ const struct zl3073x_ref *sync_ref;
+ u32 ref_freq, sync_freq;
+
+ sync_ref = zl3073x_ref_state_get(zldev, sync_ref_id);
+ ref_freq = zl3073x_ref_freq_get(&ref);
+ sync_freq = zl3073x_ref_freq_get(sync_ref);
+
+ /* Sync signal must be 8 kHz or less and clock reference
+ * must be 1 kHz or more and higher than the sync signal.
+ */
+ if (sync_freq > 8000) {
+ NL_SET_ERR_MSG(extack,
+ "sync frequency must be 8 kHz or less");
+ return -EINVAL;
+ }
+ if (ref_freq < 1000) {
+ NL_SET_ERR_MSG(extack,
+ "clock frequency must be 1 kHz or more");
+ return -EINVAL;
+ }
+ if (ref_freq <= sync_freq) {
+ NL_SET_ERR_MSG(extack,
+ "clock frequency must be higher than sync frequency");
+ return -EINVAL;
+ }
+
+ zl3073x_ref_sync_pair_set(&ref, sync_ref_id);
+ mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR;
+ } else {
+ mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF;
+ }
+
+ zl3073x_ref_sync_mode_set(&ref, mode);
+
+ rc = zl3073x_ref_state_set(zldev, ref_id, &ref);
+ if (rc)
+ return rc;
+
+ /* Exclude sync source from automatic reference selection by setting
+ * its priority to NONE. On disconnect the priority is left as NONE
+ * and the user must explicitly make the pin selectable again.
+ */
+ if (state == DPLL_PIN_STATE_CONNECTED) {
+ chan = *zl3073x_chan_state_get(zldev, zldpll->id);
+ zl3073x_chan_ref_prio_set(&chan, sync_ref_id,
+ ZL_DPLL_REF_PRIO_NONE);
+ return zl3073x_chan_state_set(zldev, zldpll->id, &chan);
+ }
+
+ return 0;
+}
+
static int
zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
@@ -1147,6 +1253,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
.phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set,
.prio_get = zl3073x_dpll_input_pin_prio_get,
.prio_set = zl3073x_dpll_input_pin_prio_set,
+ .ref_sync_get = zl3073x_dpll_input_pin_ref_sync_get,
+ .ref_sync_set = zl3073x_dpll_input_pin_ref_sync_set,
.state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get,
.state_on_dpll_set = zl3073x_dpll_input_pin_state_on_dpll_set,
};
@@ -1239,8 +1347,11 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
if (IS_ERR(props))
return PTR_ERR(props);
- /* Save package label, esync capability and phase adjust granularity */
+ /* Save package label, fwnode, esync capability and phase adjust
+ * granularity.
+ */
strscpy(pin->label, props->package_label);
+ pin->fwnode = fwnode_handle_get(props->fwnode);
pin->esync_control = props->esync_control;
pin->phase_gran = props->dpll_props.phase_gran;
@@ -1285,6 +1396,8 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
dpll_pin_put(pin->dpll_pin, &pin->tracker);
pin->dpll_pin = NULL;
err_pin_get:
+ fwnode_handle_put(pin->fwnode);
+ pin->fwnode = NULL;
zl3073x_pin_props_put(props);
return rc;
@@ -1314,6 +1427,9 @@ zl3073x_dpll_pin_unregister(struct zl3073x_dpll_pin *pin)
dpll_pin_put(pin->dpll_pin, &pin->tracker);
pin->dpll_pin = NULL;
+
+ fwnode_handle_put(pin->fwnode);
+ pin->fwnode = NULL;
}
/**
@@ -1827,6 +1943,88 @@ zl3073x_dpll_free(struct zl3073x_dpll *zldpll)
kfree(zldpll);
}
+/**
+ * zl3073x_dpll_ref_sync_pair_register - register ref_sync pairs for a pin
+ * @pin: pointer to zl3073x_dpll_pin structure
+ *
+ * Iterates 'ref-sync-sources' phandles in the pin's firmware node and
+ * registers each declared pairing.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_dpll_ref_sync_pair_register(struct zl3073x_dpll_pin *pin)
+{
+ struct zl3073x_dev *zldev = pin->dpll->dev;
+ struct fwnode_handle *fwnode;
+ struct dpll_pin *sync_pin;
+ dpll_tracker tracker;
+ int n, rc;
+
+ for (n = 0; ; n++) {
+ /* Get n'th ref-sync source */
+ fwnode = fwnode_find_reference(pin->fwnode, "ref-sync-sources",
+ n);
+ if (IS_ERR(fwnode)) {
+ rc = PTR_ERR(fwnode);
+ break;
+ }
+
+ /* Find associated dpll pin */
+ sync_pin = fwnode_dpll_pin_find(fwnode, &tracker);
+ fwnode_handle_put(fwnode);
+ if (!sync_pin) {
+ dev_warn(zldev->dev, "%s: ref-sync source %d not found",
+ pin->label, n);
+ continue;
+ }
+
+ /* Register new ref-sync pair */
+ rc = dpll_pin_ref_sync_pair_add(pin->dpll_pin, sync_pin);
+ dpll_pin_put(sync_pin, &tracker);
+
+ /* -EBUSY means pairing already exists from another DPLL's
+ * registration.
+ */
+ if (rc && rc != -EBUSY) {
+ dev_err(zldev->dev,
+ "%s: failed to add ref-sync source %d: %pe",
+ pin->label, n, ERR_PTR(rc));
+ break;
+ }
+ }
+
+ return rc != -ENOENT ? rc : 0;
+}
+
+/**
+ * zl3073x_dpll_ref_sync_pairs_register - register ref_sync pairs for a DPLL
+ * @zldpll: pointer to zl3073x_dpll structure
+ *
+ * Iterates all registered input pins of the given DPLL and establishes
+ * ref_sync pairings declared by 'ref-sync-sources' phandles in the
+ * device tree.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_dpll_ref_sync_pairs_register(struct zl3073x_dpll *zldpll)
+{
+ struct zl3073x_dpll_pin *pin;
+ int rc;
+
+ list_for_each_entry(pin, &zldpll->pins, list) {
+ if (!zl3073x_dpll_is_input_pin(pin) || !pin->fwnode)
+ continue;
+
+ rc = zl3073x_dpll_ref_sync_pair_register(pin);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
/**
* zl3073x_dpll_register - register DPLL device and all its pins
* @zldpll: pointer to zl3073x_dpll structure
@@ -1850,6 +2048,13 @@ zl3073x_dpll_register(struct zl3073x_dpll *zldpll)
return rc;
}
+ rc = zl3073x_dpll_ref_sync_pairs_register(zldpll);
+ if (rc) {
+ zl3073x_dpll_pins_unregister(zldpll);
+ zl3073x_dpll_device_unregister(zldpll);
+ return rc;
+ }
+
return 0;
}
--
2.52.0
^ permalink raw reply related
* [PATCH net-next v3 4/5] dt-bindings: dpll: add ref-sync-sources property
From: Ivan Vecera @ 2026-04-08 10:27 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Rob Herring (Arm),
Arkadiusz Kubalewski, Jiri Pirko, Michal Schmidt, Simon Horman,
Vadim Fedorenko, linux-kernel, Conor Dooley, Krzysztof Kozlowski,
devicetree, Pasi Vaananen
In-Reply-To: <20260408102716.443099-1-ivecera@redhat.com>
Add ref-sync-sources phandle-array property to the dpll-pin schema
allowing board designers to declare which input pins can serve as
sync sources in a Reference-Sync pair. A Ref-Sync pair consists of
a clock reference and a low-frequency sync signal where the DPLL locks
to the clock but phase-aligns to the sync reference.
Update both examples in the Microchip ZL3073x binding to demonstrate
the new property with a 1 PPS sync source paired to a clock source.
Reviewed-by: Petr Oros <poros@redhat.com>
Reviewed-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
.../devicetree/bindings/dpll/dpll-pin.yaml | 13 ++++++++
.../bindings/dpll/microchip,zl30731.yaml | 30 ++++++++++++++-----
2 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/Documentation/devicetree/bindings/dpll/dpll-pin.yaml b/Documentation/devicetree/bindings/dpll/dpll-pin.yaml
index 51db93b77306f..1287a472f08fa 100644
--- a/Documentation/devicetree/bindings/dpll/dpll-pin.yaml
+++ b/Documentation/devicetree/bindings/dpll/dpll-pin.yaml
@@ -36,6 +36,19 @@ properties:
description: String exposed as the pin board label
$ref: /schemas/types.yaml#/definitions/string
+ ref-sync-sources:
+ description: |
+ List of phandles to input pins that can serve as the sync source
+ in a Reference-Sync pair with this pin acting as the clock source.
+ A Ref-Sync pair consists of a clock reference and a low-frequency
+ sync signal. The DPLL locks to the clock reference but
+ phase-aligns to the sync reference.
+ Only valid for input pins. Each referenced pin must be a
+ different input pin on the same device.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ maxItems: 1
+
supported-frequencies-hz:
description: List of supported frequencies for this pin, expressed in Hz.
diff --git a/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml b/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
index 17747f754b845..fa5a8f8e390cd 100644
--- a/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
+++ b/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
@@ -52,11 +52,19 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
- pin@0 { /* REF0P */
+ sync0: pin@0 { /* REF0P - 1 PPS sync source */
reg = <0>;
connection-type = "ext";
- label = "Input 0";
- supported-frequencies-hz = /bits/ 64 <1 1000>;
+ label = "SMA1";
+ supported-frequencies-hz = /bits/ 64 <1>;
+ };
+
+ pin@1 { /* REF0N - clock source, can pair with sync0 */
+ reg = <1>;
+ connection-type = "ext";
+ label = "SMA2";
+ supported-frequencies-hz = /bits/ 64 <10000 10000000>;
+ ref-sync-sources = <&sync0>;
};
};
@@ -90,11 +98,19 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
- pin@0 { /* REF0P */
+ sync1: pin@0 { /* REF0P - 1 PPS sync source */
reg = <0>;
- connection-type = "ext";
- label = "Input 0";
- supported-frequencies-hz = /bits/ 64 <1 1000>;
+ connection-type = "gnss";
+ label = "GNSS_1PPS_IN";
+ supported-frequencies-hz = /bits/ 64 <1>;
+ };
+
+ pin@1 { /* REF0N - clock source */
+ reg = <1>;
+ connection-type = "gnss";
+ label = "GNSS_10M_IN";
+ supported-frequencies-hz = /bits/ 64 <10000000>;
+ ref-sync-sources = <&sync1>;
};
};
--
2.52.0
^ permalink raw reply related
* [PATCH net-next v3 3/5] dpll: zl3073x: add ref sync and output clock type helpers
From: Ivan Vecera @ 2026-04-08 10:27 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Arkadiusz Kubalewski, Jiri Pirko,
Michal Schmidt, Simon Horman, Vadim Fedorenko, linux-kernel,
Conor Dooley, Krzysztof Kozlowski, Rob Herring, devicetree,
Pasi Vaananen
In-Reply-To: <20260408102716.443099-1-ivecera@redhat.com>
Add ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR and ZL_REF_SYNC_CTRL_PAIR
register definitions.
Add inline helpers to get and set the sync control mode and sync pair
fields of the reference sync control register:
zl3073x_ref_sync_mode_get/set() - ZL_REF_SYNC_CTRL_MODE field
zl3073x_ref_sync_pair_get/set() - ZL_REF_SYNC_CTRL_PAIR field
Add inline helpers to get and set the clock type field of the output
mode register:
zl3073x_out_clock_type_get/set() - ZL_OUTPUT_MODE_CLOCK_TYPE field
Convert existing esync callbacks to use the new helpers.
Reviewed-by: Petr Oros <poros@redhat.com>
Reviewed-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/dpll.c | 24 ++++++++-----------
drivers/dpll/zl3073x/out.h | 22 ++++++++++++++++++
drivers/dpll/zl3073x/ref.h | 46 +++++++++++++++++++++++++++++++++++++
drivers/dpll/zl3073x/regs.h | 2 ++
4 files changed, 80 insertions(+), 14 deletions(-)
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 445f4bccb9aab..dc649cf103cb4 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -139,7 +139,7 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
esync->range = esync_freq_ranges;
esync->range_num = ARRAY_SIZE(esync_freq_ranges);
- switch (FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl)) {
+ switch (zl3073x_ref_sync_mode_get(ref)) {
case ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75:
esync->freq = ref->esync_n_div == ZL_REF_ESYNC_DIV_1HZ ? 1 : 0;
esync->pulse = 25;
@@ -175,8 +175,7 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
else
sync_mode = ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75;
- ref.sync_ctrl &= ~ZL_REF_SYNC_CTRL_MODE;
- ref.sync_ctrl |= FIELD_PREP(ZL_REF_SYNC_CTRL_MODE, sync_mode);
+ zl3073x_ref_sync_mode_set(&ref, sync_mode);
if (freq) {
/* 1 Hz is only supported frequency now */
@@ -595,7 +594,7 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
const struct zl3073x_synth *synth;
const struct zl3073x_out *out;
u32 synth_freq, out_freq;
- u8 clock_type, out_id;
+ u8 out_id;
out_id = zl3073x_output_pin_out_get(pin->id);
out = zl3073x_out_state_get(zldev, out_id);
@@ -618,8 +617,7 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
esync->range = esync_freq_ranges;
esync->range_num = ARRAY_SIZE(esync_freq_ranges);
- clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode);
- if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
+ if (zl3073x_out_clock_type_get(out) != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
/* No need to read esync data if it is not enabled */
esync->freq = 0;
esync->pulse = 0;
@@ -652,8 +650,8 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll_pin *pin = pin_priv;
const struct zl3073x_synth *synth;
struct zl3073x_out out;
- u8 clock_type, out_id;
u32 synth_freq;
+ u8 out_id;
out_id = zl3073x_output_pin_out_get(pin->id);
out = *zl3073x_out_state_get(zldev, out_id);
@@ -665,15 +663,13 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
if (zl3073x_out_is_ndiv(&out))
return -EOPNOTSUPP;
- /* Select clock type */
+ /* Update clock type in output mode */
if (freq)
- clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC;
+ zl3073x_out_clock_type_set(&out,
+ ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC);
else
- clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL;
-
- /* Update clock type in output mode */
- out.mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE;
- out.mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type);
+ zl3073x_out_clock_type_set(&out,
+ ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL);
/* If esync is being disabled just write mailbox and finish */
if (!freq)
diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h
index edf40432bba5f..660889c57bffa 100644
--- a/drivers/dpll/zl3073x/out.h
+++ b/drivers/dpll/zl3073x/out.h
@@ -42,6 +42,28 @@ const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
const struct zl3073x_out *out);
+/**
+ * zl3073x_out_clock_type_get - get output clock type
+ * @out: pointer to out state
+ *
+ * Return: clock type of given output (ZL_OUTPUT_MODE_CLOCK_TYPE_*)
+ */
+static inline u8 zl3073x_out_clock_type_get(const struct zl3073x_out *out)
+{
+ return FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode);
+}
+
+/**
+ * zl3073x_out_clock_type_set - set output clock type
+ * @out: pointer to out state
+ * @type: clock type (ZL_OUTPUT_MODE_CLOCK_TYPE_*)
+ */
+static inline void
+zl3073x_out_clock_type_set(struct zl3073x_out *out, u8 type)
+{
+ FIELD_MODIFY(ZL_OUTPUT_MODE_CLOCK_TYPE, &out->mode, type);
+}
+
/**
* zl3073x_out_signal_format_get - get output signal format
* @out: pointer to out state
diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h
index be16be20dbc7e..55e80e4f08734 100644
--- a/drivers/dpll/zl3073x/ref.h
+++ b/drivers/dpll/zl3073x/ref.h
@@ -120,6 +120,52 @@ zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq)
return 0;
}
+/**
+ * zl3073x_ref_sync_mode_get - get sync control mode
+ * @ref: pointer to ref state
+ *
+ * Return: sync control mode (ZL_REF_SYNC_CTRL_MODE_*)
+ */
+static inline u8
+zl3073x_ref_sync_mode_get(const struct zl3073x_ref *ref)
+{
+ return FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl);
+}
+
+/**
+ * zl3073x_ref_sync_mode_set - set sync control mode
+ * @ref: pointer to ref state
+ * @mode: sync control mode (ZL_REF_SYNC_CTRL_MODE_*)
+ */
+static inline void
+zl3073x_ref_sync_mode_set(struct zl3073x_ref *ref, u8 mode)
+{
+ FIELD_MODIFY(ZL_REF_SYNC_CTRL_MODE, &ref->sync_ctrl, mode);
+}
+
+/**
+ * zl3073x_ref_sync_pair_get - get sync pair reference index
+ * @ref: pointer to ref state
+ *
+ * Return: paired reference index
+ */
+static inline u8
+zl3073x_ref_sync_pair_get(const struct zl3073x_ref *ref)
+{
+ return FIELD_GET(ZL_REF_SYNC_CTRL_PAIR, ref->sync_ctrl);
+}
+
+/**
+ * zl3073x_ref_sync_pair_set - set sync pair reference index
+ * @ref: pointer to ref state
+ * @pair: paired reference index
+ */
+static inline void
+zl3073x_ref_sync_pair_set(struct zl3073x_ref *ref, u8 pair)
+{
+ FIELD_MODIFY(ZL_REF_SYNC_CTRL_PAIR, &ref->sync_ctrl, pair);
+}
+
/**
* zl3073x_ref_is_diff - check if the given input reference is differential
* @ref: pointer to ref state
diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h
index 5ae50cb761a97..d425dc67250fe 100644
--- a/drivers/dpll/zl3073x/regs.h
+++ b/drivers/dpll/zl3073x/regs.h
@@ -213,7 +213,9 @@
#define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1)
#define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0)
#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF 0
+#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR 1
#define ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75 2
+#define ZL_REF_SYNC_CTRL_PAIR GENMASK(7, 4)
#define ZL_REG_REF_ESYNC_DIV ZL_REG(10, 0x30, 4)
#define ZL_REF_ESYNC_DIV_1HZ 0
--
2.52.0
^ permalink raw reply related
* [PATCH net-next v3 2/5] dpll: zl3073x: use FIELD_MODIFY() for clear-and-set patterns
From: Ivan Vecera @ 2026-04-08 10:27 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Arkadiusz Kubalewski, Jiri Pirko,
Michal Schmidt, Simon Horman, Vadim Fedorenko, linux-kernel,
Conor Dooley, Krzysztof Kozlowski, Rob Herring, devicetree,
Pasi Vaananen
In-Reply-To: <20260408102716.443099-1-ivecera@redhat.com>
Replace open-coded clear-and-set bitfield operations with
FIELD_MODIFY().
Reviewed-by: Petr Oros <poros@redhat.com>
Reviewed-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/chan.h | 17 ++++++-----------
drivers/dpll/zl3073x/core.c | 3 +--
drivers/dpll/zl3073x/flash.c | 3 +--
3 files changed, 8 insertions(+), 15 deletions(-)
diff --git a/drivers/dpll/zl3073x/chan.h b/drivers/dpll/zl3073x/chan.h
index e0f02d3432086..481da2133202b 100644
--- a/drivers/dpll/zl3073x/chan.h
+++ b/drivers/dpll/zl3073x/chan.h
@@ -66,8 +66,7 @@ static inline u8 zl3073x_chan_ref_get(const struct zl3073x_chan *chan)
*/
static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode)
{
- chan->mode_refsel &= ~ZL_DPLL_MODE_REFSEL_MODE;
- chan->mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_MODE, mode);
+ FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_MODE, &chan->mode_refsel, mode);
}
/**
@@ -77,8 +76,7 @@ static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode)
*/
static inline void zl3073x_chan_ref_set(struct zl3073x_chan *chan, u8 ref)
{
- chan->mode_refsel &= ~ZL_DPLL_MODE_REFSEL_REF;
- chan->mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref);
+ FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_REF, &chan->mode_refsel, ref);
}
/**
@@ -110,13 +108,10 @@ zl3073x_chan_ref_prio_set(struct zl3073x_chan *chan, u8 ref, u8 prio)
{
u8 *val = &chan->ref_prio[ref / 2];
- if (!(ref & 1)) {
- *val &= ~ZL_DPLL_REF_PRIO_REF_P;
- *val |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_P, prio);
- } else {
- *val &= ~ZL_DPLL_REF_PRIO_REF_N;
- *val |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_N, prio);
- }
+ if (!(ref & 1))
+ FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_P, val, prio);
+ else
+ FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_N, val, prio);
}
/**
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index cb47a5db061aa..5f1e70f3e40a0 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -805,8 +805,7 @@ int zl3073x_dev_phase_avg_factor_set(struct zl3073x_dev *zldev, u8 factor)
value = (factor + 1) & 0x0f;
/* Update phase measurement control register */
- dpll_meas_ctrl &= ~ZL_DPLL_MEAS_CTRL_AVG_FACTOR;
- dpll_meas_ctrl |= FIELD_PREP(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, value);
+ FIELD_MODIFY(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, &dpll_meas_ctrl, value);
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MEAS_CTRL, dpll_meas_ctrl);
if (rc)
return rc;
diff --git a/drivers/dpll/zl3073x/flash.c b/drivers/dpll/zl3073x/flash.c
index 83452a77e3e98..f85535c8ad246 100644
--- a/drivers/dpll/zl3073x/flash.c
+++ b/drivers/dpll/zl3073x/flash.c
@@ -194,8 +194,7 @@ zl3073x_flash_cmd_wait(struct zl3073x_dev *zldev, u32 operation,
if (rc)
return rc;
- value &= ~ZL_WRITE_FLASH_OP;
- value |= FIELD_PREP(ZL_WRITE_FLASH_OP, operation);
+ FIELD_MODIFY(ZL_WRITE_FLASH_OP, &value, operation);
rc = zl3073x_write_u8(zldev, ZL_REG_WRITE_FLASH, value);
if (rc)
--
2.52.0
^ permalink raw reply related
* [PATCH net-next v3 1/5] dpll: zl3073x: clean up esync get/set and use zl3073x_out_is_ndiv()
From: Ivan Vecera @ 2026-04-08 10:27 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Arkadiusz Kubalewski, Jiri Pirko,
Michal Schmidt, Simon Horman, Vadim Fedorenko, linux-kernel,
Conor Dooley, Krzysztof Kozlowski, Rob Herring, devicetree,
Pasi Vaananen
In-Reply-To: <20260408102716.443099-1-ivecera@redhat.com>
Return -EOPNOTSUPP early in esync_get callbacks when esync is not
supported instead of conditionally populating the range at the end.
This simplifies the control flow by removing the finish label/goto
in the output variant and the conditional range assignment in both
input and output variants.
Replace open-coded N-div signal format switch statements with
zl3073x_out_is_ndiv() helper in esync_get, esync_set and
frequency_set callbacks.
Reviewed-by: Petr Oros <poros@redhat.com>
Reviewed-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/dpll.c | 64 ++++++++++++-------------------------
1 file changed, 20 insertions(+), 44 deletions(-)
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index d788ca45a17e5..445f4bccb9aab 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -133,6 +133,12 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
ref_id = zl3073x_input_pin_ref_get(pin->id);
ref = zl3073x_ref_state_get(zldev, ref_id);
+ if (!pin->esync_control || zl3073x_ref_freq_get(ref) <= 1)
+ return -EOPNOTSUPP;
+
+ esync->range = esync_freq_ranges;
+ esync->range_num = ARRAY_SIZE(esync_freq_ranges);
+
switch (FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl)) {
case ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75:
esync->freq = ref->esync_n_div == ZL_REF_ESYNC_DIV_1HZ ? 1 : 0;
@@ -144,17 +150,6 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
break;
}
- /* If the pin supports esync control expose its range but only
- * if the current reference frequency is > 1 Hz.
- */
- if (pin->esync_control && zl3073x_ref_freq_get(ref) > 1) {
- esync->range = esync_freq_ranges;
- esync->range_num = ARRAY_SIZE(esync_freq_ranges);
- } else {
- esync->range = NULL;
- esync->range_num = 0;
- }
-
return 0;
}
@@ -599,8 +594,8 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll_pin *pin = pin_priv;
const struct zl3073x_synth *synth;
const struct zl3073x_out *out;
+ u32 synth_freq, out_freq;
u8 clock_type, out_id;
- u32 synth_freq;
out_id = zl3073x_output_pin_out_get(pin->id);
out = zl3073x_out_state_get(zldev, out_id);
@@ -609,17 +604,19 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
* for N-division is also used for the esync divider so both cannot
* be used.
*/
- switch (zl3073x_out_signal_format_get(out)) {
- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
+ if (zl3073x_out_is_ndiv(out))
return -EOPNOTSUPP;
- default:
- break;
- }
/* Get attached synth frequency */
synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out));
synth_freq = zl3073x_synth_freq_get(synth);
+ out_freq = synth_freq / out->div;
+
+ if (!pin->esync_control || out_freq <= 1)
+ return -EOPNOTSUPP;
+
+ esync->range = esync_freq_ranges;
+ esync->range_num = ARRAY_SIZE(esync_freq_ranges);
clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode);
if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
@@ -627,11 +624,11 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
esync->freq = 0;
esync->pulse = 0;
- goto finish;
+ return 0;
}
/* Compute esync frequency */
- esync->freq = synth_freq / out->div / out->esync_n_period;
+ esync->freq = out_freq / out->esync_n_period;
/* By comparing the esync_pulse_width to the half of the pulse width
* the esync pulse percentage can be determined.
@@ -640,18 +637,6 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
*/
esync->pulse = (50 * out->esync_n_width) / out->div;
-finish:
- /* Set supported esync ranges if the pin supports esync control and
- * if the output frequency is > 1 Hz.
- */
- if (pin->esync_control && (synth_freq / out->div) > 1) {
- esync->range = esync_freq_ranges;
- esync->range_num = ARRAY_SIZE(esync_freq_ranges);
- } else {
- esync->range = NULL;
- esync->range_num = 0;
- }
-
return 0;
}
@@ -677,13 +662,8 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
* for N-division is also used for the esync divider so both cannot
* be used.
*/
- switch (zl3073x_out_signal_format_get(&out)) {
- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
+ if (zl3073x_out_is_ndiv(&out))
return -EOPNOTSUPP;
- default:
- break;
- }
/* Select clock type */
if (freq)
@@ -745,9 +725,9 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin,
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
const struct zl3073x_synth *synth;
- u8 out_id, signal_format;
u32 new_div, synth_freq;
struct zl3073x_out out;
+ u8 out_id;
out_id = zl3073x_output_pin_out_get(pin->id);
out = *zl3073x_out_state_get(zldev, out_id);
@@ -757,12 +737,8 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin,
synth_freq = zl3073x_synth_freq_get(synth);
new_div = synth_freq / (u32)frequency;
- /* Get used signal format for the given output */
- signal_format = zl3073x_out_signal_format_get(&out);
-
/* Check signal format */
- if (signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV &&
- signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV) {
+ if (!zl3073x_out_is_ndiv(&out)) {
/* For non N-divided signal formats the frequency is computed
* as division of synth frequency and output divisor.
*/
--
2.52.0
^ permalink raw reply related
* [PATCH net-next v3 0/5] dpll: zl3073x: add ref-sync pair support
From: Ivan Vecera @ 2026-04-08 10:27 UTC (permalink / raw)
To: netdev
Cc: Arkadiusz Kubalewski, Jiri Pirko, Michal Schmidt, Petr Oros,
Prathosh Satish, Simon Horman, Vadim Fedorenko, linux-kernel,
Conor Dooley, Krzysztof Kozlowski, Rob Herring, devicetree,
Pasi Vaananen
This series adds Reference-Sync pair support to the ZL3073x DPLL driver.
A Ref-Sync pair consists of a clock reference and a low-frequency sync
signal (e.g. 1 PPS) where the DPLL locks to the clock reference but
phase-aligns to the sync reference.
Patches 1-3 are preparatory cleanups and helper additions:
- Clean up esync get/set callbacks with early returns and use the
zl3073x_out_is_ndiv() helper
- Convert open-coded clear-and-set bitfield patterns to FIELD_MODIFY()
- Add ref sync control and output clock type accessor helpers
Patch 4 adds the 'ref-sync-sources' phandle-array property to the
dpll-pin device tree binding schema and updates the ZL3073x binding
examples.
Patch 5 implements the driver support:
- ref_sync_get/set callbacks with frequency validation
- Automatic sync source exclusion from reference selection
- Device tree based ref-sync pair registration
Tested and verified on Microchip EDS2 (pcb8385) development board.
Changes:
v3 - fix ref-sync-sources schema: add items/maxItems constraint for
phandle list without arg cells (Rob Herring)
v2 - added proper reviewed-by tags (requested by Kuba)
Ivan Vecera (5):
dpll: zl3073x: clean up esync get/set and use zl3073x_out_is_ndiv()
dpll: zl3073x: use FIELD_MODIFY() for clear-and-set patterns
dpll: zl3073x: add ref sync and output clock type helpers
dt-bindings: dpll: add ref-sync-sources property
dpll: zl3073x: add ref-sync pair support
.../devicetree/bindings/dpll/dpll-pin.yaml | 13 +
.../bindings/dpll/microchip,zl30731.yaml | 30 +-
drivers/dpll/zl3073x/chan.h | 17 +-
drivers/dpll/zl3073x/core.c | 3 +-
drivers/dpll/zl3073x/dpll.c | 295 ++++++++++++++----
drivers/dpll/zl3073x/flash.c | 3 +-
drivers/dpll/zl3073x/out.h | 22 ++
drivers/dpll/zl3073x/ref.h | 46 +++
drivers/dpll/zl3073x/regs.h | 2 +
9 files changed, 350 insertions(+), 81 deletions(-)
--
2.52.0
^ permalink raw reply
* Re: [RFC PATCH v4 00/19] Support socket access-control
From: Mickaël Salaün @ 2026-04-08 10:26 UTC (permalink / raw)
To: Mikhail Ivanov
Cc: gnoack, willemdebruijn.kernel, matthieu, linux-security-module,
netdev, netfilter-devel, yusongping, artem.kuzin,
konstantin.meskhidze
In-Reply-To: <20251118134639.3314803-1-ivanov.mikhail1@huawei-partners.com>
Hi Mikhail,
On Tue, Nov 18, 2025 at 09:46:20PM +0800, Mikhail Ivanov wrote:
> Hello! This is v4 RFC patch dedicated to socket protocols restriction.
>
> It is based on the landlock's mic-next branch on top of Linux 6.16-rc2
> kernel version.
>
> Objective
> =========
> Extend Landlock with a mechanism to restrict any set of protocols in
> a sandboxed process.
>
> Closes: https://github.com/landlock-lsm/linux/issues/6
>
> Motivation
> ==========
> Landlock implements the `LANDLOCK_RULE_NET_PORT` rule type, which provides
> fine-grained control of actions for a specific protocol. Any action or
> protocol that is not supported by this rule can not be controlled. As a
> result, protocols for which fine-grained control is not supported can be
> used in a sandboxed system and lead to vulnerabilities or unexpected
> behavior.
>
> Controlling the protocols used will allow to use only those that are
> necessary for the system and/or which have fine-grained Landlock control
> through others types of rules (e.g. TCP bind/connect control with
> `LANDLOCK_RULE_NET_PORT`, UNIX bind control with
> `LANDLOCK_RULE_PATH_BENEATH`).
>
> Consider following examples:
> * Server may want to use only TCP sockets for which there is fine-grained
> control of bind(2) and connect(2) actions [1].
> * System that does not need a network or that may want to disable network
> for security reasons (e.g. [2]) can achieve this by restricting the use
> of all possible protocols.
>
> [1] https://lore.kernel.org/all/ZJvy2SViorgc+cZI@google.com/
> [2] https://cr.yp.to/unix/disablenetwork.html
>
> Implementation
> ==============
> This patchset adds control over the protocols used by implementing a
> restriction of socket creation. This is possible thanks to the new type
> of rule - `LANDLOCK_RULE_SOCKET`, that allows to restrict actions on
> sockets, and a new access right - `LANDLOCK_ACCESS_SOCKET_CREATE`, that
> corresponds to user space sockets creation. The key in this rule
> corresponds to communication protocol signature from socket(2) syscall.
FYI, I sent a new patch series that adds a handled_perm field to
rulesets:
https://lore.kernel.org/all/20260312100444.2609563-6-mic@digikod.net/
See also the rationale:
https://lore.kernel.org/all/20260312100444.2609563-12-mic@digikod.net/
I think that would work well with the socket creation permission. WDYT?
Do you think you'll be able to continue this work or would you like me
or Günther to complete the remaining last bits (while of course keeping
you as the main author)?
>
> The right to create a socket is checked in the LSM hook which is called
> in the __sock_create method. The following user space operations are
> subject to this check: socket(2), socketpair(2), io_uring(7).
>
> `LANDLOCK_ACCESS_SOCKET_CREATE` does not restrict socket creation
> performed by accept(2), because created socket is used for messaging
> between already existing endpoints.
>
> Design discussion
> ===================
> 1. Should `SCTP_SOCKOPT_PEELOFF` and socketpair(2) be restricted?
>
> SCTP socket can be connected to a multiple endpoints (one-to-many
> relation). Calling setsockopt(2) on such socket with option
> `SCTP_SOCKOPT_PEELOFF` detaches one of existing connections to a separate
> UDP socket. This detach is currently restrictable.
>
> Same applies for the socketpair(2) syscall. It was noted that denying
> usage of socketpair(2) in sandboxed environment may be not meaninful [1].
>
> Currently both operations use general socket interface to create sockets.
> Therefore it's not possible to distinguish between socket(2) and those
> operations inside security_socket_create LSM hook which is currently
> used for protocols restriction. Providing such separation may require
> changes in socket layer (eg. in __sock_create) interface which may not be
> acceptable.
>
> [1] https://lore.kernel.org/all/ZurZ7nuRRl0Zf2iM@google.com/
>
> Code coverage
> =============
> Code coverage(gcov) report with the launch of all the landlock selftests:
> * security/landlock:
> lines......: 94.0% (1200 of 1276 lines)
> functions..: 95.0% (134 of 141 functions)
>
> * security/landlock/socket.c:
> lines......: 100.0% (56 of 56 lines)
> functions..: 100.0% (5 of 5 functions)
>
> Currently landlock-test-tools fails on mini.kernel_socket test due to lack
> of SMC protocol support.
>
> General changes v3->v4
> ======================
> * Implementation
> * Adds protocol field to landlock_socket_attr.
> * Adds protocol masks support via wildcards values in
> landlock_socket_attr.
> * Changes LSM hook used from socket_post_create to socket_create.
> * Changes protocol ranges acceptable by socket rules.
> * Adds audit support.
> * Changes ABI version to 8.
> * Tests
> * Adds 5 new tests:
> * mini.rule_with_wildcard, protocol_wildcard.access,
> mini.ruleset_with_wildcards_overlap:
> verify rulesets containing rules with wildcard values.
> * tcp_protocol.alias_restriction: verify that Landlock doesn't
> perform protocol mappings.
> * audit.socket_create: tests audit denial logging.
> * Squashes tests corresponding to Landlock rule adding to a single commit.
> * Documentation
> * Refactors Documentation/userspace-api/landlock.rst.
> * Commits
> * Rebases on mic-next.
> * Refactors commits.
>
> Previous versions
> =================
> v3: https://lore.kernel.org/all/20240904104824.1844082-1-ivanov.mikhail1@huawei-partners.com/
> v2: https://lore.kernel.org/all/20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com/
> v1: https://lore.kernel.org/all/20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com/
>
> Mikhail Ivanov (19):
> landlock: Support socket access-control
> selftests/landlock: Test creating a ruleset with unknown access
> selftests/landlock: Test adding a socket rule
> selftests/landlock: Testing adding rule with wildcard value
> selftests/landlock: Test acceptable ranges of socket rule key
> landlock: Add hook on socket creation
> selftests/landlock: Test basic socket restriction
> selftests/landlock: Test network stack error code consistency
> selftests/landlock: Test overlapped rulesets with rules of protocol
> ranges
> selftests/landlock: Test that kernel space sockets are not restricted
> selftests/landlock: Test protocol mappings
> selftests/landlock: Test socketpair(2) restriction
> selftests/landlock: Test SCTP peeloff restriction
> selftests/landlock: Test that accept(2) is not restricted
> lsm: Support logging socket common data
> landlock: Log socket creation denials
> selftests/landlock: Test socket creation denial log for audit
> samples/landlock: Support socket protocol restrictions
> landlock: Document socket rule type support
>
> Documentation/userspace-api/landlock.rst | 48 +-
> include/linux/lsm_audit.h | 8 +
> include/uapi/linux/landlock.h | 60 +-
> samples/landlock/sandboxer.c | 118 +-
> security/landlock/Makefile | 2 +-
> security/landlock/access.h | 3 +
> security/landlock/audit.c | 12 +
> security/landlock/audit.h | 1 +
> security/landlock/limits.h | 4 +
> security/landlock/ruleset.c | 37 +-
> security/landlock/ruleset.h | 46 +-
> security/landlock/setup.c | 2 +
> security/landlock/socket.c | 198 +++
> security/landlock/socket.h | 20 +
> security/landlock/syscalls.c | 61 +-
> security/lsm_audit.c | 4 +
> tools/testing/selftests/landlock/base_test.c | 2 +-
> tools/testing/selftests/landlock/common.h | 14 +
> tools/testing/selftests/landlock/config | 47 +
> tools/testing/selftests/landlock/net_test.c | 11 -
> .../selftests/landlock/protocols_define.h | 169 +++
> .../testing/selftests/landlock/socket_test.c | 1169 +++++++++++++++++
> 22 files changed, 1990 insertions(+), 46 deletions(-)
> create mode 100644 security/landlock/socket.c
> create mode 100644 security/landlock/socket.h
> create mode 100644 tools/testing/selftests/landlock/protocols_define.h
> create mode 100644 tools/testing/selftests/landlock/socket_test.c
>
>
> base-commit: 6dde339a3df80a57ac3d780d8cfc14d9262e2acd
> --
> 2.34.1
>
>
^ permalink raw reply
* Re: [PATCH net v6 4/4] macsec: Support VLAN-filtering lower devices
From: Cosmin Ratiu @ 2026-04-08 10:24 UTC (permalink / raw)
To: sd@queasysnail.net
Cc: andrew+netdev@lunn.ch, davem@davemloft.net,
linux-kselftest@vger.kernel.org, Dragos Tatulea, sdf@fomichev.me,
shuah@kernel.org, kuba@kernel.org, pabeni@redhat.com,
horms@kernel.org, edumazet@google.com, netdev@vger.kernel.org
In-Reply-To: <adYQ3OMfEEWFTd7X@krikkit>
On Wed, 2026-04-08 at 10:25 +0200, Sabrina Dubroca wrote:
> 2026-04-07, 15:07:47 +0000, Cosmin Ratiu wrote:
> > On Thu, 2026-04-02 at 16:48 +0200, Sabrina Dubroca wrote:
> > > If this happens on a real device, the VLAN filters will be
> > > broken.
> > > I'm
> > > not sure what the right behavior would be:
> > >
> > > 1. reject the request to enable offload
> > > 2. switch to promiscuous mode
> >
> > I implemented and tested option 1. In the unlikely scenario adding
> > VLAN
> > filters prevents offloading
>
> How unlikely is it? Resource allocation, talking to HW, device
> limits,
> anything else that could fail?
>
> > , it's better for the driver to be explicit
> > and let the user turn on promisc mode themselves. Keeping track of
> > whether VLAN filters failed and promisc was used as a fallback adds
> > some extra complexity.
>
> If it's indeed (very) unlikely, sure. There's still a bit of a
> regression/change of behavior for users compared to before the
> IFF_UNICAST_FLT patch, but I think we can wait until someone
> complains, and then add the tracking if that happens.
>
> > What would be the point of IFF_UNICAST_FLT then?
>
> The point is that this would just be a fallback.
>
> > Please let me know if you agree with this approach, so I can send
> > v8
> > with it.
>
> If you can confirm it's on the "very unlikely" side, yes, this
> approach sounds ok. Thanks.
There are many, many drivers which implement .ndo_vlan_rx_add_vid, I
can't really browse them all and determine overall likelihood of
failure. But presumably there are some memory allocations involved and
some FW communication to add the new filter.
An AI prompt of "Explore implementations of .ndo_vlan_rx_add_vid in
drivers and classify potential failure sources and their likelihood of
failure." resulted in (edited for compactness):
"""
Analyzed 24+ implementations across major drivers. Here's the
breakdown:
Category Likelihood Drivers Typical Error
HW/FW cmds Low mlx4, nfp, hinic, qeth, vmxnet3 Device-specific
Mem alloc Very Low bnx2x, qede, virtio_net -ENOMEM
Filter add Low-Medium mlx5, mlx4, ice, qede, ocelot -ENOSPC, -EEXIST
Locking Very Low be2net, mlx4, nfp, hinic -EBUSY
Res limit Medium qede (quota check) Promisc fallback
Three Driver Archetypes
1. Simple bitfield drivers (never fail): e1000, e1000e, ixgbe, igb —
just set a VFTA bit in hardware registers, always return 0.
2. Complex offload drivers (can fail): mlx5 (flow steering rules), mlx4
(FW VLAN registration), ice (switch rules + promisc management), qede
(quota-aware with promisc fallback), nfp (mailbox commands), hinic (FW
commands with rollback).
3. Delegation/passthrough drivers (inherit failures): bonding, team,
hsr, dsa, macvlan, ipvlan, macsec — propagate vlan_vid_add() to lower
devices with unwind-on-failure patterns.
"""
So I guess we go with option 1 for now.
>
> > > OTOH maybe we don't need to care, since __netdev_update_features
> > > also
> > > (kind of) ignores those errors:
> > >
> [...]
> >
> > Well, in this case we have the chance to do something nicer (even
> > proper error message back to the user via extack) for a small
>
> (That reminds me I have a branch of "macsec: add extack to X" patches
> I still need to polish and submit. I don't think I'll get to it
> before
> the merge window opens, I'll rebase on top of your changes.)
>
> > complexity cost. Perhaps the VLAN filter handling could be improved
> > separately.
>
> I'm not sure if this would be an "improvement to VLAN filter
> handling"
> or a "(breaking) change of user-visible behavior". Probably
> improvement. Or maybe it's "unlikely enough" that nobody has ever
> cared.
>
^ permalink raw reply
* [PATCH net] net: airoha: Fix FE_PSE_BUF_SET configuration if PPE2 is available
From: Lorenzo Bianconi @ 2026-04-08 10:20 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman
Cc: linux-arm-kernel, linux-mediatek, netdev, Xuegang Lu,
Lorenzo Bianconi
airoha_fe_set routine is used to set specified bits to 1 in the selected
register. In the FE_PSE_BUF_SET case this can due to a overestimation of
the required buffers for I/O queues since we can miss to set some bits
of PSE_ALLRSV_MASK subfield to 0. Fix the issue relying on airoha_fe_rmw
routine instead.
Fixes: 8e38e08f2c560 ("net: airoha: fix PSE memory configuration in airoha_fe_pse_ports_init()")
Tested-by: Xuegang Lu <xuegang.lu@airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 91cb63a32d99..c365d693cf40 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -293,16 +293,18 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth)
[FE_PSE_PORT_GDM4] = 2,
[FE_PSE_PORT_CDM5] = 2,
};
- u32 all_rsv;
int q;
- all_rsv = airoha_fe_get_pse_all_rsv(eth);
if (airoha_ppe_is_enabled(eth, 1)) {
+ u32 all_rsv;
+
/* hw misses PPE2 oq rsv */
+ all_rsv = airoha_fe_get_pse_all_rsv(eth);
all_rsv += PSE_RSV_PAGES *
pse_port_num_queues[FE_PSE_PORT_PPE2];
+ airoha_fe_rmw(eth, REG_FE_PSE_BUF_SET, PSE_ALLRSV_MASK,
+ FIELD_PREP(PSE_ALLRSV_MASK, all_rsv));
}
- airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv);
/* CMD1 */
for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_CDM1]; q++)
---
base-commit: f821664dde29302e8450aa0597bf1e4c7c5b0a22
change-id: 20260408-airoha-reg_fe_pse_buf_set-39a75edb52ca
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* Re: [PATCH net v2 3/3] vsock/test: add MSG_PEEK after partial recv test
From: Stefano Garzarella @ 2026-04-08 10:18 UTC (permalink / raw)
To: Luigi Leonardi
Cc: Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang, Xuan Zhuo,
Eugenio Pérez, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Arseniy Krasnov, kvm, virtualization,
netdev, linux-kernel
In-Reply-To: <20260407-fix_peek-v2-3-2e2581dc8b7c@redhat.com>
On Tue, Apr 07, 2026 at 11:13:57AM +0200, Luigi Leonardi wrote:
>Add a test that verifies MSG_PEEK works correctly after a partial
>recv().
>
>This is to test a bug that was present in the
>`virtio_transport_stream_do_peek()` when computing the number of bytes to
>copy: After a partial read, the peek function didn't take into
>consideration the number of bytes that were already read. So peeking the
>whole buffer would cause a out-of-bounds read, that resulted in a -EFAULT.
>
>This test does exactly this: do a partial recv on a buffer, then try to
>peek the whole buffer content.
>
>Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
>---
> tools/testing/vsock/vsock_test.c | 43 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 43 insertions(+)
>
>diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c
>index bdb0754965df..d38a90a86f34 100644
>--- a/tools/testing/vsock/vsock_test.c
>+++ b/tools/testing/vsock/vsock_test.c
>@@ -346,6 +346,44 @@ static void test_stream_msg_peek_server(const struct test_opts *opts)
> return test_msg_peek_server(opts, false);
> }
>
>+static void test_stream_peek_after_recv_client(const struct test_opts *opts)
>+{
>+ unsigned char buf[MSG_PEEK_BUF_LEN];
What about:
unsigned char buf[MSG_PEEK_BUF_LEN] = { 0 };
so we can remove the memset() call?
>+ int fd;
>+
>+ fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
>+ if (fd < 0) {
>+ perror("connect");
>+ exit(EXIT_FAILURE);
>+ }
>+
>+ memset(buf, 0, sizeof(buf));
>+
>+ send_buf(fd, buf, sizeof(buf), 0, sizeof(buf));
>+
>+ close(fd);
>+}
>+
>+static void test_stream_peek_after_recv_server(const struct test_opts *opts)
>+{
>+ unsigned char buf[MSG_PEEK_BUF_LEN];
>+ int fd;
>+
>+ fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
>+ if (fd < 0) {
>+ perror("accept");
>+ exit(EXIT_FAILURE);
>+ }
>+
>+ /* Partial recv to advance offset within the skb */
>+ recv_buf(fd, buf, 1, 0, 1);
>+
>+ /* Ask more bytes than available */
>+ recv_buf(fd, buf, sizeof(buf), MSG_PEEK, sizeof(buf) - 1);
What about checking also what we read like we do in
test_msg_peek_server() ?
Not a strong opinion, but if we go in that direction, maybe we can just
reuse test_stream_msg_peek_client() also for this test case.
Thanks,
Stefano
>+
>+ close(fd);
>+}
>+
> #define SOCK_BUF_SIZE (2 * 1024 * 1024)
> #define SOCK_BUF_SIZE_SMALL (64 * 1024)
> #define MAX_MSG_PAGES 4
>@@ -2509,6 +2547,11 @@ static struct test_case test_cases[] = {
> .run_client = test_stream_tx_credit_bounds_client,
> .run_server = test_stream_tx_credit_bounds_server,
> },
>+ {
>+ .name = "SOCK_STREAM MSG_PEEK after partial recv",
>+ .run_client = test_stream_peek_after_recv_client,
>+ .run_server = test_stream_peek_after_recv_server,
>+ },
> {},
> };
>
>
>--
>2.53.0
>
^ permalink raw reply
* Re: [PATCH net-next 0/4] net: mana: Fix probe/remove error path bugs
From: Erni Sri Satya Vennela @ 2026-04-08 10:17 UTC (permalink / raw)
To: Mohsin Bashir
Cc: kys, haiyangz, wei.liu, decui, longli, andrew+netdev, davem,
edumazet, kuba, pabeni, ssengar, dipayanroy, gargaditya,
shirazsaleem, kees, kotaranov, leon, shacharr, stephen,
linux-hyperv, netdev, linux-kernel
In-Reply-To: <62c3fcc1-6758-47c4-984e-f6940139de0c@gmail.com>
On Fri, Apr 03, 2026 at 11:28:34PM -0700, Mohsin Bashir wrote:
>
>
> On 4/3/26 12:09 AM, Erni Sri Satya Vennela wrote:
> > Fix four pre-existing bugs in mana_probe()/mana_remove() error handling
> > that can cause warnings on uninitialized work structs, masked errors,
> > and resource leaks when early probe steps fail.
> >
> > Patches 1-2 move work struct initialization (link_change_work and
> > gf_stats_work) to before any error path that could trigger
> > mana_remove(), preventing WARN_ON in __flush_work() or debug object
> > warnings when sync cancellation runs on uninitialized work structs.
> >
> > Patch 3 prevents add_adev() from overwriting a port probe error,
> > which could leave the driver in a broken state with NULL ports while
> > reporting success.
> >
> > Patch 4 changes 'goto out' to 'break' in mana_remove()'s port loop
> > so that mana_destroy_eq() is always reached, preventing EQ leaks when
> > a NULL port is encountered.
> >
> > Erni Sri Satya Vennela (4):
> > net: mana: Init link_change_work before potential error paths in probe
> > net: mana: Init gf_stats_work before potential error paths in probe
> > net: mana: Don't overwrite port probe error with add_adev result
> > net: mana: Fix EQ leak in mana_remove on NULL port
> >
> > drivers/net/ethernet/microsoft/mana/mana_en.c | 28 +++++++++----------
> > 1 file changed, 14 insertions(+), 14 deletions(-)
> >
> I believe mana is already in the mainline so fixes go to the net tree?
Thanks for the correction Mohsin.
I'll make this chaneg in the next version.
- Vennela
^ permalink raw reply
* Re: [PATCH] ppp: require CAP_NET_ADMIN in target netns for unattached ioctls
From: Matteo Croce @ 2026-04-08 10:04 UTC (permalink / raw)
To: Qingfang Deng
Cc: Taegu Ha, netdev, linux-ppp, gnault, jaco, richardbgobert,
ericwouds, Cyrill Gorcunov
In-Reply-To: <59d11588-0af2-42e6-a030-83240a0a5512@linux.dev>
On Wed, Apr 8, 2026 at 8:28 AM Qingfang Deng <qingfang.deng@linux.dev> wrote:
>
> >
> Hi,
>
> Added Cc: Cyrill, and Matteo
>
> On 2026/4/8 12:23, Taegu Ha wrote:
> > /dev/ppp open is currently authorized against file->f_cred->user_ns,
> > while unattached administrative ioctls operate on current->nsproxy->net_ns.
> >
> > As a result, a local unprivileged user can create a new user namespace
> > with CLONE_NEWUSER, gain CAP_NET_ADMIN only in that new user namespace,
> > and still issue PPPIOCNEWUNIT, PPPIOCATTACH, or PPPIOCATTCHAN against
> > an inherited network namespace.
> >
> > Require CAP_NET_ADMIN in the user namespace that owns the target network
> > namespace before handling these unattached PPP administrative ioctls.
> >
> > This preserves normal pppd operation in the network namespace it is
> > actually privileged in, while rejecting the userns-only inherited-netns
> > case.
> >
> > Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2")
>
> For fixes, you should set the target tree to "net" in the patch subject,
> using:
>
LGTM as long as it's still possible to start a pppd from within a user
an network namespace.
Regards,
--
Matteo Croce
^ permalink raw reply
* Re: [PATCH net v2 2/3] vsock/test: handle MSG_PEEK in `recv_buf`
From: Stefano Garzarella @ 2026-04-08 10:03 UTC (permalink / raw)
To: Luigi Leonardi
Cc: Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang, Xuan Zhuo,
Eugenio Pérez, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Arseniy Krasnov, kvm, virtualization,
netdev, linux-kernel
In-Reply-To: <20260407-fix_peek-v2-2-2e2581dc8b7c@redhat.com>
On Tue, Apr 07, 2026 at 11:13:56AM +0200, Luigi Leonardi wrote:
>`recv_buf` does not handle the MSG_PEEK flag correctly: it keeps calling
>`recv` until all requested bytes are available or an error occurs.
>
>The problem is how it calculates the amount of bytes read: MSG_PEEK
>doesn't consume any bytes, will re-read the same bytes from the buffer
>head, so, summing the return value every time is wrong.
>
>Moreover, MSG_PEEK doesn't consume the bytes in the buffer, so if the
>requested amount is more than the bytes available, the loop will never
>terminate, because `recv` will never return EOF. For this reason we need
>to compare the amount of read bytes with the number of bytes expected.
>
>Add a check, and if the MSG_PEEK flag is present, update the counter of
>read bytes differently, and break if we read the expected amount.
>
>This allows us to simplify the `test_stream_credit_update_test`, by
>reusing `recv_buf`.
>
>Suggested-by: Stefano Garzarella <sgarzare@redhat.com>
>Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
>---
> tools/testing/vsock/util.c | 8 ++++++++
> tools/testing/vsock/vsock_test.c | 13 +------------
> 2 files changed, 9 insertions(+), 12 deletions(-)
>
>diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c
>index 9430ef5b8bc3..f12425ca99ed 100644
>--- a/tools/testing/vsock/util.c
>+++ b/tools/testing/vsock/util.c
>@@ -399,6 +399,14 @@ void recv_buf(int fd, void *buf, size_t len, int flags, ssize_t expected_ret)
> if (ret == 0 || (ret < 0 && errno != EINTR))
> break;
>
We should add a comment here or even better in the documentation on top
of the function to explain better this behaviour for future reference.
>+ if (flags & MSG_PEEK) {
>+ if (ret == expected_ret) {
>+ nread = ret;
>+ break;
>+ }
Not that I expect this to happen often, but I wonder if it would be
better to add a `timeout_usleep()` here to avoid using up too many CPU
cycles.
>+ continue;
>+ }
>+
> nread += ret;
> } while (nread < len);
> timeout_end();
>diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c
>index 5bd20ccd9335..bdb0754965df 100644
>--- a/tools/testing/vsock/vsock_test.c
>+++ b/tools/testing/vsock/vsock_test.c
>@@ -1500,18 +1500,7 @@ static void test_stream_credit_update_test(const struct test_opts *opts,
> }
>
> /* Wait until there will be 128KB of data in rx queue. */
>- while (1) {
>- ssize_t res;
>-
>- res = recv(fd, buf, buf_size, MSG_PEEK);
>- if (res == buf_size)
>- break;
>-
>- if (res <= 0) {
>- fprintf(stderr, "unexpected 'recv()' return: %zi\n", res);
>- exit(EXIT_FAILURE);
>- }
>- }
>+ recv_buf(fd, buf, buf_size, MSG_PEEK, buf_size);
Not sure about this change in this patch, but since they are just tests
it could be fine.
mmm, on a second thought, we already used recv_buf() with MSG_PEEK in
several other tests, so yep, better to add this change, but I'd make
more clear in the commit title/description that this is at the end a fix
for other tests using MSG_PEEK with recv_buf(), I mean something like
this:
vsock/test: fix MSG_PEEK handling in recv_buf()
And also pointing out that other tests already used MSG_PEEK with
recv_buf(), but it can be broken in some cases.
Thanks,
Stefano
^ permalink raw reply
* [PATCH net v2] net_sched: fix skb memory leak in deferred qdisc drops
From: Fernando Fernandez Mancera @ 2026-04-08 10:00 UTC (permalink / raw)
To: netdev
Cc: horms, pabeni, kuba, edumazet, davem, Fernando Fernandez Mancera,
Damilola Bello
When the network stack cleans up the deferred list via qdisc_run_end(),
it operates on the root qdisc. If the root qdisc do not implement the
TCQ_F_DEQUEUE_DROPS flag the packets queue to free are never freed and
gets stranded on the child's local to_free list.
Fix this by making qdisc_dequeue_drop() aware of the root qdisc. It
fetches the root qdisc and check for the TCQ_F_DEQUEUE_DROPS flag. If
the flag is present, the packet is appended directly to the root's
to_free list. Otherwise, drop it directly as it was done before the
optimization was implemented.
Fixes: a6efc273ab82 ("net_sched: use qdisc_dequeue_drop() in cake, codel, fq_codel")
Reported-by: Damilola Bello <damilola@aterlo.com>
Closes: https://lore.kernel.org/netdev/CAPgFtOLaedBMU0f_BxV2bXftTJSmJr018Q5uozOo5vVo6b9tjw@mail.gmail.com/
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
v2: added RCU read lock protection around root pointer and used root
qdisc to append the packets to free
---
include/net/sch_generic.h | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index c3d657359a3d..5fc0b1ebaf25 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -1170,12 +1170,22 @@ static inline void tcf_kfree_skb_list(struct sk_buff *skb)
static inline void qdisc_dequeue_drop(struct Qdisc *q, struct sk_buff *skb,
enum skb_drop_reason reason)
{
+ struct Qdisc *root;
+
DEBUG_NET_WARN_ON_ONCE(!(q->flags & TCQ_F_DEQUEUE_DROPS));
DEBUG_NET_WARN_ON_ONCE(q->flags & TCQ_F_NOLOCK);
- tcf_set_drop_reason(skb, reason);
- skb->next = q->to_free;
- q->to_free = skb;
+ rcu_read_lock();
+ root = qdisc_root_sleeping(q);
+
+ if (root->flags & TCQ_F_DEQUEUE_DROPS) {
+ tcf_set_drop_reason(skb, reason);
+ skb->next = root->to_free;
+ root->to_free = skb;
+ } else {
+ kfree_skb_reason(skb, reason);
+ }
+ rcu_read_unlock();
}
/* Instead of calling kfree_skb() while root qdisc lock is held,
--
2.53.0
^ permalink raw reply related
* [PATCH 6/8] xfrm_user: fix info leak in build_mapping()
From: Steffen Klassert @ 2026-04-08 9:59 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <20260408095925.253681-1-steffen.klassert@secunet.com>
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
struct xfrm_usersa_id has a one-byte padding hole after the proto
field, which ends up never getting set to zero before copying out to
userspace. Fix that up by zeroing out the whole structure before
setting individual variables.
Fixes: 3a2dfbe8acb1 ("xfrm: Notify changes in UDP encapsulation via netlink")
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_user.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a779590c985a..baa43c325da2 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -4172,6 +4172,7 @@ static int build_mapping(struct sk_buff *skb, struct xfrm_state *x,
um = nlmsg_data(nlh);
+ memset(&um->id, 0, sizeof(um->id));
memcpy(&um->id.daddr, &x->id.daddr, sizeof(um->id.daddr));
um->id.spi = x->id.spi;
um->id.family = x->props.family;
--
2.43.0
^ permalink raw reply related
* [PATCH 3/8] xfrm: Wait for RCU readers during policy netns exit
From: Steffen Klassert @ 2026-04-08 9:58 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <20260408095925.253681-1-steffen.klassert@secunet.com>
xfrm_policy_fini() frees the policy_bydst hash tables after flushing the
policy work items and deleting all policies, but it does not wait for
concurrent RCU readers to leave their read-side critical sections first.
The policy_bydst tables are published via rcu_assign_pointer() and are
looked up through rcu_dereference_check(), so netns teardown must also
wait for an RCU grace period before freeing the table memory.
Fix this by adding synchronize_rcu() before freeing the policy hash tables.
Fixes: e1e551bc5630 ("xfrm: policy: prepare policy_bydst hash for rcu lookups")
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Reviewed-by: Florian Westphal <fw@strlen.de>
---
net/xfrm/xfrm_policy.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 362939aa56cf..8f0188e763c7 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -4290,6 +4290,8 @@ static void xfrm_policy_fini(struct net *net)
#endif
xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false);
+ synchronize_rcu();
+
WARN_ON(!list_empty(&net->xfrm.policy_all));
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
--
2.43.0
^ permalink raw reply related
* [PATCH 8/8] net: af_key: zero aligned sockaddr tail in PF_KEY exports
From: Steffen Klassert @ 2026-04-08 9:59 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <20260408095925.253681-1-steffen.klassert@secunet.com>
From: Zhengchuan Liang <zcliangcn@gmail.com>
PF_KEY export paths use `pfkey_sockaddr_size()` when reserving sockaddr
payload space, so IPv6 addresses occupy 32 bytes on the wire. However,
`pfkey_sockaddr_fill()` initializes only the first 28 bytes of
`struct sockaddr_in6`, leaving the final 4 aligned bytes uninitialized.
Not every PF_KEY message is affected. The state and policy dump builders
already zero the whole message buffer before filling the sockaddr
payloads. Keep the fix to the export paths that still append aligned
sockaddr payloads with plain `skb_put()`:
- `SADB_ACQUIRE`
- `SADB_X_NAT_T_NEW_MAPPING`
- `SADB_X_MIGRATE`
Fix those paths by clearing only the aligned sockaddr tail after
`pfkey_sockaddr_fill()`.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Fixes: 08de61beab8a ("[PFKEYV2]: Extension for dynamic update of endpoint address(es)")
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Co-developed-by: Yuan Tan <yuantan098@gmail.com>
Signed-off-by: Yuan Tan <yuantan098@gmail.com>
Suggested-by: Xin Liu <bird@lzu.edu.cn>
Tested-by: Xiao Liu <lx24@stu.ynu.edu.cn>
Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/key/af_key.c | 52 +++++++++++++++++++++++++++++++-----------------
1 file changed, 34 insertions(+), 18 deletions(-)
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 72ac2ace419d..5d480ae39405 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -757,6 +757,22 @@ static unsigned int pfkey_sockaddr_fill(const xfrm_address_t *xaddr, __be16 port
return 0;
}
+static unsigned int pfkey_sockaddr_fill_zero_tail(const xfrm_address_t *xaddr,
+ __be16 port,
+ struct sockaddr *sa,
+ unsigned short family)
+{
+ unsigned int prefixlen;
+ int sockaddr_len = pfkey_sockaddr_len(family);
+ int sockaddr_size = pfkey_sockaddr_size(family);
+
+ prefixlen = pfkey_sockaddr_fill(xaddr, port, sa, family);
+ if (sockaddr_size > sockaddr_len)
+ memset((u8 *)sa + sockaddr_len, 0, sockaddr_size - sockaddr_len);
+
+ return prefixlen;
+}
+
static struct sk_buff *__pfkey_xfrm_state2msg(const struct xfrm_state *x,
int add_keys, int hsc)
{
@@ -3206,9 +3222,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
addr->sadb_address_prefixlen =
- pfkey_sockaddr_fill(&x->props.saddr, 0,
- (struct sockaddr *) (addr + 1),
- x->props.family);
+ pfkey_sockaddr_fill_zero_tail(&x->props.saddr, 0,
+ (struct sockaddr *)(addr + 1),
+ x->props.family);
if (!addr->sadb_address_prefixlen)
BUG();
@@ -3221,9 +3237,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
addr->sadb_address_prefixlen =
- pfkey_sockaddr_fill(&x->id.daddr, 0,
- (struct sockaddr *) (addr + 1),
- x->props.family);
+ pfkey_sockaddr_fill_zero_tail(&x->id.daddr, 0,
+ (struct sockaddr *)(addr + 1),
+ x->props.family);
if (!addr->sadb_address_prefixlen)
BUG();
@@ -3421,9 +3437,9 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
addr->sadb_address_prefixlen =
- pfkey_sockaddr_fill(&x->props.saddr, 0,
- (struct sockaddr *) (addr + 1),
- x->props.family);
+ pfkey_sockaddr_fill_zero_tail(&x->props.saddr, 0,
+ (struct sockaddr *)(addr + 1),
+ x->props.family);
if (!addr->sadb_address_prefixlen)
BUG();
@@ -3443,9 +3459,9 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
addr->sadb_address_prefixlen =
- pfkey_sockaddr_fill(ipaddr, 0,
- (struct sockaddr *) (addr + 1),
- x->props.family);
+ pfkey_sockaddr_fill_zero_tail(ipaddr, 0,
+ (struct sockaddr *)(addr + 1),
+ x->props.family);
if (!addr->sadb_address_prefixlen)
BUG();
@@ -3474,15 +3490,15 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type,
switch (type) {
case SADB_EXT_ADDRESS_SRC:
addr->sadb_address_prefixlen = sel->prefixlen_s;
- pfkey_sockaddr_fill(&sel->saddr, 0,
- (struct sockaddr *)(addr + 1),
- sel->family);
+ pfkey_sockaddr_fill_zero_tail(&sel->saddr, 0,
+ (struct sockaddr *)(addr + 1),
+ sel->family);
break;
case SADB_EXT_ADDRESS_DST:
addr->sadb_address_prefixlen = sel->prefixlen_d;
- pfkey_sockaddr_fill(&sel->daddr, 0,
- (struct sockaddr *)(addr + 1),
- sel->family);
+ pfkey_sockaddr_fill_zero_tail(&sel->daddr, 0,
+ (struct sockaddr *)(addr + 1),
+ sel->family);
break;
default:
return -EINVAL;
--
2.43.0
^ permalink raw reply related
* [PATCH 1/8] xfrm: clear trailing padding in build_polexpire()
From: Steffen Klassert @ 2026-04-08 9:58 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <20260408095925.253681-1-steffen.klassert@secunet.com>
From: Yasuaki Torimaru <yasuakitorimaru@gmail.com>
build_expire() clears the trailing padding bytes of struct
xfrm_user_expire after setting the hard field via memset_after(),
but the analogous function build_polexpire() does not do this for
struct xfrm_user_polexpire.
The padding bytes after the __u8 hard field are left
uninitialized from the heap allocation, and are then sent to
userspace via netlink multicast to XFRMNLGRP_EXPIRE listeners,
leaking kernel heap memory contents.
Add the missing memset_after() call, matching build_expire().
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Yasuaki Torimaru <yasuakitorimaru@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_user.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 1656b487f833..5d59c11fc01e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -3960,6 +3960,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
return err;
}
upe->hard = !!hard;
+ /* clear the padding bytes */
+ memset_after(upe, 0, hard);
nlmsg_end(skb, nlh);
return 0;
--
2.43.0
^ permalink raw reply related
* [PATCH 2/8] xfrm: account XFRMA_IF_ID in aevent size calculation
From: Steffen Klassert @ 2026-04-08 9:58 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <20260408095925.253681-1-steffen.klassert@secunet.com>
From: Keenan Dong <keenanat2000@gmail.com>
xfrm_get_ae() allocates the reply skb with xfrm_aevent_msgsize(), then
build_aevent() appends attributes including XFRMA_IF_ID when x->if_id is
set.
xfrm_aevent_msgsize() does not include space for XFRMA_IF_ID. For states
with if_id, build_aevent() can fail with -EMSGSIZE and hit BUG_ON(err < 0)
in xfrm_get_ae(), turning a malformed netlink interaction into a kernel
panic.
Account XFRMA_IF_ID in the size calculation unconditionally and replace
the BUG_ON with normal error unwinding.
Fixes: 7e6526404ade ("xfrm: Add a new lookup key to match xfrm interfaces.")
Reported-by: Keenan Dong <keenanat2000@gmail.com>
Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_user.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 5d59c11fc01e..a779590c985a 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2677,7 +2677,8 @@ static inline unsigned int xfrm_aevent_msgsize(struct xfrm_state *x)
+ nla_total_size(4) /* XFRM_AE_RTHR */
+ nla_total_size(4) /* XFRM_AE_ETHR */
+ nla_total_size(sizeof(x->dir)) /* XFRMA_SA_DIR */
- + nla_total_size(4); /* XFRMA_SA_PCPU */
+ + nla_total_size(4) /* XFRMA_SA_PCPU */
+ + nla_total_size(sizeof(x->if_id)); /* XFRMA_IF_ID */
}
static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
@@ -2789,7 +2790,12 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
c.portid = nlh->nlmsg_pid;
err = build_aevent(r_skb, x, &c);
- BUG_ON(err < 0);
+ if (err < 0) {
+ spin_unlock_bh(&x->lock);
+ xfrm_state_put(x);
+ kfree_skb(r_skb);
+ return err;
+ }
err = nlmsg_unicast(xfrm_net_nlsk(net, skb), r_skb, NETLINK_CB(skb).portid);
spin_unlock_bh(&x->lock);
--
2.43.0
^ permalink raw reply related
* [PATCH 5/8] xfrm: fix refcount leak in xfrm_migrate_policy_find
From: Steffen Klassert @ 2026-04-08 9:59 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <20260408095925.253681-1-steffen.klassert@secunet.com>
From: Kotlyarov Mihail <mihailkotlyarow@gmail.com>
syzkaller reported a memory leak in xfrm_policy_alloc:
BUG: memory leak
unreferenced object 0xffff888114d79000 (size 1024):
comm "syz.1.17", pid 931
...
xfrm_policy_alloc+0xb3/0x4b0 net/xfrm/xfrm_policy.c:432
The root cause is a double call to xfrm_pol_hold_rcu() in
xfrm_migrate_policy_find(). The lookup function already returns
a policy with held reference, making the second call redundant.
Remove the redundant xfrm_pol_hold_rcu() call to fix the refcount
imbalance and prevent the memory leak.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Fixes: 563d5ca93e88 ("xfrm: switch migrate to xfrm_policy_lookup_bytype")
Signed-off-by: Kotlyarov Mihail <mihailkotlyarow@gmail.com>
Reviewed-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_policy.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 8f0188e763c7..a872af5610dc 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -4528,9 +4528,6 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
pol = xfrm_policy_lookup_bytype(net, type, &fl, sel->family, dir, if_id);
if (IS_ERR_OR_NULL(pol))
goto out_unlock;
-
- if (!xfrm_pol_hold_rcu(pol))
- pol = NULL;
out_unlock:
rcu_read_unlock();
return pol;
--
2.43.0
^ permalink raw reply related
* [PATCH 4/8] xfrm: hold dev ref until after transport_finish NF_HOOK
From: Steffen Klassert @ 2026-04-08 9:59 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <20260408095925.253681-1-steffen.klassert@secunet.com>
From: Qi Tang <tpluszz77@gmail.com>
After async crypto completes, xfrm_input_resume() calls dev_put()
immediately on re-entry before the skb reaches transport_finish.
The skb->dev pointer is then used inside NF_HOOK and its okfn,
which can race with device teardown.
Remove the dev_put from the async resumption entry and instead
drop the reference after the NF_HOOK call in transport_finish,
using a saved device pointer since NF_HOOK may consume the skb.
This covers NF_DROP, NF_QUEUE and NF_STOLEN paths that skip
the okfn.
For non-transport exits (decaps, gro, drop) and secondary
async return points, release the reference inline when
async is set.
Suggested-by: Florian Westphal <fw@strlen.de>
Fixes: acf568ee859f ("xfrm: Reinject transport-mode packets through tasklet")
Cc: stable@vger.kernel.org
Signed-off-by: Qi Tang <tpluszz77@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/ipv4/xfrm4_input.c | 5 ++++-
net/ipv6/xfrm6_input.c | 5 ++++-
net/xfrm/xfrm_input.c | 18 ++++++++++++++----
3 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index f28cfd88eaf5..c2eac844bcdb 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -50,6 +50,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
{
struct xfrm_offload *xo = xfrm_offload(skb);
struct iphdr *iph = ip_hdr(skb);
+ struct net_device *dev = skb->dev;
iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
@@ -73,8 +74,10 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
}
NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
- dev_net(skb->dev), NULL, skb, skb->dev, NULL,
+ dev_net(dev), NULL, skb, dev, NULL,
xfrm4_rcv_encap_finish);
+ if (async)
+ dev_put(dev);
return 0;
}
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 9005fc156a20..699a001ac166 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -43,6 +43,7 @@ static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
int xfrm6_transport_finish(struct sk_buff *skb, int async)
{
struct xfrm_offload *xo = xfrm_offload(skb);
+ struct net_device *dev = skb->dev;
int nhlen = -skb_network_offset(skb);
skb_network_header(skb)[IP6CB(skb)->nhoff] =
@@ -68,8 +69,10 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
}
NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
- dev_net(skb->dev), NULL, skb, skb->dev, NULL,
+ dev_net(dev), NULL, skb, dev, NULL,
xfrm6_transport_finish2);
+ if (async)
+ dev_put(dev);
return 0;
}
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index dc1312ed5a09..f65291eba1f6 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -506,7 +506,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
/* An encap_type of -1 indicates async resumption. */
if (encap_type == -1) {
async = 1;
- dev_put(skb->dev);
seq = XFRM_SKB_CB(skb)->seq.input.low;
spin_lock(&x->lock);
goto resume;
@@ -659,8 +658,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
dev_hold(skb->dev);
nexthdr = x->type->input(x, skb);
- if (nexthdr == -EINPROGRESS)
+ if (nexthdr == -EINPROGRESS) {
+ if (async)
+ dev_put(skb->dev);
return 0;
+ }
dev_put(skb->dev);
spin_lock(&x->lock);
@@ -695,9 +697,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
err = xfrm_inner_mode_input(x, skb);
- if (err == -EINPROGRESS)
+ if (err == -EINPROGRESS) {
+ if (async)
+ dev_put(skb->dev);
return 0;
- else if (err) {
+ } else if (err) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
goto drop;
}
@@ -734,6 +738,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
sp->olen = 0;
if (skb_valid_dst(skb))
skb_dst_drop(skb);
+ if (async)
+ dev_put(skb->dev);
gro_cells_receive(&gro_cells, skb);
return 0;
} else {
@@ -753,6 +759,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
sp->olen = 0;
if (skb_valid_dst(skb))
skb_dst_drop(skb);
+ if (async)
+ dev_put(skb->dev);
gro_cells_receive(&gro_cells, skb);
return err;
}
@@ -763,6 +771,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
drop_unlock:
spin_unlock(&x->lock);
drop:
+ if (async)
+ dev_put(skb->dev);
xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
kfree_skb(skb);
return 0;
--
2.43.0
^ permalink raw reply related
* [PATCH 7/8] xfrm_user: fix info leak in build_report()
From: Steffen Klassert @ 2026-04-08 9:59 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <20260408095925.253681-1-steffen.klassert@secunet.com>
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
struct xfrm_user_report is a __u8 proto field followed by a struct
xfrm_selector which means there is three "empty" bytes of padding, but
the padding is never zeroed before copying to userspace. Fix that up by
zeroing the structure before setting individual member variables.
Cc: stable <stable@kernel.org>
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_user.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index baa43c325da2..d56450f61669 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -4125,6 +4125,7 @@ static int build_report(struct sk_buff *skb, u8 proto,
return -EMSGSIZE;
ur = nlmsg_data(nlh);
+ memset(ur, 0, sizeof(*ur));
ur->proto = proto;
memcpy(&ur->sel, sel, sizeof(ur->sel));
--
2.43.0
^ permalink raw reply related
* [PATCH 0/8] pull request (net): ipsec 2026-04-08
From: Steffen Klassert @ 2026-04-08 9:58 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: Herbert Xu, Steffen Klassert, netdev
1) Clear trailing padding in build_polexpire() to prevent
leaking unititialized memory. From Yasuaki Torimaru.
2) Fix aevent size calculation when XFRMA_IF_ID is used.
From Keenan Dong.
3) Wait for RCU readers during policy netns exit before
freeing the policy hash tables.
4) Fix dome too eaerly dropped references on the netdev
when uding transport mode. From Qi Tang.
5) Fix refcount leak in xfrm_migrate_policy_find().
From Kotlyarov Mihail.
6) Fix two fix info leaks in build_report() and
in build_mapping(). From Greg Kroah-Hartman.
7) Zero aligned sockaddr tail in PF_KEY exports.
From Zhengchuan Liang.
Please pull or let me know if there are problems.
Thanks!
The following changes since commit c4ea7d8907cf72b259bf70bd8c2e791e1c4ff70f:
net: mana: fix use-after-free in add_adev() error path (2026-03-24 21:07:58 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git tags/ipsec-2026-04-08
for you to fetch changes up to 426c355742f02cf743b347d9d7dbdc1bfbfa31ef:
net: af_key: zero aligned sockaddr tail in PF_KEY exports (2026-04-07 11:08:24 +0200)
----------------------------------------------------------------
ipsec-2026-04-08
----------------------------------------------------------------
Greg Kroah-Hartman (2):
xfrm_user: fix info leak in build_mapping()
xfrm_user: fix info leak in build_report()
Keenan Dong (1):
xfrm: account XFRMA_IF_ID in aevent size calculation
Kotlyarov Mihail (1):
xfrm: fix refcount leak in xfrm_migrate_policy_find
Qi Tang (1):
xfrm: hold dev ref until after transport_finish NF_HOOK
Steffen Klassert (1):
xfrm: Wait for RCU readers during policy netns exit
Yasuaki Torimaru (1):
xfrm: clear trailing padding in build_polexpire()
Zhengchuan Liang (1):
net: af_key: zero aligned sockaddr tail in PF_KEY exports
net/ipv4/xfrm4_input.c | 5 ++++-
net/ipv6/xfrm6_input.c | 5 ++++-
net/key/af_key.c | 52 +++++++++++++++++++++++++++++++++-----------------
net/xfrm/xfrm_input.c | 18 +++++++++++++----
net/xfrm/xfrm_policy.c | 5 ++---
net/xfrm/xfrm_user.c | 14 ++++++++++++--
6 files changed, 70 insertions(+), 29 deletions(-)
^ permalink raw reply
* Re: [PATCH net-next 00/10] net: lan966x: add support for PCIe FDMA
From: Herve Codina @ 2026-04-08 9:51 UTC (permalink / raw)
To: Daniel Machon
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Horatiu Vultur, Steen Hegelund, UNGLinuxDriver,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev, Arnd Bergmann,
Greg Kroah-Hartman, netdev, linux-kernel, bpf
In-Reply-To: <20260407132016.4cfivs24ljqneyu7@DEN-DL-M70577>
Hi Daniel,
On Tue, 7 Apr 2026 15:20:16 +0200
Daniel Machon <daniel.machon@microchip.com> wrote:
...
>
> The following diff should fix the FDMA traffic issue, and the FDMA error splat,
> when reloading the lan966x-pci driver, by:
>
> 1. Resetting the FDMA engine on PCI init()
>
> 2. Clearing any rogue FDMA errors that may latch due to the soft reset by the
> reset driver.
>
> diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma_pci.c
> b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma_pci.c
> --- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma_pci.c
> +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma_pci.c
> @@ -372,6 +372,9 @@ static int lan966x_fdma_pci_init(struct lan966x *lan966x)
> if (!lan966x->fdma)
> return 0;
>
> + lan_wr(FDMA_CTRL_NRESET_SET(0), lan966x, FDMA_CTRL);
> + lan_wr(FDMA_CTRL_NRESET_SET(1), lan966x, FDMA_CTRL);
> +
> fdma_pci_atu_init(&lan966x->atu, lan966x->regs[TARGET_PCIE_DBI]);
>
> lan966x->rx.lan966x = lan966x;
> diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
> b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
> --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
> +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
> @@ -1071,6 +1071,15 @@ static int lan966x_reset_switch(struct lan966x *lan966x)
>
> reset_control_reset(switch_reset);
>
> + /* When in PCI mode, the GCB soft reset issued by the reset
> + * controller can latch spurious bits in the FDMA error stickies.
> + * Clear them before request_irq hooks up the FDMA IRQ line,
> + * otherwise the handler fires immediately on probe.
> + */
> + lan_wr(lan_rd(lan966x, FDMA_ERRORS), lan966x, FDMA_ERRORS);
> + lan_wr(lan_rd(lan966x, FDMA_INTR_ERR), lan966x, FDMA_INTR_ERR);
> + lan_wr(lan_rd(lan966x, FDMA_INTR_DB), lan966x, FDMA_INTR_DB);
> +
> /* Don't reinitialize the switch core, if it is already initialized. In
> * case it is initialized twice, some pointers inside the queue system
> * in HW will get corrupted and then after a while the queue system gets
> diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
> b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
> --- a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
> +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
> @@ -1010,6 +1010,15 @@ enum lan966x_target {
> #define FDMA_CH_CFG_CH_MEM_GET(x)\
> FIELD_GET(FDMA_CH_CFG_CH_MEM, x)
>
> +/* FDMA:FDMA:FDMA_CTRL */
> +#define FDMA_CTRL __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 424, 0, 1, 4)
> +
> +#define FDMA_CTRL_NRESET BIT(0)
> +#define FDMA_CTRL_NRESET_SET(x)\
> + FIELD_PREP(FDMA_CTRL_NRESET, x)
> +#define FDMA_CTRL_NRESET_GET(x)\
> + FIELD_GET(FDMA_CTRL_NRESET, x)
> +
> /* FDMA:FDMA:FDMA_PORT_CTRL */
> #define FDMA_PORT_CTRL(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 376, r, 2, 4)
>
> Let me know if it works on your end.
>
> (Btw. I have noticed another issue where TX stops working on lan966x-pci reload.
> It happens more rarely, but is unrelated to this patch series, as it also
> happens in register-based INJ/XTR mode. Whenever that happens, you will see
> "Flush timeout chip port" in the logs. This should also be fixed, but sent as a
> separate fix commit, I believe.)
>
I have tested your proposed modification.
- From a cold boot, module unloading / re-loading:
Tested Ok
- From a cold boot, module loading / no interface configuration / reboot:
Tested Ok
- From a cold boot, module loading / interface configuration / reboot:
Issue present.
- From a cold boot, module loading / interface configuration / module unloading / reboot:
Tested Ok.
The interface configuration was the following command:
ip link set eth2 up && ip addr add 192.168.32.20/16 dev eth2
With the interface configured and without unloading the lan966x_pci module
before the reboot, I have the already known FDMA error splat after the
reboot:
[ 18.908397] ------------[ cut here ]------------
[ 18.913226] Unexpected error: 64, error_type: 1073741824
[ 18.918704] WARNING: drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c:558 at lan966x_fdma_irq_handler+0xe0/0x12c [lan966x_switch], CPU#0: kworker/u8:2/38
...
The issue is not present if I unload the lan966x_pci module before the
reboot. This let me think that something has been cleaned by the module
unloading.
On top of your proposed modification, I use the shutdown() hook in the
lan966x_driver:
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -1326,9 +1326,18 @@ static void lan966x_remove(struct platform_device *pdev)
debugfs_remove_recursive(lan966x->debugfs_root);
}
+static void lan966x_shutdown(struct platform_device *pdev)
+{
+ struct lan966x *lan966x = platform_get_drvdata(pdev);
+
+ lan966x->ops->fdma_deinit(lan966x);
+}
+
static struct platform_driver lan966x_driver = {
.probe = lan966x_probe,
.remove = lan966x_remove,
+ .shutdown = lan966x_shutdown,
.driver = {
.name = "lan966x-switch",
.of_match_table = lan966x_match,
With that done, the issue is no more present.
I am not sure that this is a correct fix but it can give some clues.
Feel free to ask for more tests or more details if you need to.
Best regards,
Hervé
^ permalink raw reply
* Re: [PATCH v5 net-next 4/8] dpll: zl3073x: allow SyncE_Ref pin state change
From: Ivan Vecera @ 2026-04-08 9:44 UTC (permalink / raw)
To: Grzegorz Nitka, netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, jiri, arkadiusz.kubalewski, vadim.fedorenko,
donald.hunter, horms, pabeni, kuba, davem, edumazet,
Aleksandr Loktionov
In-Reply-To: <20260402230626.3826719-5-grzegorz.nitka@intel.com>
On 4/3/26 1:06 AM, Grzegorz Nitka wrote:
> The SyncE_Ref pin may operate as either an active or inactive reference
> depending on board design and system configuration. Some platforms need
> to disable the SyncE reference dynamically (e.g., when selecting a
> different recovered clock input). The hardware supports toggling this
> pin, therefore advertise the STATE_CAN_CHANGE capability.
>
> Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
> ---
> drivers/dpll/zl3073x/prop.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c
> index ac9d41d0f978..acd7061a741a 100644
> --- a/drivers/dpll/zl3073x/prop.c
> +++ b/drivers/dpll/zl3073x/prop.c
> @@ -215,6 +215,15 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
>
> props->dpll_props.type = DPLL_PIN_TYPE_GNSS;
>
> + /*
> + * The SyncE_Ref pin supports enabling/disabling dynamically.
> + * Some platforms may choose to expose this through firmware
> + * configuration later. For now, advertise this capability
> + * universally since the hardware allows state toggling.
> + */
> + props->dpll_props.capabilities |=
> + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
> +
> /* The output pin phase adjustment granularity equals half of
> * the synth frequency count.
> */
Reviewed-by: Ivan Vecera <ivecera@redhat.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox