genetlink: piggy back on resv_op to default to a reject policy
authorJakub Kicinski <kuba@kernel.org>
Fri, 21 Oct 2022 19:35:32 +0000 (12:35 -0700)
committerJakub Kicinski <kuba@kernel.org>
Tue, 25 Oct 2022 02:08:46 +0000 (19:08 -0700)
To keep backward compatibility we used to leave attribute parsing
to the family if no policy is specified. This becomes tedious as
we move to more strict validation. Families must define reject all
policies if they don't want any attributes accepted.

Piggy back on the resv_start_op field as the switchover point.
AFAICT only ethtool has added new commands since the resv_start_op
was defined, and it has per-op policies so this should be a no-op.

Nonetheless the patch should still go into v6.1 for consistency.

Link: https://lore.kernel.org/all/20221019125745.3f2e7659@kernel.org/
Link: https://lore.kernel.org/r/20221021193532.1511293-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/genetlink.h
net/netlink/genetlink.c

index 3d08e67..9f97f73 100644 (file)
@@ -41,13 +41,21 @@ struct genl_info;
  * @mcgrps: multicast groups used by this family
  * @n_mcgrps: number of multicast groups
  * @resv_start_op: first operation for which reserved fields of the header
- *     can be validated, new families should leave this field at zero
+ *     can be validated and policies are required (see below);
+ *     new families should leave this field at zero
  * @mcgrp_offset: starting number of multicast group IDs in this family
  *     (private)
  * @ops: the operations supported by this family
  * @n_ops: number of operations supported by this family
  * @small_ops: the small-struct operations supported by this family
  * @n_small_ops: number of small-struct operations supported by this family
+ *
+ * Attribute policies (the combination of @policy and @maxattr fields)
+ * can be attached at the family level or at the operation level.
+ * If both are present the per-operation policy takes precedence.
+ * For operations before @resv_start_op lack of policy means that the core
+ * will perform no attribute parsing or validation. For newer operations
+ * if policy is not provided core will reject all TLV attributes.
  */
 struct genl_family {
        int                     id;             /* private */
index 39b7c00..b1fd059 100644 (file)
@@ -78,10 +78,29 @@ static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) |
 static unsigned long *mc_groups = &mc_group_start;
 static unsigned long mc_groups_longs = 1;
 
+/* We need the last attribute with non-zero ID therefore a 2-entry array */
+static struct nla_policy genl_policy_reject_all[] = {
+       { .type = NLA_REJECT },
+       { .type = NLA_REJECT },
+};
+
 static int genl_ctrl_event(int event, const struct genl_family *family,
                           const struct genl_multicast_group *grp,
                           int grp_id);
 
+static void
+genl_op_fill_in_reject_policy(const struct genl_family *family,
+                             struct genl_ops *op)
+{
+       BUILD_BUG_ON(ARRAY_SIZE(genl_policy_reject_all) - 1 != 1);
+
+       if (op->policy || op->cmd < family->resv_start_op)
+               return;
+
+       op->policy = genl_policy_reject_all;
+       op->maxattr = 1;
+}
+
 static const struct genl_family *genl_family_find_byid(unsigned int id)
 {
        return idr_find(&genl_fam_idr, id);
@@ -113,6 +132,8 @@ static void genl_op_from_full(const struct genl_family *family,
                op->maxattr = family->maxattr;
        if (!op->policy)
                op->policy = family->policy;
+
+       genl_op_fill_in_reject_policy(family, op);
 }
 
 static int genl_get_cmd_full(u32 cmd, const struct genl_family *family,
@@ -142,6 +163,8 @@ static void genl_op_from_small(const struct genl_family *family,
 
        op->maxattr = family->maxattr;
        op->policy = family->policy;
+
+       genl_op_fill_in_reject_policy(family, op);
 }
 
 static int genl_get_cmd_small(u32 cmd, const struct genl_family *family,