Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ovpn: reject unexpected netlink attributes

Netlink ops do not expect all attributes to be always set, however
this condition is not explicitly coded any where, leading the user
to believe that all sent attributes are somewhat processed.

Fix this behaviour by introducing explicit checks.

For CMD_OVPN_PEER_GET and CMD_OVPN_KEY_GET directly open-code the
needed condition in the related ops handlers.
While for all other ops use attribute subsets in the ovpn.yaml spec file.

Fixes: b7a63391aa98 ("ovpn: add basic netlink support")
Reported-by: Ralf Lici <ralf@mandelbit.com>
Closes: https://github.com/OpenVPN/ovpn-net-next/issues/19
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>

+251 -20
+147 -6
Documentation/netlink/specs/ovpn.yaml
··· 161 161 type: uint 162 162 doc: Number of packets transmitted at the transport level 163 163 - 164 + name: peer-new-input 165 + subset-of: peer 166 + attributes: 167 + - 168 + name: id 169 + - 170 + name: remote-ipv4 171 + - 172 + name: remote-ipv6 173 + - 174 + name: remote-ipv6-scope-id 175 + - 176 + name: remote-port 177 + - 178 + name: socket 179 + - 180 + name: vpn-ipv4 181 + - 182 + name: vpn-ipv6 183 + - 184 + name: local-ipv4 185 + - 186 + name: local-ipv6 187 + - 188 + name: keepalive-interval 189 + - 190 + name: keepalive-timeout 191 + - 192 + name: peer-set-input 193 + subset-of: peer 194 + attributes: 195 + - 196 + name: id 197 + - 198 + name: remote-ipv4 199 + - 200 + name: remote-ipv6 201 + - 202 + name: remote-ipv6-scope-id 203 + - 204 + name: remote-port 205 + - 206 + name: vpn-ipv4 207 + - 208 + name: vpn-ipv6 209 + - 210 + name: local-ipv4 211 + - 212 + name: local-ipv6 213 + - 214 + name: keepalive-interval 215 + - 216 + name: keepalive-timeout 217 + - 218 + name: peer-del-input 219 + subset-of: peer 220 + attributes: 221 + - 222 + name: id 223 + - 164 224 name: keyconf 165 225 attributes: 166 226 - ··· 276 216 obtain the actual cipher IV 277 217 checks: 278 218 exact-len: nonce-tail-size 219 + 220 + - 221 + name: keyconf-get 222 + subset-of: keyconf 223 + attributes: 224 + - 225 + name: peer-id 226 + - 227 + name: slot 228 + - 229 + name: key-id 230 + - 231 + name: cipher-alg 232 + - 233 + name: keyconf-swap-input 234 + subset-of: keyconf 235 + attributes: 236 + - 237 + name: peer-id 238 + - 239 + name: keyconf-del-input 240 + subset-of: keyconf 241 + attributes: 242 + - 243 + name: peer-id 244 + - 245 + name: slot 279 246 - 280 247 name: ovpn 281 248 attributes: ··· 322 235 type: nest 323 236 doc: Peer specific cipher configuration 324 237 nested-attributes: keyconf 238 + - 239 + name: ovpn-peer-new-input 240 + subset-of: ovpn 241 + attributes: 242 + - 243 + name: ifindex 244 + - 245 + name: peer 246 + nested-attributes: peer-new-input 247 + - 248 + name: ovpn-peer-set-input 249 + subset-of: ovpn 250 + attributes: 251 + - 252 + name: ifindex 253 + - 254 + name: peer 255 + nested-attributes: peer-set-input 256 + - 257 + name: ovpn-peer-del-input 258 + subset-of: ovpn 259 + attributes: 260 + - 261 + name: ifindex 262 + - 263 + name: peer 264 + nested-attributes: peer-del-input 265 + - 266 + name: ovpn-keyconf-get 267 + subset-of: ovpn 268 + attributes: 269 + - 270 + name: ifindex 271 + - 272 + name: keyconf 273 + nested-attributes: keyconf-get 274 + - 275 + name: ovpn-keyconf-swap-input 276 + subset-of: ovpn 277 + attributes: 278 + - 279 + name: ifindex 280 + - 281 + name: keyconf 282 + nested-attributes: keyconf-swap-input 283 + - 284 + name: ovpn-keyconf-del-input 285 + subset-of: ovpn 286 + attributes: 287 + - 288 + name: ifindex 289 + - 290 + name: keyconf 291 + nested-attributes: keyconf-del-input 325 292 326 293 operations: 327 294 list: 328 295 - 329 296 name: peer-new 330 - attribute-set: ovpn 297 + attribute-set: ovpn-peer-new-input 331 298 flags: [ admin-perm ] 332 299 doc: Add a remote peer 333 300 do: ··· 393 252 - peer 394 253 - 395 254 name: peer-set 396 - attribute-set: ovpn 255 + attribute-set: ovpn-peer-set-input 397 256 flags: [ admin-perm ] 398 257 doc: modify a remote peer 399 258 do: ··· 427 286 - peer 428 287 - 429 288 name: peer-del 430 - attribute-set: ovpn 289 + attribute-set: ovpn-peer-del-input 431 290 flags: [ admin-perm ] 432 291 doc: Delete existing remote peer 433 292 do: ··· 457 316 - keyconf 458 317 - 459 318 name: key-get 460 - attribute-set: ovpn 319 + attribute-set: ovpn-keyconf-get 461 320 flags: [ admin-perm ] 462 321 doc: Retrieve non-sensitive data about peer key and cipher 463 322 do: ··· 472 331 - keyconf 473 332 - 474 333 name: key-swap 475 - attribute-set: ovpn 334 + attribute-set: ovpn-keyconf-swap-input 476 335 flags: [ admin-perm ] 477 336 doc: Swap primary and secondary session keys for a specific peer 478 337 do: ··· 491 350 mcgrp: peers 492 351 - 493 352 name: key-del 494 - attribute-set: ovpn 353 + attribute-set: ovpn-keyconf-del-input 495 354 flags: [ admin-perm ] 496 355 doc: Delete cipher key for a specific peer 497 356 do:
+43 -8
drivers/net/ovpn/netlink.c
··· 352 352 return -EINVAL; 353 353 354 354 ret = nla_parse_nested(attrs, OVPN_A_PEER_MAX, info->attrs[OVPN_A_PEER], 355 - ovpn_peer_nl_policy, info->extack); 355 + ovpn_peer_new_input_nl_policy, info->extack); 356 356 if (ret) 357 357 return ret; 358 358 ··· 476 476 return -EINVAL; 477 477 478 478 ret = nla_parse_nested(attrs, OVPN_A_PEER_MAX, info->attrs[OVPN_A_PEER], 479 - ovpn_peer_nl_policy, info->extack); 479 + ovpn_peer_set_input_nl_policy, info->extack); 480 480 if (ret) 481 481 return ret; 482 482 ··· 654 654 struct ovpn_peer *peer; 655 655 struct sk_buff *msg; 656 656 u32 peer_id; 657 - int ret; 657 + int ret, i; 658 658 659 659 if (GENL_REQ_ATTR_CHECK(info, OVPN_A_PEER)) 660 660 return -EINVAL; ··· 667 667 if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_PEER], attrs, 668 668 OVPN_A_PEER_ID)) 669 669 return -EINVAL; 670 + 671 + /* OVPN_CMD_PEER_GET expects only the PEER_ID, therefore 672 + * ensure that the user hasn't specified any other attribute. 673 + * 674 + * Unfortunately this check cannot be performed via netlink 675 + * spec/policy and must be open-coded. 676 + */ 677 + for (i = 0; i < OVPN_A_PEER_MAX + 1; i++) { 678 + if (i == OVPN_A_PEER_ID) 679 + continue; 680 + 681 + if (attrs[i]) { 682 + NL_SET_ERR_MSG_FMT_MOD(info->extack, 683 + "unexpected attribute %u", i); 684 + return -EINVAL; 685 + } 686 + } 670 687 671 688 peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]); 672 689 peer = ovpn_peer_get_by_id(ovpn, peer_id); ··· 785 768 return -EINVAL; 786 769 787 770 ret = nla_parse_nested(attrs, OVPN_A_PEER_MAX, info->attrs[OVPN_A_PEER], 788 - ovpn_peer_nl_policy, info->extack); 771 + ovpn_peer_del_input_nl_policy, info->extack); 789 772 if (ret) 790 773 return ret; 791 774 ··· 986 969 struct ovpn_peer *peer; 987 970 struct sk_buff *msg; 988 971 u32 peer_id; 989 - int ret; 972 + int ret, i; 990 973 991 974 if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF)) 992 975 return -EINVAL; 993 976 994 977 ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX, 995 978 info->attrs[OVPN_A_KEYCONF], 996 - ovpn_keyconf_nl_policy, info->extack); 979 + ovpn_keyconf_get_nl_policy, info->extack); 997 980 if (ret) 998 981 return ret; 999 982 ··· 1004 987 if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, 1005 988 OVPN_A_KEYCONF_SLOT)) 1006 989 return -EINVAL; 990 + 991 + /* OVPN_CMD_KEY_GET expects only the PEER_ID and the SLOT, therefore 992 + * ensure that the user hasn't specified any other attribute. 993 + * 994 + * Unfortunately this check cannot be performed via netlink 995 + * spec/policy and must be open-coded. 996 + */ 997 + for (i = 0; i < OVPN_A_KEYCONF_MAX + 1; i++) { 998 + if (i == OVPN_A_KEYCONF_PEER_ID || 999 + i == OVPN_A_KEYCONF_SLOT) 1000 + continue; 1001 + 1002 + if (attrs[i]) { 1003 + NL_SET_ERR_MSG_FMT_MOD(info->extack, 1004 + "unexpected attribute %u", i); 1005 + return -EINVAL; 1006 + } 1007 + } 1007 1008 1008 1009 peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]); 1009 1010 peer = ovpn_peer_get_by_id(ovpn, peer_id); ··· 1072 1037 1073 1038 ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX, 1074 1039 info->attrs[OVPN_A_KEYCONF], 1075 - ovpn_keyconf_nl_policy, info->extack); 1040 + ovpn_keyconf_swap_input_nl_policy, info->extack); 1076 1041 if (ret) 1077 1042 return ret; 1078 1043 ··· 1109 1074 1110 1075 ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX, 1111 1076 info->attrs[OVPN_A_KEYCONF], 1112 - ovpn_keyconf_nl_policy, info->extack); 1077 + ovpn_keyconf_del_input_nl_policy, info->extack); 1113 1078 if (ret) 1114 1079 return ret; 1115 1080