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

netfilter: ipset: send error message manually

When a message carries multiple commands and one of them triggers
an error, we have to report to the userspace which one was that.
The line number of the command plays this role and there's an attribute
reserved in the header part of the message to be filled out with the error
line number. In order not to modify the original message received from
the userspace, we construct a new, complete netlink error message and
modifies the attribute there, then send it.
Netlink is notified not to send its ACK/error message.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Jozsef Kadlecsik and committed by
Patrick McHardy
5f52bc3c 724bab47

+26 -7
+26 -7
net/netfilter/ipset/ip_set_core.c
··· 1098 1098 }; 1099 1099 1100 1100 static int 1101 - call_ad(struct sk_buff *skb, struct ip_set *set, 1101 + call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, 1102 1102 struct nlattr *tb[], enum ipset_adt adt, 1103 1103 u32 flags, bool use_lineno) 1104 1104 { ··· 1118 1118 return 0; 1119 1119 if (lineno && use_lineno) { 1120 1120 /* Error in restore/batch mode: send back lineno */ 1121 - struct nlmsghdr *nlh = nlmsg_hdr(skb); 1121 + struct nlmsghdr *rep, *nlh = nlmsg_hdr(skb); 1122 + struct sk_buff *skb2; 1123 + struct nlmsgerr *errmsg; 1124 + size_t payload = sizeof(*errmsg) + nlmsg_len(nlh); 1122 1125 int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); 1123 1126 struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; 1124 - struct nlattr *cmdattr = (void *)nlh + min_len; 1127 + struct nlattr *cmdattr; 1125 1128 u32 *errline; 1129 + 1130 + skb2 = nlmsg_new(payload, GFP_KERNEL); 1131 + if (skb2 == NULL) 1132 + return -ENOMEM; 1133 + rep = __nlmsg_put(skb2, NETLINK_CB(skb).pid, 1134 + nlh->nlmsg_seq, NLMSG_ERROR, payload, 0); 1135 + errmsg = nlmsg_data(rep); 1136 + errmsg->error = ret; 1137 + memcpy(&errmsg->msg, nlh, nlh->nlmsg_len); 1138 + cmdattr = (void *)&errmsg->msg + min_len; 1126 1139 1127 1140 nla_parse(cda, IPSET_ATTR_CMD_MAX, 1128 1141 cmdattr, nlh->nlmsg_len - min_len, ··· 1144 1131 errline = nla_data(cda[IPSET_ATTR_LINENO]); 1145 1132 1146 1133 *errline = lineno; 1134 + 1135 + netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); 1136 + /* Signal netlink not to send its ACK/errmsg. */ 1137 + return -EINTR; 1147 1138 } 1148 1139 1149 1140 return ret; ··· 1186 1169 attr[IPSET_ATTR_DATA], 1187 1170 set->type->adt_policy)) 1188 1171 return -IPSET_ERR_PROTOCOL; 1189 - ret = call_ad(skb, set, tb, IPSET_ADD, flags, use_lineno); 1172 + ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, flags, 1173 + use_lineno); 1190 1174 } else { 1191 1175 int nla_rem; 1192 1176 ··· 1198 1180 nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, 1199 1181 set->type->adt_policy)) 1200 1182 return -IPSET_ERR_PROTOCOL; 1201 - ret = call_ad(skb, set, tb, IPSET_ADD, 1183 + ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, 1202 1184 flags, use_lineno); 1203 1185 if (ret < 0) 1204 1186 return ret; ··· 1240 1222 attr[IPSET_ATTR_DATA], 1241 1223 set->type->adt_policy)) 1242 1224 return -IPSET_ERR_PROTOCOL; 1243 - ret = call_ad(skb, set, tb, IPSET_DEL, flags, use_lineno); 1225 + ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, flags, 1226 + use_lineno); 1244 1227 } else { 1245 1228 int nla_rem; 1246 1229 ··· 1252 1233 nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, 1253 1234 set->type->adt_policy)) 1254 1235 return -IPSET_ERR_PROTOCOL; 1255 - ret = call_ad(skb, set, tb, IPSET_DEL, 1236 + ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, 1256 1237 flags, use_lineno); 1257 1238 if (ret < 0) 1258 1239 return ret;