2019-05-19 21:51:43 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2011-07-02 06:31:34 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2011 Instituto Nokia de Tecnologia
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Lauro Ramos Venancio <lauro.venancio@openbossa.org>
|
|
|
|
* Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
|
|
|
|
*
|
2014-10-14 08:19:46 +08:00
|
|
|
* Vendor commands implementation based on net/wireless/nl80211.c
|
|
|
|
* which is:
|
|
|
|
*
|
|
|
|
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
|
|
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
2011-07-02 06:31:34 +08:00
|
|
|
*/
|
|
|
|
|
2011-12-14 23:43:05 +08:00
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
|
2011-11-30 03:37:33 +08:00
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
#include <net/genetlink.h>
|
|
|
|
#include <linux/nfc.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
|
|
#include "nfc.h"
|
2013-04-26 17:49:40 +08:00
|
|
|
#include "llcp.h"
|
2012-10-17 20:43:39 +08:00
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
static const struct genl_multicast_group nfc_genl_mcgrps[] = {
|
|
|
|
{ .name = NFC_GENL_MCAST_EVENT_NAME, },
|
2011-07-02 06:31:34 +08:00
|
|
|
};
|
|
|
|
|
2016-10-24 20:40:03 +08:00
|
|
|
static struct genl_family nfc_genl_family;
|
2011-07-02 06:31:34 +08:00
|
|
|
static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
|
|
|
|
[NFC_ATTR_DEVICE_INDEX] = { .type = NLA_U32 },
|
|
|
|
[NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING,
|
|
|
|
.len = NFC_DEVICE_NAME_MAXSIZE },
|
|
|
|
[NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 },
|
2020-03-03 13:05:25 +08:00
|
|
|
[NFC_ATTR_TARGET_INDEX] = { .type = NLA_U32 },
|
2011-12-14 23:43:09 +08:00
|
|
|
[NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
|
|
|
|
[NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
|
2012-03-05 08:03:34 +08:00
|
|
|
[NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
|
2012-05-15 21:57:06 +08:00
|
|
|
[NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
|
|
|
|
[NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
|
2013-02-15 17:42:52 +08:00
|
|
|
[NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 },
|
|
|
|
[NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 },
|
|
|
|
[NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 },
|
2013-02-15 17:43:06 +08:00
|
|
|
[NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED },
|
2013-04-29 23:13:27 +08:00
|
|
|
[NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING,
|
|
|
|
.len = NFC_FIRMWARE_NAME_MAXSIZE },
|
2020-03-03 13:05:24 +08:00
|
|
|
[NFC_ATTR_SE_INDEX] = { .type = NLA_U32 },
|
2013-08-28 06:47:24 +08:00
|
|
|
[NFC_ATTR_SE_APDU] = { .type = NLA_BINARY },
|
2020-03-03 13:05:26 +08:00
|
|
|
[NFC_ATTR_VENDOR_ID] = { .type = NLA_U32 },
|
|
|
|
[NFC_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
|
2015-08-20 03:26:43 +08:00
|
|
|
[NFC_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
|
|
|
|
|
2013-02-15 17:43:06 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
|
2018-02-15 07:45:07 +08:00
|
|
|
[NFC_SDP_ATTR_URI] = { .type = NLA_STRING,
|
|
|
|
.len = U8_MAX - 4 },
|
2013-02-15 17:43:06 +08:00
|
|
|
[NFC_SDP_ATTR_SAP] = { .type = NLA_U8 },
|
2011-07-02 06:31:34 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
|
2012-03-05 08:03:53 +08:00
|
|
|
struct netlink_callback *cb, int flags)
|
2011-07-02 06:31:34 +08:00
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
2012-03-05 08:03:53 +08:00
|
|
|
&nfc_genl_family, flags, NFC_CMD_GET_TARGET);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
2017-11-15 20:09:32 +08:00
|
|
|
genl_dump_check_consistent(cb, hdr);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
2012-03-30 11:23:57 +08:00
|
|
|
if (nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target->idx) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols) ||
|
|
|
|
nla_put_u16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (target->nfcid1_len > 0 &&
|
|
|
|
nla_put(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len,
|
|
|
|
target->nfcid1))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (target->sensb_res_len > 0 &&
|
|
|
|
nla_put(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len,
|
|
|
|
target->sensb_res))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (target->sensf_res_len > 0 &&
|
|
|
|
nla_put(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len,
|
|
|
|
target->sensf_res))
|
|
|
|
goto nla_put_failure;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
2014-01-15 08:52:11 +08:00
|
|
|
if (target->is_iso15693) {
|
|
|
|
if (nla_put_u8(msg, NFC_ATTR_TARGET_ISO15693_DSFID,
|
|
|
|
target->iso15693_dsfid) ||
|
|
|
|
nla_put(msg, NFC_ATTR_TARGET_ISO15693_UID,
|
|
|
|
sizeof(target->iso15693_uid), target->iso15693_uid))
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
|
|
|
|
{
|
2019-10-06 02:04:38 +08:00
|
|
|
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
2011-07-02 06:31:34 +08:00
|
|
|
struct nfc_dev *dev;
|
|
|
|
u32 idx;
|
|
|
|
|
2023-08-15 05:47:18 +08:00
|
|
|
if (!info->info.attrs[NFC_ATTR_DEVICE_INDEX])
|
2011-07-02 06:31:34 +08:00
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
2023-08-15 05:47:18 +08:00
|
|
|
idx = nla_get_u32(info->info.attrs[NFC_ATTR_DEVICE_INDEX]);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_dump_targets(struct sk_buff *skb,
|
2012-03-05 08:03:53 +08:00
|
|
|
struct netlink_callback *cb)
|
2011-07-02 06:31:34 +08:00
|
|
|
{
|
|
|
|
int i = cb->args[0];
|
|
|
|
struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!dev) {
|
|
|
|
dev = __get_device_from_cb(cb);
|
|
|
|
if (IS_ERR(dev))
|
|
|
|
return PTR_ERR(dev);
|
|
|
|
|
|
|
|
cb->args[1] = (long) dev;
|
|
|
|
}
|
|
|
|
|
2012-05-07 18:31:15 +08:00
|
|
|
device_lock(&dev->dev);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
cb->seq = dev->targets_generation;
|
|
|
|
|
|
|
|
while (i < dev->n_targets) {
|
|
|
|
rc = nfc_genl_send_target(skb, &dev->targets[i], cb,
|
2012-03-05 08:03:53 +08:00
|
|
|
NLM_F_MULTI);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (rc < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2012-05-07 18:31:15 +08:00
|
|
|
device_unlock(&dev->dev);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
cb->args[0] = i;
|
|
|
|
|
|
|
|
return skb->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_dump_targets_done(struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
|
|
|
|
|
|
|
|
if (dev)
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nfc_genl_targets_found(struct nfc_dev *dev)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
dev->genl_data.poll_req_portid = 0;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
2012-03-05 08:03:53 +08:00
|
|
|
NFC_EVENT_TARGETS_FOUND);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
2012-03-30 11:23:57 +08:00
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2012-04-11 01:43:04 +08:00
|
|
|
int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
2012-04-11 01:43:04 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_EVENT_TARGET_LOST);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
2012-04-19 02:17:13 +08:00
|
|
|
if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx))
|
|
|
|
goto nla_put_failure;
|
2012-04-11 01:43:04 +08:00
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
2012-04-11 01:43:04 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2012-06-01 19:21:13 +08:00
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
2012-06-01 19:21:13 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_EVENT_TM_ACTIVATED);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_TM_PROTOCOLS, protocol))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
2012-06-01 19:21:13 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nfc_genl_tm_deactivated(struct nfc_dev *dev)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
2012-06-01 19:21:13 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_EVENT_TM_DEACTIVATED);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
2012-06-01 19:21:13 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2012-04-11 01:43:04 +08:00
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2017-02-04 09:15:55 +08:00
|
|
|
static int nfc_genl_setup_device_added(struct nfc_dev *dev, struct sk_buff *msg)
|
|
|
|
{
|
|
|
|
if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
int nfc_genl_device_added(struct nfc_dev *dev)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
2012-03-05 08:03:53 +08:00
|
|
|
NFC_EVENT_DEVICE_ADDED);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
2017-02-04 09:15:55 +08:00
|
|
|
if (nfc_genl_setup_device_added(dev, msg))
|
2012-03-30 11:23:57 +08:00
|
|
|
goto nla_put_failure;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nfc_genl_device_removed(struct nfc_dev *dev)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
2012-03-05 08:03:53 +08:00
|
|
|
NFC_EVENT_DEVICE_REMOVED);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
2012-03-30 11:23:57 +08:00
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2013-02-15 17:43:06 +08:00
|
|
|
int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
struct nlattr *sdp_attr, *uri_attr;
|
|
|
|
struct nfc_llcp_sdp_tlv *sdres;
|
|
|
|
struct hlist_node *n;
|
|
|
|
void *hdr;
|
|
|
|
int rc = -EMSGSIZE;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_EVENT_LLC_SDRES);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2019-04-26 17:13:06 +08:00
|
|
|
sdp_attr = nla_nest_start_noflag(msg, NFC_ATTR_LLC_SDP);
|
2013-02-15 17:43:06 +08:00
|
|
|
if (sdp_attr == NULL) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 1;
|
|
|
|
hlist_for_each_entry_safe(sdres, n, sdres_list, node) {
|
|
|
|
pr_debug("uri: %s, sap: %d\n", sdres->uri, sdres->sap);
|
|
|
|
|
2019-04-26 17:13:06 +08:00
|
|
|
uri_attr = nla_nest_start_noflag(msg, i++);
|
2013-02-15 17:43:06 +08:00
|
|
|
if (uri_attr == NULL) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nla_put_u8(msg, NFC_SDP_ATTR_SAP, sdres->sap))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_string(msg, NFC_SDP_ATTR_URI, sdres->uri))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(msg, uri_attr);
|
|
|
|
|
|
|
|
hlist_del(&sdres->node);
|
|
|
|
|
|
|
|
nfc_llcp_free_sdp_tlv(sdres);
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(msg, sdp_attr);
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
|
2013-02-15 17:43:06 +08:00
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
|
|
|
|
nfc_llcp_free_sdp_tlv_list(sdres_list);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-05-10 21:47:37 +08:00
|
|
|
int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_EVENT_SE_ADDED);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_SE_TYPE, type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
2013-05-10 21:47:37 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_EVENT_SE_REMOVED);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
2013-05-10 21:47:37 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2015-02-02 05:26:16 +08:00
|
|
|
int nfc_genl_se_transaction(struct nfc_dev *dev, u8 se_idx,
|
|
|
|
struct nfc_evt_transaction *evt_transaction)
|
|
|
|
{
|
|
|
|
struct nfc_se *se;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_EVENT_SE_TRANSACTION);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
se = nfc_find_se(dev, se_idx);
|
|
|
|
if (!se)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type) ||
|
|
|
|
nla_put(msg, NFC_ATTR_SE_AID, evt_transaction->aid_len,
|
|
|
|
evt_transaction->aid) ||
|
|
|
|
nla_put(msg, NFC_ATTR_SE_PARAMS, evt_transaction->params_len,
|
|
|
|
evt_transaction->params))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
/* evt_transaction is no more used */
|
|
|
|
devm_kfree(&dev->dev, evt_transaction);
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
/* evt_transaction is no more used */
|
|
|
|
devm_kfree(&dev->dev, evt_transaction);
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2015-12-24 06:45:18 +08:00
|
|
|
int nfc_genl_se_connectivity(struct nfc_dev *dev, u8 se_idx)
|
|
|
|
{
|
2021-07-30 22:42:00 +08:00
|
|
|
const struct nfc_se *se;
|
2015-12-24 06:45:18 +08:00
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_EVENT_SE_CONNECTIVITY);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
se = nfc_find_se(dev, se_idx);
|
|
|
|
if (!se)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
|
2012-09-08 04:12:54 +08:00
|
|
|
u32 portid, u32 seq,
|
2012-03-05 08:03:53 +08:00
|
|
|
struct netlink_callback *cb,
|
|
|
|
int flags)
|
2011-07-02 06:31:34 +08:00
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags,
|
2012-03-05 08:03:53 +08:00
|
|
|
NFC_CMD_GET_DEVICE);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (cb)
|
2017-11-15 20:09:32 +08:00
|
|
|
genl_dump_check_consistent(cb, hdr);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
2017-02-04 09:15:55 +08:00
|
|
|
if (nfc_genl_setup_device_added(dev, msg))
|
2012-03-30 11:23:57 +08:00
|
|
|
goto nla_put_failure;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_dump_devices(struct sk_buff *skb,
|
2012-03-05 08:03:53 +08:00
|
|
|
struct netlink_callback *cb)
|
2011-07-02 06:31:34 +08:00
|
|
|
{
|
|
|
|
struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
|
|
|
|
struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
|
|
|
|
bool first_call = false;
|
|
|
|
|
|
|
|
if (!iter) {
|
|
|
|
first_call = true;
|
|
|
|
iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
|
|
|
|
if (!iter)
|
|
|
|
return -ENOMEM;
|
|
|
|
cb->args[0] = (long) iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&nfc_devlist_mutex);
|
|
|
|
|
|
|
|
cb->seq = nfc_devlist_generation;
|
|
|
|
|
|
|
|
if (first_call) {
|
|
|
|
nfc_device_iter_init(iter);
|
|
|
|
dev = nfc_device_iter_next(iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (dev) {
|
|
|
|
int rc;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).portid,
|
2012-03-05 08:03:53 +08:00
|
|
|
cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (rc < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
dev = nfc_device_iter_next(iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&nfc_devlist_mutex);
|
|
|
|
|
|
|
|
cb->args[1] = (long) dev;
|
|
|
|
|
|
|
|
return skb->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
|
|
|
|
|
2021-12-09 02:27:42 +08:00
|
|
|
if (iter) {
|
|
|
|
nfc_device_iter_exit(iter);
|
|
|
|
kfree(iter);
|
|
|
|
}
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-14 23:43:09 +08:00
|
|
|
int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
|
2012-03-05 08:03:53 +08:00
|
|
|
u8 comm_mode, u8 rf_mode)
|
2011-12-14 23:43:09 +08:00
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
pr_debug("DEP link is up\n");
|
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
2011-12-14 23:43:09 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2012-03-05 08:03:53 +08:00
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, NFC_CMD_DEP_LINK_UP);
|
2011-12-14 23:43:09 +08:00
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
2012-03-30 11:23:57 +08:00
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (rf_mode == NFC_RF_INITIATOR &&
|
|
|
|
nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u8(msg, NFC_ATTR_COMM_MODE, comm_mode) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_RF_MODE, rf_mode))
|
|
|
|
goto nla_put_failure;
|
2011-12-14 23:43:09 +08:00
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
|
|
|
dev->dep_link_up = true;
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
|
2011-12-14 23:43:09 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nfc_genl_dep_link_down_event(struct nfc_dev *dev)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
pr_debug("DEP link is down\n");
|
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
2011-12-14 23:43:09 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
2012-03-05 08:03:53 +08:00
|
|
|
NFC_CMD_DEP_LINK_DOWN);
|
2011-12-14 23:43:09 +08:00
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
2012-03-30 11:23:57 +08:00
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
2011-12-14 23:43:09 +08:00
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
|
2011-12-14 23:43:09 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
u32 idx;
|
|
|
|
int rc = -ENOBUFS;
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2012-06-28 11:57:45 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!msg) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto out_putdev;
|
|
|
|
}
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
rc = nfc_genl_send_device(msg, dev, info->snd_portid, info->snd_seq,
|
2012-03-05 08:03:53 +08:00
|
|
|
NULL, 0);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (rc < 0)
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
|
|
|
|
out_free:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
out_putdev:
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-09-18 16:19:33 +08:00
|
|
|
static int nfc_genl_dev_up(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc;
|
|
|
|
u32 idx;
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
rc = nfc_dev_up(dev);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_dev_down(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc;
|
|
|
|
u32 idx;
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
rc = nfc_dev_down(dev);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc;
|
|
|
|
u32 idx;
|
2012-05-15 21:57:06 +08:00
|
|
|
u32 im_protocols = 0, tm_protocols = 0;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
2011-12-14 23:43:09 +08:00
|
|
|
pr_debug("Poll start\n");
|
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
2012-05-15 21:57:06 +08:00
|
|
|
((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
|
|
|
|
!info->attrs[NFC_ATTR_PROTOCOLS]) &&
|
2012-10-17 21:23:39 +08:00
|
|
|
!info->attrs[NFC_ATTR_TM_PROTOCOLS]))
|
2011-07-02 06:31:34 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
2012-05-15 21:57:06 +08:00
|
|
|
|
|
|
|
if (info->attrs[NFC_ATTR_TM_PROTOCOLS])
|
|
|
|
tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]);
|
|
|
|
|
|
|
|
if (info->attrs[NFC_ATTR_IM_PROTOCOLS])
|
|
|
|
im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]);
|
2012-05-31 17:48:58 +08:00
|
|
|
else if (info->attrs[NFC_ATTR_PROTOCOLS])
|
|
|
|
im_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
mutex_lock(&dev->genl_data.genl_data_mutex);
|
|
|
|
|
2012-05-15 21:57:06 +08:00
|
|
|
rc = nfc_start_poll(dev, im_protocols, tm_protocols);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (!rc)
|
2012-09-08 04:12:54 +08:00
|
|
|
dev->genl_data.poll_req_portid = info->snd_portid;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
mutex_unlock(&dev->genl_data.genl_data_mutex);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc;
|
|
|
|
u32 idx;
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2012-06-28 22:41:57 +08:00
|
|
|
device_lock(&dev->dev);
|
|
|
|
|
|
|
|
if (!dev->polling) {
|
|
|
|
device_unlock(&dev->dev);
|
2021-01-21 23:37:45 +08:00
|
|
|
nfc_put_device(dev);
|
2012-06-28 22:41:57 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
device_unlock(&dev->dev);
|
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
mutex_lock(&dev->genl_data.genl_data_mutex);
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
if (dev->genl_data.poll_req_portid != info->snd_portid) {
|
2011-07-02 06:31:34 +08:00
|
|
|
rc = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = nfc_stop_poll(dev);
|
2012-09-08 04:12:54 +08:00
|
|
|
dev->genl_data.poll_req_portid = 0;
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
mutex_unlock(&dev->genl_data.genl_data_mutex);
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-12-03 04:27:50 +08:00
|
|
|
static int nfc_genl_activate_target(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
u32 device_idx, target_idx, protocol;
|
|
|
|
int rc;
|
|
|
|
|
2017-05-24 18:42:26 +08:00
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_TARGET_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_PROTOCOLS])
|
2014-12-03 04:27:50 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(device_idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
target_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
|
|
|
|
protocol = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
|
|
|
|
|
2015-10-26 05:54:43 +08:00
|
|
|
nfc_deactivate_target(dev, target_idx, NFC_TARGET_MODE_SLEEP);
|
2014-12-03 04:27:50 +08:00
|
|
|
rc = nfc_activate_target(dev, target_idx, protocol);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
2017-03-23 03:20:58 +08:00
|
|
|
return rc;
|
2014-12-03 04:27:50 +08:00
|
|
|
}
|
|
|
|
|
2017-06-16 11:34:22 +08:00
|
|
|
static int nfc_genl_deactivate_target(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
u32 device_idx, target_idx;
|
|
|
|
int rc;
|
|
|
|
|
2019-06-14 15:13:02 +08:00
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_TARGET_INDEX])
|
2017-06-16 11:34:22 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(device_idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
target_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
|
|
|
|
|
|
|
|
rc = nfc_deactivate_target(dev, target_idx, NFC_TARGET_MODE_SLEEP);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-12-14 23:43:09 +08:00
|
|
|
static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc, tgt_idx;
|
|
|
|
u32 idx;
|
2012-03-05 08:03:50 +08:00
|
|
|
u8 comm;
|
2011-12-14 23:43:09 +08:00
|
|
|
|
|
|
|
pr_debug("DEP link up\n");
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
2012-03-05 08:03:50 +08:00
|
|
|
!info->attrs[NFC_ATTR_COMM_MODE])
|
2011-12-14 23:43:09 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
if (!info->attrs[NFC_ATTR_TARGET_INDEX])
|
|
|
|
tgt_idx = NFC_TARGET_IDX_ANY;
|
|
|
|
else
|
|
|
|
tgt_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
|
|
|
|
|
|
|
|
comm = nla_get_u8(info->attrs[NFC_ATTR_COMM_MODE]);
|
|
|
|
|
|
|
|
if (comm != NFC_COMM_ACTIVE && comm != NFC_COMM_PASSIVE)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2012-03-05 08:03:50 +08:00
|
|
|
rc = nfc_dep_link_up(dev, tgt_idx, comm);
|
2011-12-14 23:43:09 +08:00
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc;
|
|
|
|
u32 idx;
|
|
|
|
|
2024-04-10 11:48:46 +08:00
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
|
2011-12-14 23:43:09 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
rc = nfc_dep_link_down(dev);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-10-17 20:43:39 +08:00
|
|
|
static int nfc_genl_send_params(struct sk_buff *msg,
|
|
|
|
struct nfc_llcp_local *local,
|
|
|
|
u32 portid, u32 seq)
|
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, 0,
|
|
|
|
NFC_CMD_LLC_GET_PARAMS);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, local->dev->idx) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_LLC_PARAM_LTO, local->lto) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_LLC_PARAM_RW, local->rw) ||
|
|
|
|
nla_put_u16(msg, NFC_ATTR_LLC_PARAM_MIUX, be16_to_cpu(local->miux)))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
2012-10-17 20:43:39 +08:00
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
struct nfc_llcp_local *local;
|
|
|
|
int rc = 0;
|
|
|
|
struct sk_buff *msg = NULL;
|
|
|
|
u32 idx;
|
|
|
|
|
2024-04-10 11:48:46 +08:00
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
|
2012-10-17 20:43:39 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
|
|
|
|
|
|
|
local = nfc_llcp_find_local(dev);
|
|
|
|
if (!local) {
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg) {
|
|
|
|
rc = -ENOMEM;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
This commit fixes several use-after-free that caused by function
nfc_llcp_find_local(). For example, one UAF can happen when below buggy
time window occurs.
// nfc_genl_llc_get_params | // nfc_unregister_device
|
dev = nfc_get_device(idx); | device_lock(...)
if (!dev) | dev->shutting_down = true;
return -ENODEV; | device_unlock(...);
|
device_lock(...); | // nfc_llcp_unregister_device
| nfc_llcp_find_local()
nfc_llcp_find_local(...); |
| local_cleanup()
if (!local) { |
rc = -ENODEV; | // nfc_llcp_local_put
goto exit; | kref_put(.., local_release)
} |
| // local_release
| list_del(&local->list)
// nfc_genl_send_params | kfree()
local->dev->idx !!!UAF!!! |
|
and the crash trace for the one of the discussed UAF like:
BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
Read of size 8 at addr ffff888105b0e410 by task 20114
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:319 [inline]
print_report+0xcc/0x620 mm/kasan/report.c:430
kasan_report+0xb2/0xe0 mm/kasan/report.c:536
nfc_genl_send_params net/nfc/netlink.c:999 [inline]
nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg+0x1b6/0x200 net/socket.c:747
____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
__sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
RIP: 0033:0x7f34640a2389
RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
</TASK>
Allocated by task 20116:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:374 [inline]
__kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
kmalloc include/linux/slab.h:580 [inline]
kzalloc include/linux/slab.h:720 [inline]
nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
nfc_register_device+0x61/0x260 net/nfc/core.c:1124
nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
misc_open+0x379/0x4a0 drivers/char/misc.c:165
chrdev_open+0x26c/0x780 fs/char_dev.c:414
do_dentry_open+0x6c4/0x12a0 fs/open.c:920
do_open fs/namei.c:3560 [inline]
path_openat+0x24fe/0x37e0 fs/namei.c:3715
do_filp_open+0x1ba/0x410 fs/namei.c:3742
do_sys_openat2+0x171/0x4c0 fs/open.c:1356
do_sys_open fs/open.c:1372 [inline]
__do_sys_openat fs/open.c:1388 [inline]
__se_sys_openat fs/open.c:1383 [inline]
__x64_sys_openat+0x143/0x200 fs/open.c:1383
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Freed by task 20115:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free mm/kasan/common.c:200 [inline]
__kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
kasan_slab_free include/linux/kasan.h:162 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook mm/slub.c:1807 [inline]
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0x7a/0x190 mm/slub.c:3800
local_release net/nfc/llcp_core.c:174 [inline]
kref_put include/linux/kref.h:65 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
__fput+0x252/0xa20 fs/file_table.c:321
task_work_run+0x174/0x270 kernel/task_work.c:179
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
__syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Last potentially related work creation:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
__kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
call_netdevice_notifiers net/core/dev.c:1989 [inline]
dev_change_name+0x3c3/0x870 net/core/dev.c:1211
dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
sock_do_ioctl+0x160/0x260 net/socket.c:1213
sock_ioctl+0x3f9/0x670 net/socket.c:1316
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
The buggy address belongs to the object at ffff888105b0e400
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 16 bytes inside of
freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
The buggy address belongs to the physical page:
head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000010200(slab|head|node=0|zone=2)
raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
In summary, this patch solves those use-after-free by
1. Re-implement the nfc_llcp_find_local(). The current version does not
grab the reference when getting the local from the linked list. For
example, the llcp_sock_bind() gets the reference like below:
// llcp_sock_bind()
local = nfc_llcp_find_local(dev); // A
..... \
| raceable
..... /
llcp_sock->local = nfc_llcp_local_get(local); // B
There is an apparent race window that one can drop the reference
and free the local object fetched in (A) before (B) gets the reference.
2. Some callers of the nfc_llcp_find_local() do not grab the reference
at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
error handling function to put the reference.
3. Add the nfc_llcp_remove_local() helper. The local object is removed
from the linked list in local_release() when all reference is gone. This
patch removes it when nfc_llcp_unregister_device() is called.
Therefore, every caller of nfc_llcp_find_local() will get a reference
even when the nfc_llcp_unregister_device() is called. This promises no
use-after-free for the local object is ever possible.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
goto put_local;
|
2012-10-17 20:43:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq);
|
|
|
|
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
This commit fixes several use-after-free that caused by function
nfc_llcp_find_local(). For example, one UAF can happen when below buggy
time window occurs.
// nfc_genl_llc_get_params | // nfc_unregister_device
|
dev = nfc_get_device(idx); | device_lock(...)
if (!dev) | dev->shutting_down = true;
return -ENODEV; | device_unlock(...);
|
device_lock(...); | // nfc_llcp_unregister_device
| nfc_llcp_find_local()
nfc_llcp_find_local(...); |
| local_cleanup()
if (!local) { |
rc = -ENODEV; | // nfc_llcp_local_put
goto exit; | kref_put(.., local_release)
} |
| // local_release
| list_del(&local->list)
// nfc_genl_send_params | kfree()
local->dev->idx !!!UAF!!! |
|
and the crash trace for the one of the discussed UAF like:
BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
Read of size 8 at addr ffff888105b0e410 by task 20114
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:319 [inline]
print_report+0xcc/0x620 mm/kasan/report.c:430
kasan_report+0xb2/0xe0 mm/kasan/report.c:536
nfc_genl_send_params net/nfc/netlink.c:999 [inline]
nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg+0x1b6/0x200 net/socket.c:747
____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
__sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
RIP: 0033:0x7f34640a2389
RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
</TASK>
Allocated by task 20116:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:374 [inline]
__kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
kmalloc include/linux/slab.h:580 [inline]
kzalloc include/linux/slab.h:720 [inline]
nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
nfc_register_device+0x61/0x260 net/nfc/core.c:1124
nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
misc_open+0x379/0x4a0 drivers/char/misc.c:165
chrdev_open+0x26c/0x780 fs/char_dev.c:414
do_dentry_open+0x6c4/0x12a0 fs/open.c:920
do_open fs/namei.c:3560 [inline]
path_openat+0x24fe/0x37e0 fs/namei.c:3715
do_filp_open+0x1ba/0x410 fs/namei.c:3742
do_sys_openat2+0x171/0x4c0 fs/open.c:1356
do_sys_open fs/open.c:1372 [inline]
__do_sys_openat fs/open.c:1388 [inline]
__se_sys_openat fs/open.c:1383 [inline]
__x64_sys_openat+0x143/0x200 fs/open.c:1383
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Freed by task 20115:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free mm/kasan/common.c:200 [inline]
__kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
kasan_slab_free include/linux/kasan.h:162 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook mm/slub.c:1807 [inline]
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0x7a/0x190 mm/slub.c:3800
local_release net/nfc/llcp_core.c:174 [inline]
kref_put include/linux/kref.h:65 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
__fput+0x252/0xa20 fs/file_table.c:321
task_work_run+0x174/0x270 kernel/task_work.c:179
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
__syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Last potentially related work creation:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
__kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
call_netdevice_notifiers net/core/dev.c:1989 [inline]
dev_change_name+0x3c3/0x870 net/core/dev.c:1211
dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
sock_do_ioctl+0x160/0x260 net/socket.c:1213
sock_ioctl+0x3f9/0x670 net/socket.c:1316
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
The buggy address belongs to the object at ffff888105b0e400
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 16 bytes inside of
freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
The buggy address belongs to the physical page:
head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000010200(slab|head|node=0|zone=2)
raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
In summary, this patch solves those use-after-free by
1. Re-implement the nfc_llcp_find_local(). The current version does not
grab the reference when getting the local from the linked list. For
example, the llcp_sock_bind() gets the reference like below:
// llcp_sock_bind()
local = nfc_llcp_find_local(dev); // A
..... \
| raceable
..... /
llcp_sock->local = nfc_llcp_local_get(local); // B
There is an apparent race window that one can drop the reference
and free the local object fetched in (A) before (B) gets the reference.
2. Some callers of the nfc_llcp_find_local() do not grab the reference
at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
error handling function to put the reference.
3. Add the nfc_llcp_remove_local() helper. The local object is removed
from the linked list in local_release() when all reference is gone. This
patch removes it when nfc_llcp_unregister_device() is called.
Therefore, every caller of nfc_llcp_find_local() will get a reference
even when the nfc_llcp_unregister_device() is called. This promises no
use-after-free for the local object is ever possible.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
put_local:
|
|
|
|
nfc_llcp_local_put(local);
|
|
|
|
|
2012-10-17 20:43:39 +08:00
|
|
|
exit:
|
|
|
|
device_unlock(&dev->dev);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
if (msg)
|
|
|
|
nlmsg_free(msg);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
struct nfc_llcp_local *local;
|
|
|
|
u8 rw = 0;
|
|
|
|
u16 miux = 0;
|
|
|
|
u32 idx;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
|
|
|
(!info->attrs[NFC_ATTR_LLC_PARAM_LTO] &&
|
|
|
|
!info->attrs[NFC_ATTR_LLC_PARAM_RW] &&
|
|
|
|
!info->attrs[NFC_ATTR_LLC_PARAM_MIUX]))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) {
|
|
|
|
rw = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_RW]);
|
|
|
|
|
|
|
|
if (rw > LLCP_MAX_RW)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) {
|
|
|
|
miux = nla_get_u16(info->attrs[NFC_ATTR_LLC_PARAM_MIUX]);
|
|
|
|
|
|
|
|
if (miux > LLCP_MAX_MIUX)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
|
|
|
|
|
|
|
local = nfc_llcp_find_local(dev);
|
|
|
|
if (!local) {
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) {
|
|
|
|
if (dev->dep_link_up) {
|
|
|
|
rc = -EINPROGRESS;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
This commit fixes several use-after-free that caused by function
nfc_llcp_find_local(). For example, one UAF can happen when below buggy
time window occurs.
// nfc_genl_llc_get_params | // nfc_unregister_device
|
dev = nfc_get_device(idx); | device_lock(...)
if (!dev) | dev->shutting_down = true;
return -ENODEV; | device_unlock(...);
|
device_lock(...); | // nfc_llcp_unregister_device
| nfc_llcp_find_local()
nfc_llcp_find_local(...); |
| local_cleanup()
if (!local) { |
rc = -ENODEV; | // nfc_llcp_local_put
goto exit; | kref_put(.., local_release)
} |
| // local_release
| list_del(&local->list)
// nfc_genl_send_params | kfree()
local->dev->idx !!!UAF!!! |
|
and the crash trace for the one of the discussed UAF like:
BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
Read of size 8 at addr ffff888105b0e410 by task 20114
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:319 [inline]
print_report+0xcc/0x620 mm/kasan/report.c:430
kasan_report+0xb2/0xe0 mm/kasan/report.c:536
nfc_genl_send_params net/nfc/netlink.c:999 [inline]
nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg+0x1b6/0x200 net/socket.c:747
____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
__sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
RIP: 0033:0x7f34640a2389
RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
</TASK>
Allocated by task 20116:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:374 [inline]
__kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
kmalloc include/linux/slab.h:580 [inline]
kzalloc include/linux/slab.h:720 [inline]
nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
nfc_register_device+0x61/0x260 net/nfc/core.c:1124
nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
misc_open+0x379/0x4a0 drivers/char/misc.c:165
chrdev_open+0x26c/0x780 fs/char_dev.c:414
do_dentry_open+0x6c4/0x12a0 fs/open.c:920
do_open fs/namei.c:3560 [inline]
path_openat+0x24fe/0x37e0 fs/namei.c:3715
do_filp_open+0x1ba/0x410 fs/namei.c:3742
do_sys_openat2+0x171/0x4c0 fs/open.c:1356
do_sys_open fs/open.c:1372 [inline]
__do_sys_openat fs/open.c:1388 [inline]
__se_sys_openat fs/open.c:1383 [inline]
__x64_sys_openat+0x143/0x200 fs/open.c:1383
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Freed by task 20115:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free mm/kasan/common.c:200 [inline]
__kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
kasan_slab_free include/linux/kasan.h:162 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook mm/slub.c:1807 [inline]
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0x7a/0x190 mm/slub.c:3800
local_release net/nfc/llcp_core.c:174 [inline]
kref_put include/linux/kref.h:65 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
__fput+0x252/0xa20 fs/file_table.c:321
task_work_run+0x174/0x270 kernel/task_work.c:179
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
__syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Last potentially related work creation:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
__kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
call_netdevice_notifiers net/core/dev.c:1989 [inline]
dev_change_name+0x3c3/0x870 net/core/dev.c:1211
dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
sock_do_ioctl+0x160/0x260 net/socket.c:1213
sock_ioctl+0x3f9/0x670 net/socket.c:1316
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
The buggy address belongs to the object at ffff888105b0e400
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 16 bytes inside of
freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
The buggy address belongs to the physical page:
head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000010200(slab|head|node=0|zone=2)
raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
In summary, this patch solves those use-after-free by
1. Re-implement the nfc_llcp_find_local(). The current version does not
grab the reference when getting the local from the linked list. For
example, the llcp_sock_bind() gets the reference like below:
// llcp_sock_bind()
local = nfc_llcp_find_local(dev); // A
..... \
| raceable
..... /
llcp_sock->local = nfc_llcp_local_get(local); // B
There is an apparent race window that one can drop the reference
and free the local object fetched in (A) before (B) gets the reference.
2. Some callers of the nfc_llcp_find_local() do not grab the reference
at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
error handling function to put the reference.
3. Add the nfc_llcp_remove_local() helper. The local object is removed
from the linked list in local_release() when all reference is gone. This
patch removes it when nfc_llcp_unregister_device() is called.
Therefore, every caller of nfc_llcp_find_local() will get a reference
even when the nfc_llcp_unregister_device() is called. This promises no
use-after-free for the local object is ever possible.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
goto put_local;
|
2012-10-17 20:43:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->attrs[NFC_ATTR_LLC_PARAM_RW])
|
|
|
|
local->rw = rw;
|
|
|
|
|
|
|
|
if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX])
|
|
|
|
local->miux = cpu_to_be16(miux);
|
|
|
|
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
This commit fixes several use-after-free that caused by function
nfc_llcp_find_local(). For example, one UAF can happen when below buggy
time window occurs.
// nfc_genl_llc_get_params | // nfc_unregister_device
|
dev = nfc_get_device(idx); | device_lock(...)
if (!dev) | dev->shutting_down = true;
return -ENODEV; | device_unlock(...);
|
device_lock(...); | // nfc_llcp_unregister_device
| nfc_llcp_find_local()
nfc_llcp_find_local(...); |
| local_cleanup()
if (!local) { |
rc = -ENODEV; | // nfc_llcp_local_put
goto exit; | kref_put(.., local_release)
} |
| // local_release
| list_del(&local->list)
// nfc_genl_send_params | kfree()
local->dev->idx !!!UAF!!! |
|
and the crash trace for the one of the discussed UAF like:
BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
Read of size 8 at addr ffff888105b0e410 by task 20114
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:319 [inline]
print_report+0xcc/0x620 mm/kasan/report.c:430
kasan_report+0xb2/0xe0 mm/kasan/report.c:536
nfc_genl_send_params net/nfc/netlink.c:999 [inline]
nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg+0x1b6/0x200 net/socket.c:747
____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
__sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
RIP: 0033:0x7f34640a2389
RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
</TASK>
Allocated by task 20116:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:374 [inline]
__kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
kmalloc include/linux/slab.h:580 [inline]
kzalloc include/linux/slab.h:720 [inline]
nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
nfc_register_device+0x61/0x260 net/nfc/core.c:1124
nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
misc_open+0x379/0x4a0 drivers/char/misc.c:165
chrdev_open+0x26c/0x780 fs/char_dev.c:414
do_dentry_open+0x6c4/0x12a0 fs/open.c:920
do_open fs/namei.c:3560 [inline]
path_openat+0x24fe/0x37e0 fs/namei.c:3715
do_filp_open+0x1ba/0x410 fs/namei.c:3742
do_sys_openat2+0x171/0x4c0 fs/open.c:1356
do_sys_open fs/open.c:1372 [inline]
__do_sys_openat fs/open.c:1388 [inline]
__se_sys_openat fs/open.c:1383 [inline]
__x64_sys_openat+0x143/0x200 fs/open.c:1383
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Freed by task 20115:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free mm/kasan/common.c:200 [inline]
__kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
kasan_slab_free include/linux/kasan.h:162 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook mm/slub.c:1807 [inline]
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0x7a/0x190 mm/slub.c:3800
local_release net/nfc/llcp_core.c:174 [inline]
kref_put include/linux/kref.h:65 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
__fput+0x252/0xa20 fs/file_table.c:321
task_work_run+0x174/0x270 kernel/task_work.c:179
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
__syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Last potentially related work creation:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
__kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
call_netdevice_notifiers net/core/dev.c:1989 [inline]
dev_change_name+0x3c3/0x870 net/core/dev.c:1211
dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
sock_do_ioctl+0x160/0x260 net/socket.c:1213
sock_ioctl+0x3f9/0x670 net/socket.c:1316
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
The buggy address belongs to the object at ffff888105b0e400
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 16 bytes inside of
freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
The buggy address belongs to the physical page:
head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000010200(slab|head|node=0|zone=2)
raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
In summary, this patch solves those use-after-free by
1. Re-implement the nfc_llcp_find_local(). The current version does not
grab the reference when getting the local from the linked list. For
example, the llcp_sock_bind() gets the reference like below:
// llcp_sock_bind()
local = nfc_llcp_find_local(dev); // A
..... \
| raceable
..... /
llcp_sock->local = nfc_llcp_local_get(local); // B
There is an apparent race window that one can drop the reference
and free the local object fetched in (A) before (B) gets the reference.
2. Some callers of the nfc_llcp_find_local() do not grab the reference
at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
error handling function to put the reference.
3. Add the nfc_llcp_remove_local() helper. The local object is removed
from the linked list in local_release() when all reference is gone. This
patch removes it when nfc_llcp_unregister_device() is called.
Therefore, every caller of nfc_llcp_find_local() will get a reference
even when the nfc_llcp_unregister_device() is called. This promises no
use-after-free for the local object is ever possible.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
put_local:
|
|
|
|
nfc_llcp_local_put(local);
|
|
|
|
|
2012-10-17 20:43:39 +08:00
|
|
|
exit:
|
|
|
|
device_unlock(&dev->dev);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-02-15 17:43:06 +08:00
|
|
|
static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
struct nfc_llcp_local *local;
|
|
|
|
struct nlattr *attr, *sdp_attrs[NFC_SDP_ATTR_MAX+1];
|
|
|
|
u32 idx;
|
|
|
|
u8 tid;
|
|
|
|
char *uri;
|
|
|
|
int rc = 0, rem;
|
|
|
|
size_t uri_len, tlvs_len;
|
|
|
|
struct hlist_head sdreq_list;
|
|
|
|
struct nfc_llcp_sdp_tlv *sdreq;
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_LLC_SDP])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
2015-10-17 17:32:19 +08:00
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
2013-02-15 17:43:06 +08:00
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
|
|
|
|
|
|
|
if (dev->dep_link_up == false) {
|
|
|
|
rc = -ENOLINK;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
local = nfc_llcp_find_local(dev);
|
|
|
|
if (!local) {
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_HLIST_HEAD(&sdreq_list);
|
|
|
|
|
|
|
|
tlvs_len = 0;
|
|
|
|
|
|
|
|
nla_for_each_nested(attr, info->attrs[NFC_ATTR_LLC_SDP], rem) {
|
netlink: make validation more configurable for future strictness
We currently have two levels of strict validation:
1) liberal (default)
- undefined (type >= max) & NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
- garbage at end of message accepted
2) strict (opt-in)
- NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
Split out parsing strictness into four different options:
* TRAILING - check that there's no trailing data after parsing
attributes (in message or nested)
* MAXTYPE - reject attrs > max known type
* UNSPEC - reject attributes with NLA_UNSPEC policy entries
* STRICT_ATTRS - strictly validate attribute size
The default for future things should be *everything*.
The current *_strict() is a combination of TRAILING and MAXTYPE,
and is renamed to _deprecated_strict().
The current regular parsing has none of this, and is renamed to
*_parse_deprecated().
Additionally it allows us to selectively set one of the new flags
even on old policies. Notably, the UNSPEC flag could be useful in
this case, since it can be arranged (by filling in the policy) to
not be an incompatible userspace ABI change, but would then going
forward prevent forgetting attribute entries. Similar can apply
to the POLICY flag.
We end up with the following renames:
* nla_parse -> nla_parse_deprecated
* nla_parse_strict -> nla_parse_deprecated_strict
* nlmsg_parse -> nlmsg_parse_deprecated
* nlmsg_parse_strict -> nlmsg_parse_deprecated_strict
* nla_parse_nested -> nla_parse_nested_deprecated
* nla_validate_nested -> nla_validate_nested_deprecated
Using spatch, of course:
@@
expression TB, MAX, HEAD, LEN, POL, EXT;
@@
-nla_parse(TB, MAX, HEAD, LEN, POL, EXT)
+nla_parse_deprecated(TB, MAX, HEAD, LEN, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression TB, MAX, NLA, POL, EXT;
@@
-nla_parse_nested(TB, MAX, NLA, POL, EXT)
+nla_parse_nested_deprecated(TB, MAX, NLA, POL, EXT)
@@
expression START, MAX, POL, EXT;
@@
-nla_validate_nested(START, MAX, POL, EXT)
+nla_validate_nested_deprecated(START, MAX, POL, EXT)
@@
expression NLH, HDRLEN, MAX, POL, EXT;
@@
-nlmsg_validate(NLH, HDRLEN, MAX, POL, EXT)
+nlmsg_validate_deprecated(NLH, HDRLEN, MAX, POL, EXT)
For this patch, don't actually add the strict, non-renamed versions
yet so that it breaks compile if I get it wrong.
Also, while at it, make nla_validate and nla_parse go down to a
common __nla_validate_parse() function to avoid code duplication.
Ultimately, this allows us to have very strict validation for every
new caller of nla_parse()/nlmsg_parse() etc as re-introduced in the
next patch, while existing things will continue to work as is.
In effect then, this adds fully strict validation for any new command.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-04-26 20:07:28 +08:00
|
|
|
rc = nla_parse_nested_deprecated(sdp_attrs, NFC_SDP_ATTR_MAX,
|
|
|
|
attr, nfc_sdp_genl_policy,
|
|
|
|
info->extack);
|
2013-02-15 17:43:06 +08:00
|
|
|
|
|
|
|
if (rc != 0) {
|
|
|
|
rc = -EINVAL;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
This commit fixes several use-after-free that caused by function
nfc_llcp_find_local(). For example, one UAF can happen when below buggy
time window occurs.
// nfc_genl_llc_get_params | // nfc_unregister_device
|
dev = nfc_get_device(idx); | device_lock(...)
if (!dev) | dev->shutting_down = true;
return -ENODEV; | device_unlock(...);
|
device_lock(...); | // nfc_llcp_unregister_device
| nfc_llcp_find_local()
nfc_llcp_find_local(...); |
| local_cleanup()
if (!local) { |
rc = -ENODEV; | // nfc_llcp_local_put
goto exit; | kref_put(.., local_release)
} |
| // local_release
| list_del(&local->list)
// nfc_genl_send_params | kfree()
local->dev->idx !!!UAF!!! |
|
and the crash trace for the one of the discussed UAF like:
BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
Read of size 8 at addr ffff888105b0e410 by task 20114
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:319 [inline]
print_report+0xcc/0x620 mm/kasan/report.c:430
kasan_report+0xb2/0xe0 mm/kasan/report.c:536
nfc_genl_send_params net/nfc/netlink.c:999 [inline]
nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg+0x1b6/0x200 net/socket.c:747
____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
__sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
RIP: 0033:0x7f34640a2389
RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
</TASK>
Allocated by task 20116:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:374 [inline]
__kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
kmalloc include/linux/slab.h:580 [inline]
kzalloc include/linux/slab.h:720 [inline]
nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
nfc_register_device+0x61/0x260 net/nfc/core.c:1124
nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
misc_open+0x379/0x4a0 drivers/char/misc.c:165
chrdev_open+0x26c/0x780 fs/char_dev.c:414
do_dentry_open+0x6c4/0x12a0 fs/open.c:920
do_open fs/namei.c:3560 [inline]
path_openat+0x24fe/0x37e0 fs/namei.c:3715
do_filp_open+0x1ba/0x410 fs/namei.c:3742
do_sys_openat2+0x171/0x4c0 fs/open.c:1356
do_sys_open fs/open.c:1372 [inline]
__do_sys_openat fs/open.c:1388 [inline]
__se_sys_openat fs/open.c:1383 [inline]
__x64_sys_openat+0x143/0x200 fs/open.c:1383
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Freed by task 20115:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free mm/kasan/common.c:200 [inline]
__kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
kasan_slab_free include/linux/kasan.h:162 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook mm/slub.c:1807 [inline]
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0x7a/0x190 mm/slub.c:3800
local_release net/nfc/llcp_core.c:174 [inline]
kref_put include/linux/kref.h:65 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
__fput+0x252/0xa20 fs/file_table.c:321
task_work_run+0x174/0x270 kernel/task_work.c:179
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
__syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Last potentially related work creation:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
__kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
call_netdevice_notifiers net/core/dev.c:1989 [inline]
dev_change_name+0x3c3/0x870 net/core/dev.c:1211
dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
sock_do_ioctl+0x160/0x260 net/socket.c:1213
sock_ioctl+0x3f9/0x670 net/socket.c:1316
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
The buggy address belongs to the object at ffff888105b0e400
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 16 bytes inside of
freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
The buggy address belongs to the physical page:
head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000010200(slab|head|node=0|zone=2)
raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
In summary, this patch solves those use-after-free by
1. Re-implement the nfc_llcp_find_local(). The current version does not
grab the reference when getting the local from the linked list. For
example, the llcp_sock_bind() gets the reference like below:
// llcp_sock_bind()
local = nfc_llcp_find_local(dev); // A
..... \
| raceable
..... /
llcp_sock->local = nfc_llcp_local_get(local); // B
There is an apparent race window that one can drop the reference
and free the local object fetched in (A) before (B) gets the reference.
2. Some callers of the nfc_llcp_find_local() do not grab the reference
at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
error handling function to put the reference.
3. Add the nfc_llcp_remove_local() helper. The local object is removed
from the linked list in local_release() when all reference is gone. This
patch removes it when nfc_llcp_unregister_device() is called.
Therefore, every caller of nfc_llcp_find_local() will get a reference
even when the nfc_llcp_unregister_device() is called. This promises no
use-after-free for the local object is ever possible.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
goto put_local;
|
2013-02-15 17:43:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!sdp_attrs[NFC_SDP_ATTR_URI])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
uri_len = nla_len(sdp_attrs[NFC_SDP_ATTR_URI]);
|
|
|
|
if (uri_len == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
uri = nla_data(sdp_attrs[NFC_SDP_ATTR_URI]);
|
|
|
|
if (uri == NULL || *uri == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tid = local->sdreq_next_tid++;
|
|
|
|
|
|
|
|
sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len);
|
|
|
|
if (sdreq == NULL) {
|
|
|
|
rc = -ENOMEM;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
This commit fixes several use-after-free that caused by function
nfc_llcp_find_local(). For example, one UAF can happen when below buggy
time window occurs.
// nfc_genl_llc_get_params | // nfc_unregister_device
|
dev = nfc_get_device(idx); | device_lock(...)
if (!dev) | dev->shutting_down = true;
return -ENODEV; | device_unlock(...);
|
device_lock(...); | // nfc_llcp_unregister_device
| nfc_llcp_find_local()
nfc_llcp_find_local(...); |
| local_cleanup()
if (!local) { |
rc = -ENODEV; | // nfc_llcp_local_put
goto exit; | kref_put(.., local_release)
} |
| // local_release
| list_del(&local->list)
// nfc_genl_send_params | kfree()
local->dev->idx !!!UAF!!! |
|
and the crash trace for the one of the discussed UAF like:
BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
Read of size 8 at addr ffff888105b0e410 by task 20114
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:319 [inline]
print_report+0xcc/0x620 mm/kasan/report.c:430
kasan_report+0xb2/0xe0 mm/kasan/report.c:536
nfc_genl_send_params net/nfc/netlink.c:999 [inline]
nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg+0x1b6/0x200 net/socket.c:747
____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
__sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
RIP: 0033:0x7f34640a2389
RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
</TASK>
Allocated by task 20116:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:374 [inline]
__kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
kmalloc include/linux/slab.h:580 [inline]
kzalloc include/linux/slab.h:720 [inline]
nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
nfc_register_device+0x61/0x260 net/nfc/core.c:1124
nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
misc_open+0x379/0x4a0 drivers/char/misc.c:165
chrdev_open+0x26c/0x780 fs/char_dev.c:414
do_dentry_open+0x6c4/0x12a0 fs/open.c:920
do_open fs/namei.c:3560 [inline]
path_openat+0x24fe/0x37e0 fs/namei.c:3715
do_filp_open+0x1ba/0x410 fs/namei.c:3742
do_sys_openat2+0x171/0x4c0 fs/open.c:1356
do_sys_open fs/open.c:1372 [inline]
__do_sys_openat fs/open.c:1388 [inline]
__se_sys_openat fs/open.c:1383 [inline]
__x64_sys_openat+0x143/0x200 fs/open.c:1383
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Freed by task 20115:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free mm/kasan/common.c:200 [inline]
__kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
kasan_slab_free include/linux/kasan.h:162 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook mm/slub.c:1807 [inline]
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0x7a/0x190 mm/slub.c:3800
local_release net/nfc/llcp_core.c:174 [inline]
kref_put include/linux/kref.h:65 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
__fput+0x252/0xa20 fs/file_table.c:321
task_work_run+0x174/0x270 kernel/task_work.c:179
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
__syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Last potentially related work creation:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
__kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
call_netdevice_notifiers net/core/dev.c:1989 [inline]
dev_change_name+0x3c3/0x870 net/core/dev.c:1211
dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
sock_do_ioctl+0x160/0x260 net/socket.c:1213
sock_ioctl+0x3f9/0x670 net/socket.c:1316
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
The buggy address belongs to the object at ffff888105b0e400
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 16 bytes inside of
freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
The buggy address belongs to the physical page:
head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000010200(slab|head|node=0|zone=2)
raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
In summary, this patch solves those use-after-free by
1. Re-implement the nfc_llcp_find_local(). The current version does not
grab the reference when getting the local from the linked list. For
example, the llcp_sock_bind() gets the reference like below:
// llcp_sock_bind()
local = nfc_llcp_find_local(dev); // A
..... \
| raceable
..... /
llcp_sock->local = nfc_llcp_local_get(local); // B
There is an apparent race window that one can drop the reference
and free the local object fetched in (A) before (B) gets the reference.
2. Some callers of the nfc_llcp_find_local() do not grab the reference
at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
error handling function to put the reference.
3. Add the nfc_llcp_remove_local() helper. The local object is removed
from the linked list in local_release() when all reference is gone. This
patch removes it when nfc_llcp_unregister_device() is called.
Therefore, every caller of nfc_llcp_find_local() will get a reference
even when the nfc_llcp_unregister_device() is called. This promises no
use-after-free for the local object is ever possible.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
goto put_local;
|
2013-02-15 17:43:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
tlvs_len += sdreq->tlv_len;
|
|
|
|
|
|
|
|
hlist_add_head(&sdreq->node, &sdreq_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hlist_empty(&sdreq_list)) {
|
|
|
|
rc = -EINVAL;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
This commit fixes several use-after-free that caused by function
nfc_llcp_find_local(). For example, one UAF can happen when below buggy
time window occurs.
// nfc_genl_llc_get_params | // nfc_unregister_device
|
dev = nfc_get_device(idx); | device_lock(...)
if (!dev) | dev->shutting_down = true;
return -ENODEV; | device_unlock(...);
|
device_lock(...); | // nfc_llcp_unregister_device
| nfc_llcp_find_local()
nfc_llcp_find_local(...); |
| local_cleanup()
if (!local) { |
rc = -ENODEV; | // nfc_llcp_local_put
goto exit; | kref_put(.., local_release)
} |
| // local_release
| list_del(&local->list)
// nfc_genl_send_params | kfree()
local->dev->idx !!!UAF!!! |
|
and the crash trace for the one of the discussed UAF like:
BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
Read of size 8 at addr ffff888105b0e410 by task 20114
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:319 [inline]
print_report+0xcc/0x620 mm/kasan/report.c:430
kasan_report+0xb2/0xe0 mm/kasan/report.c:536
nfc_genl_send_params net/nfc/netlink.c:999 [inline]
nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg+0x1b6/0x200 net/socket.c:747
____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
__sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
RIP: 0033:0x7f34640a2389
RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
</TASK>
Allocated by task 20116:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:374 [inline]
__kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
kmalloc include/linux/slab.h:580 [inline]
kzalloc include/linux/slab.h:720 [inline]
nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
nfc_register_device+0x61/0x260 net/nfc/core.c:1124
nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
misc_open+0x379/0x4a0 drivers/char/misc.c:165
chrdev_open+0x26c/0x780 fs/char_dev.c:414
do_dentry_open+0x6c4/0x12a0 fs/open.c:920
do_open fs/namei.c:3560 [inline]
path_openat+0x24fe/0x37e0 fs/namei.c:3715
do_filp_open+0x1ba/0x410 fs/namei.c:3742
do_sys_openat2+0x171/0x4c0 fs/open.c:1356
do_sys_open fs/open.c:1372 [inline]
__do_sys_openat fs/open.c:1388 [inline]
__se_sys_openat fs/open.c:1383 [inline]
__x64_sys_openat+0x143/0x200 fs/open.c:1383
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Freed by task 20115:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free mm/kasan/common.c:200 [inline]
__kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
kasan_slab_free include/linux/kasan.h:162 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook mm/slub.c:1807 [inline]
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0x7a/0x190 mm/slub.c:3800
local_release net/nfc/llcp_core.c:174 [inline]
kref_put include/linux/kref.h:65 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
__fput+0x252/0xa20 fs/file_table.c:321
task_work_run+0x174/0x270 kernel/task_work.c:179
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
__syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Last potentially related work creation:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
__kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
call_netdevice_notifiers net/core/dev.c:1989 [inline]
dev_change_name+0x3c3/0x870 net/core/dev.c:1211
dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
sock_do_ioctl+0x160/0x260 net/socket.c:1213
sock_ioctl+0x3f9/0x670 net/socket.c:1316
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
The buggy address belongs to the object at ffff888105b0e400
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 16 bytes inside of
freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
The buggy address belongs to the physical page:
head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000010200(slab|head|node=0|zone=2)
raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
In summary, this patch solves those use-after-free by
1. Re-implement the nfc_llcp_find_local(). The current version does not
grab the reference when getting the local from the linked list. For
example, the llcp_sock_bind() gets the reference like below:
// llcp_sock_bind()
local = nfc_llcp_find_local(dev); // A
..... \
| raceable
..... /
llcp_sock->local = nfc_llcp_local_get(local); // B
There is an apparent race window that one can drop the reference
and free the local object fetched in (A) before (B) gets the reference.
2. Some callers of the nfc_llcp_find_local() do not grab the reference
at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
error handling function to put the reference.
3. Add the nfc_llcp_remove_local() helper. The local object is removed
from the linked list in local_release() when all reference is gone. This
patch removes it when nfc_llcp_unregister_device() is called.
Therefore, every caller of nfc_llcp_find_local() will get a reference
even when the nfc_llcp_unregister_device() is called. This promises no
use-after-free for the local object is ever possible.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
goto put_local;
|
2013-02-15 17:43:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len);
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
This commit fixes several use-after-free that caused by function
nfc_llcp_find_local(). For example, one UAF can happen when below buggy
time window occurs.
// nfc_genl_llc_get_params | // nfc_unregister_device
|
dev = nfc_get_device(idx); | device_lock(...)
if (!dev) | dev->shutting_down = true;
return -ENODEV; | device_unlock(...);
|
device_lock(...); | // nfc_llcp_unregister_device
| nfc_llcp_find_local()
nfc_llcp_find_local(...); |
| local_cleanup()
if (!local) { |
rc = -ENODEV; | // nfc_llcp_local_put
goto exit; | kref_put(.., local_release)
} |
| // local_release
| list_del(&local->list)
// nfc_genl_send_params | kfree()
local->dev->idx !!!UAF!!! |
|
and the crash trace for the one of the discussed UAF like:
BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
Read of size 8 at addr ffff888105b0e410 by task 20114
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:319 [inline]
print_report+0xcc/0x620 mm/kasan/report.c:430
kasan_report+0xb2/0xe0 mm/kasan/report.c:536
nfc_genl_send_params net/nfc/netlink.c:999 [inline]
nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg+0x1b6/0x200 net/socket.c:747
____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
__sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
RIP: 0033:0x7f34640a2389
RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
</TASK>
Allocated by task 20116:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:374 [inline]
__kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
kmalloc include/linux/slab.h:580 [inline]
kzalloc include/linux/slab.h:720 [inline]
nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
nfc_register_device+0x61/0x260 net/nfc/core.c:1124
nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
misc_open+0x379/0x4a0 drivers/char/misc.c:165
chrdev_open+0x26c/0x780 fs/char_dev.c:414
do_dentry_open+0x6c4/0x12a0 fs/open.c:920
do_open fs/namei.c:3560 [inline]
path_openat+0x24fe/0x37e0 fs/namei.c:3715
do_filp_open+0x1ba/0x410 fs/namei.c:3742
do_sys_openat2+0x171/0x4c0 fs/open.c:1356
do_sys_open fs/open.c:1372 [inline]
__do_sys_openat fs/open.c:1388 [inline]
__se_sys_openat fs/open.c:1383 [inline]
__x64_sys_openat+0x143/0x200 fs/open.c:1383
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Freed by task 20115:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free mm/kasan/common.c:200 [inline]
__kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
kasan_slab_free include/linux/kasan.h:162 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook mm/slub.c:1807 [inline]
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0x7a/0x190 mm/slub.c:3800
local_release net/nfc/llcp_core.c:174 [inline]
kref_put include/linux/kref.h:65 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
__fput+0x252/0xa20 fs/file_table.c:321
task_work_run+0x174/0x270 kernel/task_work.c:179
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
__syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x72/0xdc
Last potentially related work creation:
kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
__kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
call_netdevice_notifiers net/core/dev.c:1989 [inline]
dev_change_name+0x3c3/0x870 net/core/dev.c:1211
dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
sock_do_ioctl+0x160/0x260 net/socket.c:1213
sock_ioctl+0x3f9/0x670 net/socket.c:1316
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x72/0xdc
The buggy address belongs to the object at ffff888105b0e400
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 16 bytes inside of
freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
The buggy address belongs to the physical page:
head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000010200(slab|head|node=0|zone=2)
raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
In summary, this patch solves those use-after-free by
1. Re-implement the nfc_llcp_find_local(). The current version does not
grab the reference when getting the local from the linked list. For
example, the llcp_sock_bind() gets the reference like below:
// llcp_sock_bind()
local = nfc_llcp_find_local(dev); // A
..... \
| raceable
..... /
llcp_sock->local = nfc_llcp_local_get(local); // B
There is an apparent race window that one can drop the reference
and free the local object fetched in (A) before (B) gets the reference.
2. Some callers of the nfc_llcp_find_local() do not grab the reference
at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
error handling function to put the reference.
3. Add the nfc_llcp_remove_local() helper. The local object is removed
from the linked list in local_release() when all reference is gone. This
patch removes it when nfc_llcp_unregister_device() is called.
Therefore, every caller of nfc_llcp_find_local() will get a reference
even when the nfc_llcp_unregister_device() is called. This promises no
use-after-free for the local object is ever possible.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
|
|
|
|
put_local:
|
|
|
|
nfc_llcp_local_put(local);
|
|
|
|
|
2013-02-15 17:43:06 +08:00
|
|
|
exit:
|
|
|
|
device_unlock(&dev->dev);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-07-31 07:19:43 +08:00
|
|
|
static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info)
|
2013-04-29 23:13:27 +08:00
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc;
|
|
|
|
u32 idx;
|
|
|
|
char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
|
|
|
|
|
2020-10-19 19:38:58 +08:00
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || !info->attrs[NFC_ATTR_FIRMWARE_NAME])
|
2013-04-29 23:13:27 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2020-11-16 01:08:06 +08:00
|
|
|
nla_strscpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME],
|
2013-04-29 23:13:27 +08:00
|
|
|
sizeof(firmware_name));
|
|
|
|
|
2013-07-31 07:19:43 +08:00
|
|
|
rc = nfc_fw_download(dev, firmware_name);
|
2013-04-29 23:13:27 +08:00
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-07-19 20:57:55 +08:00
|
|
|
int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
|
|
|
|
u32 result)
|
2013-04-29 23:13:27 +08:00
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
2022-05-04 13:58:47 +08:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
2013-04-29 23:13:27 +08:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
2013-07-31 07:19:43 +08:00
|
|
|
NFC_CMD_FW_DOWNLOAD);
|
2013-04-29 23:13:27 +08:00
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_string(msg, NFC_ATTR_FIRMWARE_NAME, firmware_name) ||
|
2013-07-19 20:57:55 +08:00
|
|
|
nla_put_u32(msg, NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS, result) ||
|
2013-04-29 23:13:27 +08:00
|
|
|
nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2022-05-04 13:58:47 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
|
2013-04-29 23:13:27 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2013-05-10 23:07:32 +08:00
|
|
|
static int nfc_genl_enable_se(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc;
|
|
|
|
u32 idx, se_idx;
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_SE_INDEX])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
rc = nfc_enable_se(dev, se_idx);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
int rc;
|
|
|
|
u32 idx, se_idx;
|
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_SE_INDEX])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
rc = nfc_disable_se(dev, se_idx);
|
|
|
|
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-07-25 00:10:50 +08:00
|
|
|
static int nfc_genl_send_se(struct sk_buff *msg, struct nfc_dev *dev,
|
|
|
|
u32 portid, u32 seq,
|
|
|
|
struct netlink_callback *cb,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
struct nfc_se *se, *n;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(se, n, &dev->secure_elements, list) {
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags,
|
|
|
|
NFC_CMD_GET_SE);
|
|
|
|
if (!hdr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (cb)
|
2017-11-15 20:09:32 +08:00
|
|
|
genl_dump_check_consistent(cb, hdr);
|
2013-07-25 00:10:50 +08:00
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_SE_INDEX, se->idx) ||
|
|
|
|
nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
genlmsg_end(msg, hdr);
|
2013-07-25 00:10:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_dump_ses(struct sk_buff *skb,
|
|
|
|
struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
|
|
|
|
struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
|
|
|
|
bool first_call = false;
|
|
|
|
|
|
|
|
if (!iter) {
|
|
|
|
first_call = true;
|
|
|
|
iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
|
|
|
|
if (!iter)
|
|
|
|
return -ENOMEM;
|
|
|
|
cb->args[0] = (long) iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&nfc_devlist_mutex);
|
|
|
|
|
|
|
|
cb->seq = nfc_devlist_generation;
|
|
|
|
|
|
|
|
if (first_call) {
|
|
|
|
nfc_device_iter_init(iter);
|
|
|
|
dev = nfc_device_iter_next(iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (dev) {
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = nfc_genl_send_se(skb, dev, NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
|
|
|
|
if (rc < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
dev = nfc_device_iter_next(iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&nfc_devlist_mutex);
|
|
|
|
|
|
|
|
cb->args[1] = (long) dev;
|
|
|
|
|
|
|
|
return skb->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_dump_ses_done(struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
|
|
|
|
|
2021-12-09 16:13:07 +08:00
|
|
|
if (iter) {
|
|
|
|
nfc_device_iter_exit(iter);
|
|
|
|
kfree(iter);
|
|
|
|
}
|
2013-07-25 00:10:50 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-03 04:27:51 +08:00
|
|
|
static int nfc_se_io(struct nfc_dev *dev, u32 se_idx,
|
|
|
|
u8 *apdu, size_t apdu_length,
|
|
|
|
se_io_cb_t cb, void *cb_context)
|
|
|
|
{
|
|
|
|
struct nfc_se *se;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
pr_debug("%s se index %d\n", dev_name(&dev->dev), se_idx);
|
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
|
|
|
|
|
|
|
if (!device_is_registered(&dev->dev)) {
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dev->dev_up) {
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dev->ops->se_io) {
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
se = nfc_find_se(dev, se_idx);
|
|
|
|
if (!se) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (se->state != NFC_SE_ENABLED) {
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = dev->ops->se_io(dev, se_idx, apdu,
|
|
|
|
apdu_length, cb, cb_context);
|
|
|
|
|
2023-02-25 18:56:14 +08:00
|
|
|
device_unlock(&dev->dev);
|
|
|
|
return rc;
|
|
|
|
|
2014-12-03 04:27:51 +08:00
|
|
|
error:
|
|
|
|
device_unlock(&dev->dev);
|
2023-03-07 05:26:50 +08:00
|
|
|
kfree(cb_context);
|
2014-12-03 04:27:51 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-08-28 06:47:24 +08:00
|
|
|
struct se_io_ctx {
|
|
|
|
u32 dev_idx;
|
|
|
|
u32 se_idx;
|
|
|
|
};
|
|
|
|
|
2013-10-07 20:18:44 +08:00
|
|
|
static void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err)
|
2013-08-28 06:47:24 +08:00
|
|
|
{
|
|
|
|
struct se_io_ctx *ctx = context;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg) {
|
|
|
|
kfree(ctx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
|
|
|
NFC_CMD_SE_IO);
|
|
|
|
if (!hdr)
|
|
|
|
goto free_msg;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, ctx->dev_idx) ||
|
|
|
|
nla_put_u32(msg, NFC_ATTR_SE_INDEX, ctx->se_idx) ||
|
|
|
|
nla_put(msg, NFC_ATTR_SE_APDU, apdu_len, apdu))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
|
2013-08-28 06:47:24 +08:00
|
|
|
|
|
|
|
kfree(ctx);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
free_msg:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
kfree(ctx);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
struct se_io_ctx *ctx;
|
|
|
|
u32 dev_idx, se_idx;
|
|
|
|
u8 *apdu;
|
|
|
|
size_t apdu_len;
|
2022-12-23 15:37:18 +08:00
|
|
|
int rc;
|
2013-08-28 06:47:24 +08:00
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_SE_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_SE_APDU])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dev_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(dev_idx);
|
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2022-12-23 15:37:18 +08:00
|
|
|
if (!dev->ops || !dev->ops->se_io) {
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
2013-08-28 06:47:24 +08:00
|
|
|
|
|
|
|
apdu_len = nla_len(info->attrs[NFC_ATTR_SE_APDU]);
|
2022-12-23 15:37:18 +08:00
|
|
|
if (apdu_len == 0) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
2013-08-28 06:47:24 +08:00
|
|
|
|
|
|
|
apdu = nla_data(info->attrs[NFC_ATTR_SE_APDU]);
|
2022-12-23 15:37:18 +08:00
|
|
|
if (!apdu) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
2013-08-28 06:47:24 +08:00
|
|
|
|
|
|
|
ctx = kzalloc(sizeof(struct se_io_ctx), GFP_KERNEL);
|
2022-12-23 15:37:18 +08:00
|
|
|
if (!ctx) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
2013-08-28 06:47:24 +08:00
|
|
|
|
|
|
|
ctx->dev_idx = dev_idx;
|
|
|
|
ctx->se_idx = se_idx;
|
|
|
|
|
2022-12-23 15:37:18 +08:00
|
|
|
rc = nfc_se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx);
|
|
|
|
|
|
|
|
put_dev:
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return rc;
|
2013-08-28 06:47:24 +08:00
|
|
|
}
|
|
|
|
|
2014-10-14 08:19:46 +08:00
|
|
|
static int nfc_genl_vendor_cmd(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev;
|
2021-07-25 05:49:23 +08:00
|
|
|
const struct nfc_vendor_cmd *cmd;
|
2014-10-14 08:19:46 +08:00
|
|
|
u32 dev_idx, vid, subcmd;
|
|
|
|
u8 *data;
|
|
|
|
size_t data_len;
|
2015-08-20 03:26:43 +08:00
|
|
|
int i, err;
|
2014-10-14 08:19:46 +08:00
|
|
|
|
|
|
|
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
|
|
|
!info->attrs[NFC_ATTR_VENDOR_ID] ||
|
|
|
|
!info->attrs[NFC_ATTR_VENDOR_SUBCMD])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dev_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
|
|
|
vid = nla_get_u32(info->attrs[NFC_ATTR_VENDOR_ID]);
|
|
|
|
subcmd = nla_get_u32(info->attrs[NFC_ATTR_VENDOR_SUBCMD]);
|
|
|
|
|
|
|
|
dev = nfc_get_device(dev_idx);
|
2022-12-23 15:37:18 +08:00
|
|
|
if (!dev)
|
2014-10-14 08:19:46 +08:00
|
|
|
return -ENODEV;
|
|
|
|
|
2022-12-23 15:37:18 +08:00
|
|
|
if (!dev->vendor_cmds || !dev->n_vendor_cmds) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
|
|
|
|
2015-08-15 04:33:40 +08:00
|
|
|
if (info->attrs[NFC_ATTR_VENDOR_DATA]) {
|
|
|
|
data = nla_data(info->attrs[NFC_ATTR_VENDOR_DATA]);
|
2014-10-14 08:19:46 +08:00
|
|
|
data_len = nla_len(info->attrs[NFC_ATTR_VENDOR_DATA]);
|
2022-12-23 15:37:18 +08:00
|
|
|
if (data_len == 0) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
2014-10-14 08:19:46 +08:00
|
|
|
} else {
|
2015-08-17 14:33:43 +08:00
|
|
|
data = NULL;
|
2014-10-14 08:19:46 +08:00
|
|
|
data_len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < dev->n_vendor_cmds; i++) {
|
|
|
|
cmd = &dev->vendor_cmds[i];
|
|
|
|
|
|
|
|
if (cmd->vendor_id != vid || cmd->subcmd != subcmd)
|
|
|
|
continue;
|
|
|
|
|
2015-08-20 03:26:43 +08:00
|
|
|
dev->cur_cmd_info = info;
|
|
|
|
err = cmd->doit(dev, data, data_len);
|
|
|
|
dev->cur_cmd_info = NULL;
|
2022-12-23 15:37:18 +08:00
|
|
|
goto put_dev;
|
2014-10-14 08:19:46 +08:00
|
|
|
}
|
|
|
|
|
2022-12-23 15:37:18 +08:00
|
|
|
err = -EOPNOTSUPP;
|
|
|
|
|
|
|
|
put_dev:
|
|
|
|
nfc_put_device(dev);
|
|
|
|
return err;
|
2014-10-14 08:19:46 +08:00
|
|
|
}
|
|
|
|
|
2015-08-20 03:26:43 +08:00
|
|
|
/* message building helper */
|
|
|
|
static inline void *nfc_hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
|
|
|
|
int flags, u8 cmd)
|
|
|
|
{
|
|
|
|
/* since there is no private header just add the generic one */
|
|
|
|
return genlmsg_put(skb, portid, seq, &nfc_genl_family, flags, cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *
|
|
|
|
__nfc_alloc_vendor_cmd_skb(struct nfc_dev *dev, int approxlen,
|
|
|
|
u32 portid, u32 seq,
|
|
|
|
enum nfc_attrs attr,
|
|
|
|
u32 oui, u32 subcmd, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
skb = nlmsg_new(approxlen + 100, gfp);
|
|
|
|
if (!skb)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
hdr = nfc_hdr_put(skb, portid, seq, 0, NFC_CMD_VENDOR);
|
|
|
|
if (!hdr) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nla_put_u32(skb, NFC_ATTR_DEVICE_INDEX, dev->idx))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(skb, NFC_ATTR_VENDOR_ID, oui))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(skb, NFC_ATTR_VENDOR_SUBCMD, subcmd))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
((void **)skb->cb)[0] = dev;
|
|
|
|
((void **)skb->cb)[1] = hdr;
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
kfree_skb(skb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sk_buff *__nfc_alloc_vendor_cmd_reply_skb(struct nfc_dev *dev,
|
|
|
|
enum nfc_attrs attr,
|
|
|
|
u32 oui, u32 subcmd,
|
|
|
|
int approxlen)
|
|
|
|
{
|
|
|
|
if (WARN_ON(!dev->cur_cmd_info))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return __nfc_alloc_vendor_cmd_skb(dev, approxlen,
|
|
|
|
dev->cur_cmd_info->snd_portid,
|
|
|
|
dev->cur_cmd_info->snd_seq, attr,
|
|
|
|
oui, subcmd, GFP_KERNEL);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__nfc_alloc_vendor_cmd_reply_skb);
|
|
|
|
|
|
|
|
int nfc_vendor_cmd_reply(struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct nfc_dev *dev = ((void **)skb->cb)[0];
|
|
|
|
void *hdr = ((void **)skb->cb)[1];
|
|
|
|
|
|
|
|
/* clear CB data for netlink core to own from now on */
|
|
|
|
memset(skb->cb, 0, sizeof(skb->cb));
|
|
|
|
|
|
|
|
if (WARN_ON(!dev->cur_cmd_info)) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
return genlmsg_reply(skb, dev->cur_cmd_info);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(nfc_vendor_cmd_reply);
|
|
|
|
|
2013-11-15 00:14:46 +08:00
|
|
|
static const struct genl_ops nfc_genl_ops[] = {
|
2011-07-02 06:31:34 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_GET_DEVICE,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2011-07-02 06:31:34 +08:00
|
|
|
.doit = nfc_genl_get_device,
|
|
|
|
.dumpit = nfc_genl_dump_devices,
|
|
|
|
.done = nfc_genl_dump_devices_done,
|
2011-09-18 16:19:33 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_DEV_UP,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2011-09-18 16:19:33 +08:00
|
|
|
.doit = nfc_genl_dev_up,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2011-09-18 16:19:33 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_DEV_DOWN,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2011-09-18 16:19:33 +08:00
|
|
|
.doit = nfc_genl_dev_down,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2011-07-02 06:31:34 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_START_POLL,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2011-07-02 06:31:34 +08:00
|
|
|
.doit = nfc_genl_start_poll,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2011-07-02 06:31:34 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_STOP_POLL,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2011-07-02 06:31:34 +08:00
|
|
|
.doit = nfc_genl_stop_poll,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2011-07-02 06:31:34 +08:00
|
|
|
},
|
2011-12-14 23:43:09 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_DEP_LINK_UP,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2011-12-14 23:43:09 +08:00
|
|
|
.doit = nfc_genl_dep_link_up,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2011-12-14 23:43:09 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_DEP_LINK_DOWN,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2011-12-14 23:43:09 +08:00
|
|
|
.doit = nfc_genl_dep_link_down,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2011-12-14 23:43:09 +08:00
|
|
|
},
|
2011-07-02 06:31:34 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_GET_TARGET,
|
2019-10-06 02:04:38 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT |
|
|
|
|
GENL_DONT_VALIDATE_DUMP_STRICT,
|
2011-07-02 06:31:34 +08:00
|
|
|
.dumpit = nfc_genl_dump_targets,
|
|
|
|
.done = nfc_genl_dump_targets_done,
|
|
|
|
},
|
2012-10-17 20:43:39 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_LLC_GET_PARAMS,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2012-10-17 20:43:39 +08:00
|
|
|
.doit = nfc_genl_llc_get_params,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_LLC_SET_PARAMS,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2012-10-17 20:43:39 +08:00
|
|
|
.doit = nfc_genl_llc_set_params,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2012-10-17 20:43:39 +08:00
|
|
|
},
|
2013-02-15 17:43:06 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_LLC_SDREQ,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2013-02-15 17:43:06 +08:00
|
|
|
.doit = nfc_genl_llc_sdreq,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2013-02-15 17:43:06 +08:00
|
|
|
},
|
2013-04-29 23:13:27 +08:00
|
|
|
{
|
2013-07-31 07:19:43 +08:00
|
|
|
.cmd = NFC_CMD_FW_DOWNLOAD,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2013-07-31 07:19:43 +08:00
|
|
|
.doit = nfc_genl_fw_download,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2013-04-29 23:13:27 +08:00
|
|
|
},
|
2013-05-10 23:07:32 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_ENABLE_SE,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2013-05-10 23:07:32 +08:00
|
|
|
.doit = nfc_genl_enable_se,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2013-05-10 23:07:32 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_DISABLE_SE,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2013-05-10 23:07:32 +08:00
|
|
|
.doit = nfc_genl_disable_se,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2013-05-10 23:07:32 +08:00
|
|
|
},
|
2013-07-25 00:10:50 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_GET_SE,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2013-07-25 00:10:50 +08:00
|
|
|
.dumpit = nfc_genl_dump_ses,
|
|
|
|
.done = nfc_genl_dump_ses_done,
|
|
|
|
},
|
2013-08-28 06:47:24 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_SE_IO,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2013-08-28 06:47:24 +08:00
|
|
|
.doit = nfc_genl_se_io,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2013-08-28 06:47:24 +08:00
|
|
|
},
|
2014-12-03 04:27:50 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_ACTIVATE_TARGET,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2014-12-03 04:27:50 +08:00
|
|
|
.doit = nfc_genl_activate_target,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2014-12-03 04:27:50 +08:00
|
|
|
},
|
2014-10-14 08:19:46 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_VENDOR,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2014-10-14 08:19:46 +08:00
|
|
|
.doit = nfc_genl_vendor_cmd,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2014-10-14 08:19:46 +08:00
|
|
|
},
|
2017-06-16 11:34:22 +08:00
|
|
|
{
|
|
|
|
.cmd = NFC_CMD_DEACTIVATE_TARGET,
|
2019-04-26 20:07:31 +08:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2017-06-16 11:34:22 +08:00
|
|
|
.doit = nfc_genl_deactivate_target,
|
2021-11-02 16:10:21 +08:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
2017-06-16 11:34:22 +08:00
|
|
|
},
|
2011-07-02 06:31:34 +08:00
|
|
|
};
|
|
|
|
|
2016-10-24 20:40:05 +08:00
|
|
|
static struct genl_family nfc_genl_family __ro_after_init = {
|
2016-10-24 20:40:03 +08:00
|
|
|
.hdrsize = 0,
|
|
|
|
.name = NFC_GENL_NAME,
|
|
|
|
.version = NFC_GENL_VERSION,
|
|
|
|
.maxattr = NFC_ATTR_MAX,
|
genetlink: make policy common to family
Since maxattr is common, the policy can't really differ sanely,
so make it common as well.
The only user that did in fact manage to make a non-common policy
is taskstats, which has to be really careful about it (since it's
still using a common maxattr!). This is no longer supported, but
we can fake it using pre_doit.
This reduces the size of e.g. nl80211.o (which has lots of commands):
text data bss dec hex filename
398745 14323 2240 415308 6564c net/wireless/nl80211.o (before)
397913 14331 2240 414484 65314 net/wireless/nl80211.o (after)
--------------------------------
-832 +8 0 -824
Which is obviously just 8 bytes for each command, and an added 8
bytes for the new policy pointer. I'm not sure why the ops list is
counted as .text though.
Most of the code transformations were done using the following spatch:
@ops@
identifier OPS;
expression POLICY;
@@
struct genl_ops OPS[] = {
...,
{
- .policy = POLICY,
},
...
};
@@
identifier ops.OPS;
expression ops.POLICY;
identifier fam;
expression M;
@@
struct genl_family fam = {
.ops = OPS,
.maxattr = M,
+ .policy = POLICY,
...
};
This also gets rid of devlink_nl_cmd_region_read_dumpit() accessing
the cb->data as ops, which we want to change in a later genl patch.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-03-22 05:51:02 +08:00
|
|
|
.policy = nfc_genl_policy,
|
2016-10-24 20:40:03 +08:00
|
|
|
.module = THIS_MODULE,
|
|
|
|
.ops = nfc_genl_ops,
|
|
|
|
.n_ops = ARRAY_SIZE(nfc_genl_ops),
|
2022-08-25 08:18:30 +08:00
|
|
|
.resv_start_op = NFC_CMD_DEACTIVATE_TARGET + 1,
|
2016-10-24 20:40:03 +08:00
|
|
|
.mcgrps = nfc_genl_mcgrps,
|
|
|
|
.n_mcgrps = ARRAY_SIZE(nfc_genl_mcgrps),
|
|
|
|
};
|
|
|
|
|
2012-09-26 20:17:12 +08:00
|
|
|
|
|
|
|
struct urelease_work {
|
|
|
|
struct work_struct w;
|
2015-04-13 06:52:36 +08:00
|
|
|
u32 portid;
|
2012-09-26 20:17:12 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static void nfc_urelease_event_work(struct work_struct *work)
|
2011-07-02 06:31:34 +08:00
|
|
|
{
|
2012-09-26 20:17:12 +08:00
|
|
|
struct urelease_work *w = container_of(work, struct urelease_work, w);
|
2011-07-02 06:31:34 +08:00
|
|
|
struct class_dev_iter iter;
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
|
2012-09-28 23:11:16 +08:00
|
|
|
pr_debug("portid %d\n", w->portid);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
2012-09-26 20:17:12 +08:00
|
|
|
mutex_lock(&nfc_devlist_mutex);
|
2011-07-02 06:31:34 +08:00
|
|
|
|
|
|
|
nfc_device_iter_init(&iter);
|
|
|
|
dev = nfc_device_iter_next(&iter);
|
|
|
|
|
|
|
|
while (dev) {
|
2012-09-26 20:17:12 +08:00
|
|
|
mutex_lock(&dev->genl_data.genl_data_mutex);
|
|
|
|
|
2012-09-28 23:11:16 +08:00
|
|
|
if (dev->genl_data.poll_req_portid == w->portid) {
|
2011-07-02 06:31:34 +08:00
|
|
|
nfc_stop_poll(dev);
|
2012-09-08 04:12:54 +08:00
|
|
|
dev->genl_data.poll_req_portid = 0;
|
2011-07-02 06:31:34 +08:00
|
|
|
}
|
2012-09-26 20:17:12 +08:00
|
|
|
|
|
|
|
mutex_unlock(&dev->genl_data.genl_data_mutex);
|
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
dev = nfc_device_iter_next(&iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
nfc_device_iter_exit(&iter);
|
|
|
|
|
2012-09-26 20:17:12 +08:00
|
|
|
mutex_unlock(&nfc_devlist_mutex);
|
|
|
|
|
|
|
|
kfree(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_genl_rcv_nl_event(struct notifier_block *this,
|
|
|
|
unsigned long event, void *ptr)
|
|
|
|
{
|
|
|
|
struct netlink_notify *n = ptr;
|
|
|
|
struct urelease_work *w;
|
|
|
|
|
|
|
|
if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC)
|
|
|
|
goto out;
|
|
|
|
|
2012-09-28 23:11:16 +08:00
|
|
|
pr_debug("NETLINK_URELEASE event from id %d\n", n->portid);
|
2012-09-26 20:17:12 +08:00
|
|
|
|
|
|
|
w = kmalloc(sizeof(*w), GFP_ATOMIC);
|
|
|
|
if (w) {
|
2021-01-15 12:14:53 +08:00
|
|
|
INIT_WORK(&w->w, nfc_urelease_event_work);
|
2012-09-28 23:11:16 +08:00
|
|
|
w->portid = n->portid;
|
2021-01-15 12:14:53 +08:00
|
|
|
schedule_work(&w->w);
|
2012-09-26 20:17:12 +08:00
|
|
|
}
|
|
|
|
|
2011-07-02 06:31:34 +08:00
|
|
|
out:
|
|
|
|
return NOTIFY_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nfc_genl_data_init(struct nfc_genl_data *genl_data)
|
|
|
|
{
|
2012-09-08 04:12:54 +08:00
|
|
|
genl_data->poll_req_portid = 0;
|
2011-07-02 06:31:34 +08:00
|
|
|
mutex_init(&genl_data->genl_data_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void nfc_genl_data_exit(struct nfc_genl_data *genl_data)
|
|
|
|
{
|
|
|
|
mutex_destroy(&genl_data->genl_data_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct notifier_block nl_notifier = {
|
|
|
|
.notifier_call = nfc_genl_rcv_nl_event,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nfc_genl_init() - Initialize netlink interface
|
|
|
|
*
|
|
|
|
* This initialization function registers the nfc netlink family.
|
|
|
|
*/
|
|
|
|
int __init nfc_genl_init(void)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2016-10-24 20:40:03 +08:00
|
|
|
rc = genl_register_family(&nfc_genl_family);
|
2011-07-02 06:31:34 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
netlink_register_notifier(&nl_notifier);
|
|
|
|
|
2013-11-19 22:19:39 +08:00
|
|
|
return 0;
|
2011-07-02 06:31:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nfc_genl_exit() - Deinitialize netlink interface
|
|
|
|
*
|
|
|
|
* This exit function unregisters the nfc netlink family.
|
|
|
|
*/
|
|
|
|
void nfc_genl_exit(void)
|
|
|
|
{
|
|
|
|
netlink_unregister_notifier(&nl_notifier);
|
|
|
|
genl_unregister_family(&nfc_genl_family);
|
|
|
|
}
|