diff options
author | Johannes Berg <johannes.berg@intel.com> | 2018-09-26 05:15:32 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-09-28 13:24:39 -0400 |
commit | c29f1845b2b22974411278bad3a2ac0b7815dfb4 (patch) | |
tree | 068b778699737fdf5bc184913423daa334412c1a /lib/nlattr.c | |
parent | 48fde90a78f8c67e2bec5061f9725fe363519feb (diff) |
netlink: move extack setting into validate_nla()
This unifies the code between nla_parse() which sets the bad
attribute pointer and an error message, and nla_validate()
which only sets the bad attribute pointer.
It also cleans up the code for NLA_REJECT and paves the way
for nested policy validation, as it will allow us to easily
skip setting the "generic" message without any extra args
like the **error_msg now, just passing the extack through is
now enough.
While at it, remove the unnecessary label in nla_parse().
Suggested-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib/nlattr.c')
-rw-r--r-- | lib/nlattr.c | 68 |
1 files changed, 36 insertions, 32 deletions
diff --git a/lib/nlattr.c b/lib/nlattr.c index e2e5b38394d5..6e03d650bec4 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c | |||
@@ -69,10 +69,11 @@ static int validate_nla_bitfield32(const struct nlattr *nla, | |||
69 | 69 | ||
70 | static int validate_nla(const struct nlattr *nla, int maxtype, | 70 | static int validate_nla(const struct nlattr *nla, int maxtype, |
71 | const struct nla_policy *policy, | 71 | const struct nla_policy *policy, |
72 | const char **error_msg) | 72 | struct netlink_ext_ack *extack) |
73 | { | 73 | { |
74 | const struct nla_policy *pt; | 74 | const struct nla_policy *pt; |
75 | int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); | 75 | int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); |
76 | int err = -ERANGE; | ||
76 | 77 | ||
77 | if (type <= 0 || type > maxtype) | 78 | if (type <= 0 || type > maxtype) |
78 | return 0; | 79 | return 0; |
@@ -90,24 +91,31 @@ static int validate_nla(const struct nlattr *nla, int maxtype, | |||
90 | switch (pt->type) { | 91 | switch (pt->type) { |
91 | case NLA_EXACT_LEN: | 92 | case NLA_EXACT_LEN: |
92 | if (attrlen != pt->len) | 93 | if (attrlen != pt->len) |
93 | return -ERANGE; | 94 | goto out_err; |
94 | break; | 95 | break; |
95 | 96 | ||
96 | case NLA_REJECT: | 97 | case NLA_REJECT: |
97 | if (pt->validation_data && error_msg) | 98 | if (extack && pt->validation_data) { |
98 | *error_msg = pt->validation_data; | 99 | NL_SET_BAD_ATTR(extack, nla); |
99 | return -EINVAL; | 100 | extack->_msg = pt->validation_data; |
101 | return -EINVAL; | ||
102 | } | ||
103 | err = -EINVAL; | ||
104 | goto out_err; | ||
100 | 105 | ||
101 | case NLA_FLAG: | 106 | case NLA_FLAG: |
102 | if (attrlen > 0) | 107 | if (attrlen > 0) |
103 | return -ERANGE; | 108 | goto out_err; |
104 | break; | 109 | break; |
105 | 110 | ||
106 | case NLA_BITFIELD32: | 111 | case NLA_BITFIELD32: |
107 | if (attrlen != sizeof(struct nla_bitfield32)) | 112 | if (attrlen != sizeof(struct nla_bitfield32)) |
108 | return -ERANGE; | 113 | goto out_err; |
109 | 114 | ||
110 | return validate_nla_bitfield32(nla, pt->validation_data); | 115 | err = validate_nla_bitfield32(nla, pt->validation_data); |
116 | if (err) | ||
117 | goto out_err; | ||
118 | break; | ||
111 | 119 | ||
112 | case NLA_NUL_STRING: | 120 | case NLA_NUL_STRING: |
113 | if (pt->len) | 121 | if (pt->len) |
@@ -115,13 +123,15 @@ static int validate_nla(const struct nlattr *nla, int maxtype, | |||
115 | else | 123 | else |
116 | minlen = attrlen; | 124 | minlen = attrlen; |
117 | 125 | ||
118 | if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) | 126 | if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) { |
119 | return -EINVAL; | 127 | err = -EINVAL; |
128 | goto out_err; | ||
129 | } | ||
120 | /* fall through */ | 130 | /* fall through */ |
121 | 131 | ||
122 | case NLA_STRING: | 132 | case NLA_STRING: |
123 | if (attrlen < 1) | 133 | if (attrlen < 1) |
124 | return -ERANGE; | 134 | goto out_err; |
125 | 135 | ||
126 | if (pt->len) { | 136 | if (pt->len) { |
127 | char *buf = nla_data(nla); | 137 | char *buf = nla_data(nla); |
@@ -130,13 +140,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype, | |||
130 | attrlen--; | 140 | attrlen--; |
131 | 141 | ||
132 | if (attrlen > pt->len) | 142 | if (attrlen > pt->len) |
133 | return -ERANGE; | 143 | goto out_err; |
134 | } | 144 | } |
135 | break; | 145 | break; |
136 | 146 | ||
137 | case NLA_BINARY: | 147 | case NLA_BINARY: |
138 | if (pt->len && attrlen > pt->len) | 148 | if (pt->len && attrlen > pt->len) |
139 | return -ERANGE; | 149 | goto out_err; |
140 | break; | 150 | break; |
141 | 151 | ||
142 | case NLA_NESTED: | 152 | case NLA_NESTED: |
@@ -152,10 +162,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype, | |||
152 | minlen = nla_attr_minlen[pt->type]; | 162 | minlen = nla_attr_minlen[pt->type]; |
153 | 163 | ||
154 | if (attrlen < minlen) | 164 | if (attrlen < minlen) |
155 | return -ERANGE; | 165 | goto out_err; |
156 | } | 166 | } |
157 | 167 | ||
158 | return 0; | 168 | return 0; |
169 | out_err: | ||
170 | NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation"); | ||
171 | return err; | ||
159 | } | 172 | } |
160 | 173 | ||
161 | /** | 174 | /** |
@@ -180,12 +193,10 @@ int nla_validate(const struct nlattr *head, int len, int maxtype, | |||
180 | int rem; | 193 | int rem; |
181 | 194 | ||
182 | nla_for_each_attr(nla, head, len, rem) { | 195 | nla_for_each_attr(nla, head, len, rem) { |
183 | int err = validate_nla(nla, maxtype, policy, NULL); | 196 | int err = validate_nla(nla, maxtype, policy, extack); |
184 | 197 | ||
185 | if (err < 0) { | 198 | if (err < 0) |
186 | NL_SET_BAD_ATTR(extack, nla); | ||
187 | return err; | 199 | return err; |
188 | } | ||
189 | } | 200 | } |
190 | 201 | ||
191 | return 0; | 202 | return 0; |
@@ -241,7 +252,7 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, | |||
241 | struct netlink_ext_ack *extack) | 252 | struct netlink_ext_ack *extack) |
242 | { | 253 | { |
243 | const struct nlattr *nla; | 254 | const struct nlattr *nla; |
244 | int rem, err; | 255 | int rem; |
245 | 256 | ||
246 | memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); | 257 | memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); |
247 | 258 | ||
@@ -249,17 +260,12 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, | |||
249 | u16 type = nla_type(nla); | 260 | u16 type = nla_type(nla); |
250 | 261 | ||
251 | if (type > 0 && type <= maxtype) { | 262 | if (type > 0 && type <= maxtype) { |
252 | static const char _msg[] = "Attribute failed policy validation"; | ||
253 | const char *msg = _msg; | ||
254 | |||
255 | if (policy) { | 263 | if (policy) { |
256 | err = validate_nla(nla, maxtype, policy, &msg); | 264 | int err = validate_nla(nla, maxtype, policy, |
257 | if (err < 0) { | 265 | extack); |
258 | NL_SET_BAD_ATTR(extack, nla); | 266 | |
259 | if (extack) | 267 | if (err < 0) |
260 | extack->_msg = msg; | 268 | return err; |
261 | goto errout; | ||
262 | } | ||
263 | } | 269 | } |
264 | 270 | ||
265 | tb[type] = (struct nlattr *)nla; | 271 | tb[type] = (struct nlattr *)nla; |
@@ -270,9 +276,7 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, | |||
270 | pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n", | 276 | pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n", |
271 | rem, current->comm); | 277 | rem, current->comm); |
272 | 278 | ||
273 | err = 0; | 279 | return 0; |
274 | errout: | ||
275 | return err; | ||
276 | } | 280 | } |
277 | EXPORT_SYMBOL(nla_parse); | 281 | EXPORT_SYMBOL(nla_parse); |
278 | 282 | ||