s390/qeth: sanitize ARP requests
The ARP_{ADD,REMOVE}_ENTRY cmd structs contain reserved fields. Introduce a common helper that doesn't raw-copy the user-provided data into the cmd, but only sets those fields that are strictly needed for the command. This also sets the correct command length for ARP_REMOVE_ENTRY. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9fae5c3b60
commit
125d7d3011
|
@ -1046,11 +1046,6 @@ int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
|
||||||
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
|
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
|
||||||
void qeth_trace_features(struct qeth_card *);
|
void qeth_trace_features(struct qeth_card *);
|
||||||
void qeth_close_dev(struct qeth_card *);
|
void qeth_close_dev(struct qeth_card *);
|
||||||
int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
|
|
||||||
long,
|
|
||||||
int (*reply_cb)(struct qeth_card *,
|
|
||||||
struct qeth_reply *, unsigned long),
|
|
||||||
void *);
|
|
||||||
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
|
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
|
||||||
struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
|
struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
|
||||||
enum qeth_ipa_funcs,
|
enum qeth_ipa_funcs,
|
||||||
|
|
|
@ -5477,11 +5477,12 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(qeth_get_setassparms_cmd);
|
EXPORT_SYMBOL_GPL(qeth_get_setassparms_cmd);
|
||||||
|
|
||||||
int qeth_send_setassparms(struct qeth_card *card,
|
static int qeth_send_setassparms(struct qeth_card *card,
|
||||||
struct qeth_cmd_buffer *iob, __u16 len, long data,
|
struct qeth_cmd_buffer *iob, u16 len,
|
||||||
int (*reply_cb)(struct qeth_card *,
|
long data, int (*reply_cb)(struct qeth_card *,
|
||||||
struct qeth_reply *, unsigned long),
|
struct qeth_reply *,
|
||||||
void *reply_param)
|
unsigned long),
|
||||||
|
void *reply_param)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct qeth_ipa_cmd *cmd;
|
struct qeth_ipa_cmd *cmd;
|
||||||
|
@ -5497,7 +5498,6 @@ int qeth_send_setassparms(struct qeth_card *card,
|
||||||
rc = qeth_send_ipa_cmd(card, iob, reply_cb, reply_param);
|
rc = qeth_send_ipa_cmd(card, iob, reply_cb, reply_param);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(qeth_send_setassparms);
|
|
||||||
|
|
||||||
int qeth_send_simple_setassparms_prot(struct qeth_card *card,
|
int qeth_send_simple_setassparms_prot(struct qeth_card *card,
|
||||||
enum qeth_ipa_funcs ipa_func,
|
enum qeth_ipa_funcs ipa_func,
|
||||||
|
|
|
@ -436,7 +436,7 @@ struct qeth_ipacmd_setassparms {
|
||||||
__u32 flags_32bit;
|
__u32 flags_32bit;
|
||||||
struct qeth_ipa_caps caps;
|
struct qeth_ipa_caps caps;
|
||||||
struct qeth_checksum_cmd chksum;
|
struct qeth_checksum_cmd chksum;
|
||||||
struct qeth_arp_cache_entry add_arp_entry;
|
struct qeth_arp_cache_entry arp_entry;
|
||||||
struct qeth_arp_query_data query_arp;
|
struct qeth_arp_query_data query_arp;
|
||||||
struct qeth_tso_start_data tso;
|
struct qeth_tso_start_data tso;
|
||||||
__u8 ip[16];
|
__u8 ip[16];
|
||||||
|
|
|
@ -1777,13 +1777,18 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qeth_l3_arp_add_entry(struct qeth_card *card,
|
static int qeth_l3_arp_modify_entry(struct qeth_card *card,
|
||||||
struct qeth_arp_cache_entry *entry)
|
struct qeth_arp_cache_entry *entry,
|
||||||
|
enum qeth_arp_process_subcmds arp_cmd)
|
||||||
{
|
{
|
||||||
|
struct qeth_arp_cache_entry *cmd_entry;
|
||||||
struct qeth_cmd_buffer *iob;
|
struct qeth_cmd_buffer *iob;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
QETH_CARD_TEXT(card, 3, "arpadent");
|
if (arp_cmd == IPA_CMD_ASS_ARP_ADD_ENTRY)
|
||||||
|
QETH_CARD_TEXT(card, 3, "arpadd");
|
||||||
|
else
|
||||||
|
QETH_CARD_TEXT(card, 3, "arpdel");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* currently GuestLAN only supports the ARP assist function
|
* currently GuestLAN only supports the ARP assist function
|
||||||
|
@ -1796,54 +1801,19 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card,
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
|
iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING, arp_cmd,
|
||||||
IPA_CMD_ASS_ARP_ADD_ENTRY,
|
sizeof(*cmd_entry), QETH_PROT_IPV4);
|
||||||
sizeof(struct qeth_arp_cache_entry),
|
|
||||||
QETH_PROT_IPV4);
|
|
||||||
if (!iob)
|
if (!iob)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
rc = qeth_send_setassparms(card, iob,
|
|
||||||
sizeof(struct qeth_arp_cache_entry),
|
cmd_entry = &__ipa_cmd(iob)->data.setassparms.data.arp_entry;
|
||||||
(unsigned long) entry,
|
ether_addr_copy(cmd_entry->macaddr, entry->macaddr);
|
||||||
qeth_setassparms_cb, NULL);
|
memcpy(cmd_entry->ipaddr, entry->ipaddr, 4);
|
||||||
|
rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_cb, NULL);
|
||||||
if (rc)
|
if (rc)
|
||||||
QETH_DBF_MESSAGE(2, "Could not add ARP entry on device %x: %#x\n",
|
QETH_DBF_MESSAGE(2, "Could not modify (cmd: %#x) ARP entry on device %x: %#x\n",
|
||||||
CARD_DEVID(card), rc);
|
arp_cmd, CARD_DEVID(card), rc);
|
||||||
return qeth_l3_arp_makerc(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qeth_l3_arp_remove_entry(struct qeth_card *card,
|
|
||||||
struct qeth_arp_cache_entry *entry)
|
|
||||||
{
|
|
||||||
struct qeth_cmd_buffer *iob;
|
|
||||||
char buf[16] = {0, };
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
QETH_CARD_TEXT(card, 3, "arprment");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* currently GuestLAN only supports the ARP assist function
|
|
||||||
* IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_REMOVE_ENTRY;
|
|
||||||
* thus we say EOPNOTSUPP for this ARP function
|
|
||||||
*/
|
|
||||||
if (card->info.guestlan)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
memcpy(buf, entry, 12);
|
|
||||||
iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
|
|
||||||
IPA_CMD_ASS_ARP_REMOVE_ENTRY,
|
|
||||||
12,
|
|
||||||
QETH_PROT_IPV4);
|
|
||||||
if (!iob)
|
|
||||||
return -ENOMEM;
|
|
||||||
rc = qeth_send_setassparms(card, iob,
|
|
||||||
12, (unsigned long)buf,
|
|
||||||
qeth_setassparms_cb, NULL);
|
|
||||||
if (rc)
|
|
||||||
QETH_DBF_MESSAGE(2, "Could not delete ARP entry on device %x: %#x\n",
|
|
||||||
CARD_DEVID(card), rc);
|
|
||||||
return qeth_l3_arp_makerc(rc);
|
return qeth_l3_arp_makerc(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1875,6 +1845,7 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||||
{
|
{
|
||||||
struct qeth_card *card = dev->ml_priv;
|
struct qeth_card *card = dev->ml_priv;
|
||||||
struct qeth_arp_cache_entry arp_entry;
|
struct qeth_arp_cache_entry arp_entry;
|
||||||
|
enum qeth_arp_process_subcmds arp_cmd;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
@ -1893,27 +1864,16 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||||
rc = qeth_l3_arp_query(card, rq->ifr_ifru.ifru_data);
|
rc = qeth_l3_arp_query(card, rq->ifr_ifru.ifru_data);
|
||||||
break;
|
break;
|
||||||
case SIOC_QETH_ARP_ADD_ENTRY:
|
case SIOC_QETH_ARP_ADD_ENTRY:
|
||||||
if (!capable(CAP_NET_ADMIN)) {
|
|
||||||
rc = -EPERM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
|
|
||||||
sizeof(struct qeth_arp_cache_entry)))
|
|
||||||
rc = -EFAULT;
|
|
||||||
else
|
|
||||||
rc = qeth_l3_arp_add_entry(card, &arp_entry);
|
|
||||||
break;
|
|
||||||
case SIOC_QETH_ARP_REMOVE_ENTRY:
|
case SIOC_QETH_ARP_REMOVE_ENTRY:
|
||||||
if (!capable(CAP_NET_ADMIN)) {
|
if (!capable(CAP_NET_ADMIN))
|
||||||
rc = -EPERM;
|
return -EPERM;
|
||||||
break;
|
if (copy_from_user(&arp_entry, rq->ifr_data, sizeof(arp_entry)))
|
||||||
}
|
return -EFAULT;
|
||||||
if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
|
|
||||||
sizeof(struct qeth_arp_cache_entry)))
|
arp_cmd = (cmd == SIOC_QETH_ARP_ADD_ENTRY) ?
|
||||||
rc = -EFAULT;
|
IPA_CMD_ASS_ARP_ADD_ENTRY :
|
||||||
else
|
IPA_CMD_ASS_ARP_REMOVE_ENTRY;
|
||||||
rc = qeth_l3_arp_remove_entry(card, &arp_entry);
|
return qeth_l3_arp_modify_entry(card, &arp_entry, arp_cmd);
|
||||||
break;
|
|
||||||
case SIOC_QETH_ARP_FLUSH_CACHE:
|
case SIOC_QETH_ARP_FLUSH_CACHE:
|
||||||
if (!capable(CAP_NET_ADMIN)) {
|
if (!capable(CAP_NET_ADMIN)) {
|
||||||
rc = -EPERM;
|
rc = -EPERM;
|
||||||
|
|
Loading…
Reference in New Issue