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

inet_diag: Move the INET_DIAG_REQ_BYTECODE nlattr to cb->data

The INET_DIAG_REQ_BYTECODE nlattr is currently re-found every time when
the "dump()" is re-started.

In a latter patch, it will also need to parse the new
INET_DIAG_REQ_SK_BPF_STORAGES nlattr to learn the map_fds. Thus, this
patch takes this chance to store the parsed nlattr in cb->data
during the "start" time of a dump.

By doing this, the "bc" argument also becomes unnecessary
and is removed. Also, the two copies of the INET_DIAG_REQ_BYTECODE
parsing-audit logic between compat/current version can be
consolidated to one.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Song Liu <songliubraving@fb.com>
Link: https://lore.kernel.org/bpf/20200225230415.1975555-1-kafai@fb.com

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
0df6d328 5682d393

+98 -64
+7 -4
include/linux/inet_diag.h
··· 15 15 struct inet_diag_handler { 16 16 void (*dump)(struct sk_buff *skb, 17 17 struct netlink_callback *cb, 18 - const struct inet_diag_req_v2 *r, 19 - struct nlattr *bc); 18 + const struct inet_diag_req_v2 *r); 20 19 21 20 int (*dump_one)(struct netlink_callback *cb, 22 21 const struct inet_diag_req_v2 *req); ··· 38 39 __u16 idiag_info_size; 39 40 }; 40 41 42 + struct inet_diag_dump_data { 43 + struct nlattr *req_nlas[__INET_DIAG_REQ_MAX]; 44 + #define inet_diag_nla_bc req_nlas[INET_DIAG_REQ_BYTECODE] 45 + }; 46 + 41 47 struct inet_connection_sock; 42 48 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, 43 49 struct sk_buff *skb, struct netlink_callback *cb, ··· 50 46 u16 nlmsg_flags, bool net_admin); 51 47 void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb, 52 48 struct netlink_callback *cb, 53 - const struct inet_diag_req_v2 *r, 54 - struct nlattr *bc); 49 + const struct inet_diag_req_v2 *r); 55 50 int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, 56 51 struct netlink_callback *cb, 57 52 const struct inet_diag_req_v2 *req);
+2 -1
include/uapi/linux/inet_diag.h
··· 64 64 enum { 65 65 INET_DIAG_REQ_NONE, 66 66 INET_DIAG_REQ_BYTECODE, 67 + __INET_DIAG_REQ_MAX, 67 68 }; 68 69 69 - #define INET_DIAG_REQ_MAX INET_DIAG_REQ_BYTECODE 70 + #define INET_DIAG_REQ_MAX (__INET_DIAG_REQ_MAX - 1) 70 71 71 72 /* Bytecode is sequence of 4 byte commands followed by variable arguments. 72 73 * All the commands identified by "code" are conditional jumps forward:
+2 -2
net/dccp/diag.c
··· 46 46 } 47 47 48 48 static void dccp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 49 - const struct inet_diag_req_v2 *r, struct nlattr *bc) 49 + const struct inet_diag_req_v2 *r) 50 50 { 51 - inet_diag_dump_icsk(&dccp_hashinfo, skb, cb, r, bc); 51 + inet_diag_dump_icsk(&dccp_hashinfo, skb, cb, r); 52 52 } 53 53 54 54 static int dccp_diag_dump_one(struct netlink_callback *cb,
+70 -47
net/ipv4/inet_diag.c
··· 495 495 if (IS_ERR(handler)) { 496 496 err = PTR_ERR(handler); 497 497 } else if (cmd == SOCK_DIAG_BY_FAMILY) { 498 + struct inet_diag_dump_data empty_dump_data = {}; 498 499 struct netlink_callback cb = { 499 500 .nlh = nlh, 500 501 .skb = in_skb, 502 + .data = &empty_dump_data, 501 503 }; 502 504 err = handler->dump_one(&cb, req); 503 505 } else if (cmd == SOCK_DESTROY && handler->destroy) { ··· 865 863 866 864 void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, 867 865 struct netlink_callback *cb, 868 - const struct inet_diag_req_v2 *r, struct nlattr *bc) 866 + const struct inet_diag_req_v2 *r) 869 867 { 870 868 bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); 869 + struct inet_diag_dump_data *cb_data = cb->data; 871 870 struct net *net = sock_net(skb->sk); 872 871 u32 idiag_states = r->idiag_states; 873 872 int i, num, s_i, s_num; 873 + struct nlattr *bc; 874 874 struct sock *sk; 875 875 876 + bc = cb_data->inet_diag_nla_bc; 876 877 if (idiag_states & TCPF_SYN_RECV) 877 878 idiag_states |= TCPF_NEW_SYN_RECV; 878 879 s_i = cb->args[1]; ··· 1019 1014 EXPORT_SYMBOL_GPL(inet_diag_dump_icsk); 1020 1015 1021 1016 static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 1022 - const struct inet_diag_req_v2 *r, 1023 - struct nlattr *bc) 1017 + const struct inet_diag_req_v2 *r) 1024 1018 { 1025 1019 const struct inet_diag_handler *handler; 1026 1020 int err = 0; 1027 1021 1028 1022 handler = inet_diag_lock_handler(r->sdiag_protocol); 1029 1023 if (!IS_ERR(handler)) 1030 - handler->dump(skb, cb, r, bc); 1024 + handler->dump(skb, cb, r); 1031 1025 else 1032 1026 err = PTR_ERR(handler); 1033 1027 inet_diag_unlock_handler(handler); ··· 1036 1032 1037 1033 static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) 1038 1034 { 1039 - int hdrlen = sizeof(struct inet_diag_req_v2); 1040 - struct nlattr *bc = NULL; 1035 + return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh)); 1036 + } 1041 1037 1042 - if (nlmsg_attrlen(cb->nlh, hdrlen)) 1043 - bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); 1038 + static int __inet_diag_dump_start(struct netlink_callback *cb, int hdrlen) 1039 + { 1040 + const struct nlmsghdr *nlh = cb->nlh; 1041 + struct inet_diag_dump_data *cb_data; 1042 + struct sk_buff *skb = cb->skb; 1043 + struct nlattr *nla; 1044 + int rem, err; 1044 1045 1045 - return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh), bc); 1046 + cb_data = kzalloc(sizeof(*cb_data), GFP_KERNEL); 1047 + if (!cb_data) 1048 + return -ENOMEM; 1049 + 1050 + nla_for_each_attr(nla, nlmsg_attrdata(nlh, hdrlen), 1051 + nlmsg_attrlen(nlh, hdrlen), rem) { 1052 + int type = nla_type(nla); 1053 + 1054 + if (type < __INET_DIAG_REQ_MAX) 1055 + cb_data->req_nlas[type] = nla; 1056 + } 1057 + 1058 + nla = cb_data->inet_diag_nla_bc; 1059 + if (nla) { 1060 + err = inet_diag_bc_audit(nla, skb); 1061 + if (err) { 1062 + kfree(cb_data); 1063 + return err; 1064 + } 1065 + } 1066 + 1067 + cb->data = cb_data; 1068 + return 0; 1069 + } 1070 + 1071 + static int inet_diag_dump_start(struct netlink_callback *cb) 1072 + { 1073 + return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req_v2)); 1074 + } 1075 + 1076 + static int inet_diag_dump_start_compat(struct netlink_callback *cb) 1077 + { 1078 + return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req)); 1079 + } 1080 + 1081 + static int inet_diag_dump_done(struct netlink_callback *cb) 1082 + { 1083 + kfree(cb->data); 1084 + 1085 + return 0; 1046 1086 } 1047 1087 1048 1088 static int inet_diag_type2proto(int type) ··· 1105 1057 struct netlink_callback *cb) 1106 1058 { 1107 1059 struct inet_diag_req *rc = nlmsg_data(cb->nlh); 1108 - int hdrlen = sizeof(struct inet_diag_req); 1109 1060 struct inet_diag_req_v2 req; 1110 - struct nlattr *bc = NULL; 1111 1061 1112 1062 req.sdiag_family = AF_UNSPEC; /* compatibility */ 1113 1063 req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type); ··· 1113 1067 req.idiag_states = rc->idiag_states; 1114 1068 req.id = rc->id; 1115 1069 1116 - if (nlmsg_attrlen(cb->nlh, hdrlen)) 1117 - bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); 1118 - 1119 - return __inet_diag_dump(skb, cb, &req, bc); 1070 + return __inet_diag_dump(skb, cb, &req); 1120 1071 } 1121 1072 1122 1073 static int inet_diag_get_exact_compat(struct sk_buff *in_skb, ··· 1141 1098 return -EINVAL; 1142 1099 1143 1100 if (nlh->nlmsg_flags & NLM_F_DUMP) { 1144 - if (nlmsg_attrlen(nlh, hdrlen)) { 1145 - struct nlattr *attr; 1146 - int err; 1147 - 1148 - attr = nlmsg_find_attr(nlh, hdrlen, 1149 - INET_DIAG_REQ_BYTECODE); 1150 - err = inet_diag_bc_audit(attr, skb); 1151 - if (err) 1152 - return err; 1153 - } 1154 - { 1155 - struct netlink_dump_control c = { 1156 - .dump = inet_diag_dump_compat, 1157 - }; 1158 - return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); 1159 - } 1101 + struct netlink_dump_control c = { 1102 + .start = inet_diag_dump_start_compat, 1103 + .done = inet_diag_dump_done, 1104 + .dump = inet_diag_dump_compat, 1105 + }; 1106 + return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); 1160 1107 } 1161 1108 1162 1109 return inet_diag_get_exact_compat(skb, nlh); ··· 1162 1129 1163 1130 if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY && 1164 1131 h->nlmsg_flags & NLM_F_DUMP) { 1165 - if (nlmsg_attrlen(h, hdrlen)) { 1166 - struct nlattr *attr; 1167 - int err; 1168 - 1169 - attr = nlmsg_find_attr(h, hdrlen, 1170 - INET_DIAG_REQ_BYTECODE); 1171 - err = inet_diag_bc_audit(attr, skb); 1172 - if (err) 1173 - return err; 1174 - } 1175 - { 1176 - struct netlink_dump_control c = { 1177 - .dump = inet_diag_dump, 1178 - }; 1179 - return netlink_dump_start(net->diag_nlsk, skb, h, &c); 1180 - } 1132 + struct netlink_dump_control c = { 1133 + .start = inet_diag_dump_start, 1134 + .done = inet_diag_dump_done, 1135 + .dump = inet_diag_dump, 1136 + }; 1137 + return netlink_dump_start(net->diag_nlsk, skb, h, &c); 1181 1138 } 1182 1139 1183 1140 return inet_diag_cmd_exact(h->nlmsg_type, skb, h, nlmsg_data(h));
+5 -1
net/ipv4/raw_diag.c
··· 138 138 } 139 139 140 140 static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 141 - const struct inet_diag_req_v2 *r, struct nlattr *bc) 141 + const struct inet_diag_req_v2 *r) 142 142 { 143 143 bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); 144 144 struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); 145 145 struct net *net = sock_net(skb->sk); 146 + struct inet_diag_dump_data *cb_data; 146 147 int num, s_num, slot, s_slot; 147 148 struct sock *sk = NULL; 149 + struct nlattr *bc; 148 150 149 151 if (IS_ERR(hashinfo)) 150 152 return; 151 153 154 + cb_data = cb->data; 155 + bc = cb_data->inet_diag_nla_bc; 152 156 s_slot = cb->args[0]; 153 157 num = s_num = cb->args[1]; 154 158
+2 -2
net/ipv4/tcp_diag.c
··· 179 179 } 180 180 181 181 static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 182 - const struct inet_diag_req_v2 *r, struct nlattr *bc) 182 + const struct inet_diag_req_v2 *r) 183 183 { 184 - inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc); 184 + inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r); 185 185 } 186 186 187 187 static int tcp_diag_dump_one(struct netlink_callback *cb,
+9 -6
net/ipv4/udp_diag.c
··· 89 89 90 90 static void udp_dump(struct udp_table *table, struct sk_buff *skb, 91 91 struct netlink_callback *cb, 92 - const struct inet_diag_req_v2 *r, struct nlattr *bc) 92 + const struct inet_diag_req_v2 *r) 93 93 { 94 94 bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); 95 95 struct net *net = sock_net(skb->sk); 96 + struct inet_diag_dump_data *cb_data; 96 97 int num, s_num, slot, s_slot; 98 + struct nlattr *bc; 97 99 100 + cb_data = cb->data; 101 + bc = cb_data->inet_diag_nla_bc; 98 102 s_slot = cb->args[0]; 99 103 num = s_num = cb->args[1]; 100 104 ··· 146 142 } 147 143 148 144 static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 149 - const struct inet_diag_req_v2 *r, struct nlattr *bc) 145 + const struct inet_diag_req_v2 *r) 150 146 { 151 - udp_dump(&udp_table, skb, cb, r, bc); 147 + udp_dump(&udp_table, skb, cb, r); 152 148 } 153 149 154 150 static int udp_diag_dump_one(struct netlink_callback *cb, ··· 249 245 }; 250 246 251 247 static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 252 - const struct inet_diag_req_v2 *r, 253 - struct nlattr *bc) 248 + const struct inet_diag_req_v2 *r) 254 249 { 255 - udp_dump(&udplite_table, skb, cb, r, bc); 250 + udp_dump(&udplite_table, skb, cb, r); 256 251 } 257 252 258 253 static int udplite_diag_dump_one(struct netlink_callback *cb,
+1 -1
net/sctp/diag.c
··· 471 471 } 472 472 473 473 static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 474 - const struct inet_diag_req_v2 *r, struct nlattr *bc) 474 + const struct inet_diag_req_v2 *r) 475 475 { 476 476 u32 idiag_states = r->idiag_states; 477 477 struct net *net = sock_net(skb->sk);