From: Johannes Berg <johannes.b...@intel.com>

In one of my previous patches in this area I introduced code
to pass out just the error message to store in the extack, for
use in NLA_REJECT.

Change this code now to set both the error message and the bad
attribute pointer, and carry around a boolean indicating that
the values have been set.

This will be used in the next patch to allow recursive validation
of nested policies, while preserving the innermost error message
rather than overwriting it with a generic out-level message.

Signed-off-by: Johannes Berg <johannes.b...@intel.com>
---
 lib/nlattr.c | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/lib/nlattr.c b/lib/nlattr.c
index 46a6d79cf2d1..fecc7b834706 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -70,7 +70,7 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
 
 static int validate_nla(const struct nlattr *nla, int maxtype,
                        const struct nla_policy *policy,
-                       const char **error_msg)
+                       struct netlink_ext_ack *extack, bool *extack_set)
 {
        const struct nla_policy *pt;
        int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla);
@@ -95,8 +95,11 @@ static int validate_nla(const struct nlattr *nla, int 
maxtype,
                break;
 
        case NLA_REJECT:
-               if (pt->validation_data && error_msg)
-                       *error_msg = pt->validation_data;
+               if (pt->validation_data && extack && !*extack_set) {
+                       *extack_set = true;
+                       extack->_msg = pt->validation_data;
+                       NL_SET_BAD_ATTR(extack, nla);
+               }
                return -EINVAL;
 
        case NLA_FLAG:
@@ -161,24 +164,25 @@ static int validate_nla(const struct nlattr *nla, int 
maxtype,
 
 static int nla_validate_parse(const struct nlattr *head, int len, int maxtype,
                              const struct nla_policy *policy,
-                             struct netlink_ext_ack *extack,
+                             struct netlink_ext_ack *extack, bool *extack_set,
                              struct nlattr **tb)
 {
        const struct nlattr *nla;
        int rem;
 
        nla_for_each_attr(nla, head, len, rem) {
-               static const char _msg[] = "Attribute failed policy validation";
-               const char *msg = _msg;
                u16 type = nla_type(nla);
 
                if (policy) {
-                       int err = validate_nla(nla, maxtype, policy, &msg);
+                       int err = validate_nla(nla, maxtype, policy,
+                                              extack, extack_set);
 
                        if (err < 0) {
-                               if (extack)
-                                       extack->_msg = msg;
-                               NL_SET_BAD_ATTR(extack, nla);
+                               if (!*extack_set) {
+                                       *extack_set = true;
+                                       NL_SET_ERR_MSG_ATTR(extack, nla,
+                                                           "Attribute failed 
policy validation");
+                               }
                                return err;
                        }
                }
@@ -208,9 +212,11 @@ int nla_validate(const struct nlattr *head, int len, int 
maxtype,
                 const struct nla_policy *policy,
                 struct netlink_ext_ack *extack)
 {
+       bool extack_set = false;
        int rem;
 
-       rem = nla_validate_parse(head, len, maxtype, policy, extack, NULL);
+       rem = nla_validate_parse(head, len, maxtype, policy,
+                                extack, &extack_set, NULL);
 
        if (rem < 0)
                return rem;
@@ -267,11 +273,13 @@ int nla_parse(struct nlattr **tb, int maxtype, const 
struct nlattr *head,
              int len, const struct nla_policy *policy,
              struct netlink_ext_ack *extack)
 {
+       bool extack_set = false;
        int rem;
 
        memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
 
-       rem = nla_validate_parse(head, len, maxtype, policy, extack, tb);
+       rem = nla_validate_parse(head, len, maxtype, policy,
+                                extack, &extack_set, tb);
        if (rem < 0)
                return rem;
 
-- 
2.14.4

Reply via email to