Import of kernel-4.18.0-553.150.1.el8_10
This commit is contained in:
parent
22c3439a79
commit
b6cd90ab03
@ -12,7 +12,7 @@ RHEL_MINOR = 10
|
||||
#
|
||||
# Use this spot to avoid future merge conflicts.
|
||||
# Do not trim this comment.
|
||||
RHEL_RELEASE = 553.148.1
|
||||
RHEL_RELEASE = 553.150.1
|
||||
|
||||
#
|
||||
# ZSTREAM
|
||||
|
||||
@ -162,13 +162,12 @@ static void vxcan_setup(struct net_device *dev)
|
||||
/* forward declaration for rtnl_create_link() */
|
||||
static struct rtnl_link_ops vxcan_link_ops;
|
||||
|
||||
static int vxcan_newlink(struct net *net, struct net_device *dev,
|
||||
static int vxcan_newlink(struct net *peer_net, struct net_device *dev,
|
||||
struct nlattr *tb[], struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct vxcan_priv *priv;
|
||||
struct net_device *peer;
|
||||
struct net *peer_net;
|
||||
|
||||
struct nlattr *peer_tb[IFLA_MAX + 1], **tbp = tb;
|
||||
char ifname[IFNAMSIZ];
|
||||
@ -178,19 +177,10 @@ static int vxcan_newlink(struct net *net, struct net_device *dev,
|
||||
|
||||
/* register peer device */
|
||||
if (data && data[VXCAN_INFO_PEER]) {
|
||||
struct nlattr *nla_peer;
|
||||
struct nlattr *nla_peer = data[VXCAN_INFO_PEER];
|
||||
|
||||
nla_peer = data[VXCAN_INFO_PEER];
|
||||
ifmp = nla_data(nla_peer);
|
||||
err = rtnl_nla_parse_ifla(peer_tb,
|
||||
nla_data(nla_peer) +
|
||||
sizeof(struct ifinfomsg),
|
||||
nla_len(nla_peer) -
|
||||
sizeof(struct ifinfomsg),
|
||||
NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
|
||||
tbp = peer_tb;
|
||||
}
|
||||
|
||||
@ -202,23 +192,15 @@ static int vxcan_newlink(struct net *net, struct net_device *dev,
|
||||
name_assign_type = NET_NAME_ENUM;
|
||||
}
|
||||
|
||||
peer_net = rtnl_link_get_net(net, tbp);
|
||||
if (IS_ERR(peer_net))
|
||||
return PTR_ERR(peer_net);
|
||||
|
||||
peer = rtnl_create_link(peer_net, ifname, name_assign_type,
|
||||
&vxcan_link_ops, tbp, extack);
|
||||
if (IS_ERR(peer)) {
|
||||
put_net(peer_net);
|
||||
if (IS_ERR(peer))
|
||||
return PTR_ERR(peer);
|
||||
}
|
||||
|
||||
if (ifmp && dev->ifindex)
|
||||
peer->ifindex = ifmp->ifi_index;
|
||||
|
||||
err = register_netdevice(peer);
|
||||
put_net(peer_net);
|
||||
peer_net = NULL;
|
||||
if (err < 0) {
|
||||
free_netdev(peer);
|
||||
return err;
|
||||
@ -297,6 +279,7 @@ static struct rtnl_link_ops vxcan_link_ops = {
|
||||
.newlink = vxcan_newlink,
|
||||
.dellink = vxcan_dellink,
|
||||
.policy = vxcan_policy,
|
||||
.peer_type = VXCAN_INFO_PEER,
|
||||
.maxtype = VXCAN_INFO_MAX,
|
||||
.get_link_net = vxcan_get_link_net,
|
||||
};
|
||||
|
||||
@ -1655,7 +1655,7 @@ static int veth_init_queues(struct net_device *dev, struct nlattr *tb[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int veth_newlink(struct net *src_net, struct net_device *dev,
|
||||
static int veth_newlink(struct net *peer_net, struct net_device *dev,
|
||||
struct nlattr *tb[], struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
@ -1666,27 +1666,15 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
|
||||
struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
|
||||
unsigned char name_assign_type;
|
||||
struct ifinfomsg *ifmp;
|
||||
struct net *net;
|
||||
|
||||
/*
|
||||
* create and register peer first
|
||||
*/
|
||||
if (data != NULL && data[VETH_INFO_PEER] != NULL) {
|
||||
struct nlattr *nla_peer;
|
||||
if (data && data[VETH_INFO_PEER]) {
|
||||
struct nlattr *nla_peer = data[VETH_INFO_PEER];
|
||||
|
||||
nla_peer = data[VETH_INFO_PEER];
|
||||
ifmp = nla_data(nla_peer);
|
||||
err = rtnl_nla_parse_ifla(peer_tb,
|
||||
nla_data(nla_peer) + sizeof(struct ifinfomsg),
|
||||
nla_len(nla_peer) - sizeof(struct ifinfomsg),
|
||||
NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = veth_validate(peer_tb, NULL, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
|
||||
tbp = peer_tb;
|
||||
} else {
|
||||
ifmp = NULL;
|
||||
@ -1701,16 +1689,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
|
||||
name_assign_type = NET_NAME_ENUM;
|
||||
}
|
||||
|
||||
net = rtnl_link_get_net(src_net, tbp);
|
||||
if (IS_ERR(net))
|
||||
return PTR_ERR(net);
|
||||
|
||||
peer = rtnl_create_link(net, ifname, name_assign_type,
|
||||
peer = rtnl_create_link(peer_net, ifname, name_assign_type,
|
||||
&veth_link_ops, tbp, extack);
|
||||
if (IS_ERR(peer)) {
|
||||
put_net(net);
|
||||
if (IS_ERR(peer))
|
||||
return PTR_ERR(peer);
|
||||
}
|
||||
|
||||
if (!ifmp || !tbp[IFLA_ADDRESS])
|
||||
eth_hw_addr_random(peer);
|
||||
@ -1721,8 +1703,6 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
|
||||
netif_inherit_tso_max(peer, dev);
|
||||
|
||||
err = register_netdevice(peer);
|
||||
put_net(net);
|
||||
net = NULL;
|
||||
if (err < 0)
|
||||
goto err_register_peer;
|
||||
|
||||
@ -1841,6 +1821,7 @@ static struct rtnl_link_ops veth_link_ops = {
|
||||
.newlink = veth_newlink,
|
||||
.dellink = veth_dellink,
|
||||
.policy = veth_policy,
|
||||
.peer_type = VETH_INFO_PEER,
|
||||
.maxtype = VETH_INFO_MAX,
|
||||
.get_link_net = veth_get_link_net,
|
||||
.get_num_tx_queues = veth_get_num_queues,
|
||||
|
||||
@ -300,7 +300,7 @@ static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector
|
||||
return hlist_entry_safe(node, struct fsnotify_mark, obj_list);
|
||||
}
|
||||
|
||||
static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
|
||||
struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
|
||||
{
|
||||
struct hlist_node *node = NULL;
|
||||
|
||||
|
||||
@ -299,9 +299,6 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
|
||||
*/
|
||||
static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
|
||||
{
|
||||
if (!mark)
|
||||
return true;
|
||||
|
||||
if (refcount_inc_not_zero(&mark->refcnt)) {
|
||||
spin_lock(&mark->lock);
|
||||
if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) {
|
||||
@ -341,13 +338,20 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
|
||||
int type;
|
||||
|
||||
fsnotify_foreach_obj_type(type) {
|
||||
struct fsnotify_mark *mark = iter_info->marks[type];
|
||||
|
||||
/* This can fail if mark is being removed */
|
||||
if (!fsnotify_get_mark_safe(iter_info->marks[type]))
|
||||
goto fail;
|
||||
while (mark && !fsnotify_get_mark_safe(mark)) {
|
||||
if (fsnotify_iter_should_report_type(iter_info, type))
|
||||
goto fail;
|
||||
/* This is a mark in an unrelated group, skip */
|
||||
mark = fsnotify_next_mark(mark);
|
||||
iter_info->marks[type] = mark;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that both marks are pinned by refcount in the inode / vfsmount
|
||||
* Now that all marks are pinned by refcount in the inode / vfsmount / etc
|
||||
* lists, we can drop SRCU lock, and safely resume the list iteration
|
||||
* once userspace returns.
|
||||
*/
|
||||
|
||||
@ -482,6 +482,7 @@ static inline void fsnotify_clear_sb_marks_by_group(struct fsnotify_group *group
|
||||
}
|
||||
extern void fsnotify_get_mark(struct fsnotify_mark *mark);
|
||||
extern void fsnotify_put_mark(struct fsnotify_mark *mark);
|
||||
struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark);
|
||||
extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info);
|
||||
extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info);
|
||||
|
||||
|
||||
@ -79,4 +79,9 @@ void nf_conntrack_lock(spinlock_t *lock);
|
||||
|
||||
extern spinlock_t nf_conntrack_expect_lock;
|
||||
|
||||
static inline void lockdep_nfct_expect_lock_held(void)
|
||||
{
|
||||
lockdep_assert_held(&nf_conntrack_expect_lock);
|
||||
}
|
||||
|
||||
#endif /* _NF_CONNTRACK_CORE_H */
|
||||
|
||||
@ -39,6 +39,7 @@ struct rtnl_link_ops_extended_rh {
|
||||
* @list: Used internally
|
||||
* @kind: Identifier
|
||||
* @netns_refund: Physical device, move to init_net on netns exit
|
||||
* @peer_type: Peer device specific netlink attribute number (e.g. VETH_INFO_PEER)
|
||||
* @maxtype: Highest device specific netlink attribute number
|
||||
* @policy: Netlink policy for device specific attribute validation
|
||||
* @validate: Optional validation function for netlink/changelink parameters
|
||||
@ -126,7 +127,7 @@ struct rtnl_link_ops {
|
||||
unsigned char name_assign_type,
|
||||
unsigned int num_tx_queues,
|
||||
unsigned int num_rx_queues))
|
||||
RH_KABI_RESERVE(3)
|
||||
RH_KABI_USE(3, const u16 peer_type)
|
||||
RH_KABI_RESERVE(4)
|
||||
RH_KABI_RESERVE(5)
|
||||
RH_KABI_RESERVE(6)
|
||||
@ -194,8 +195,8 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname,
|
||||
int rtnl_delete_link(struct net_device *dev);
|
||||
int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm);
|
||||
|
||||
int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len,
|
||||
struct netlink_ext_ack *exterr);
|
||||
int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer,
|
||||
struct netlink_ext_ack *exterr);
|
||||
struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid);
|
||||
|
||||
#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind)
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
|
||||
kernel.centos,1,Red Hat,kernel-core,4.18.0-553.148.1.el8.x86_64,mailto:secalert@redhat.com
|
||||
kernel.centos,1,Red Hat,kernel-core,4.18.0-553.150.1.el8.x86_64,mailto:secalert@redhat.com
|
||||
|
||||
@ -2144,17 +2144,32 @@ out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len,
|
||||
struct netlink_ext_ack *exterr)
|
||||
int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer,
|
||||
struct netlink_ext_ack *exterr)
|
||||
{
|
||||
return nla_parse_deprecated(tb, IFLA_MAX, head, len, ifla_policy,
|
||||
const struct ifinfomsg *ifmp;
|
||||
const struct nlattr *attrs;
|
||||
size_t len;
|
||||
|
||||
ifmp = nla_data(nla_peer);
|
||||
attrs = nla_data(nla_peer) + sizeof(struct ifinfomsg);
|
||||
len = nla_len(nla_peer) - sizeof(struct ifinfomsg);
|
||||
|
||||
if (ifmp->ifi_index < 0) {
|
||||
NL_SET_ERR_MSG_ATTR(exterr, nla_peer,
|
||||
"ifindex can't be negative");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return nla_parse_deprecated(tb, IFLA_MAX, attrs, len, ifla_policy,
|
||||
exterr);
|
||||
}
|
||||
EXPORT_SYMBOL(rtnl_nla_parse_ifla);
|
||||
EXPORT_SYMBOL(rtnl_nla_parse_ifinfomsg);
|
||||
|
||||
struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
|
||||
static struct net *rtnl_link_get_net_ifla(struct nlattr *tb[])
|
||||
{
|
||||
struct net *net;
|
||||
struct net *net = NULL;
|
||||
|
||||
/* Examine the link attributes and figure out which
|
||||
* network namespace we are talking about.
|
||||
*/
|
||||
@ -2162,8 +2177,17 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
|
||||
net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
|
||||
else if (tb[IFLA_NET_NS_FD])
|
||||
net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD]));
|
||||
else
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
|
||||
{
|
||||
struct net *net = rtnl_link_get_net_ifla(tb);
|
||||
|
||||
if (!net)
|
||||
net = get_net(src_net);
|
||||
|
||||
return net;
|
||||
}
|
||||
EXPORT_SYMBOL(rtnl_link_get_net);
|
||||
@ -3184,23 +3208,172 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct nlattr **attr, struct netlink_ext_ack *extack)
|
||||
static int rtnl_newlink_create(struct sk_buff *skb, struct ifinfomsg *ifm,
|
||||
const struct rtnl_link_ops *ops,
|
||||
struct net *peer_net,
|
||||
struct nlattr **tb, struct nlattr **data,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
|
||||
unsigned char name_assign_type = NET_NAME_USER;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct net *dest_net, *link_net;
|
||||
struct net_device *dev;
|
||||
char ifname[IFNAMSIZ];
|
||||
int err;
|
||||
|
||||
if (!ops->alloc && !ops->setup)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (tb[IFLA_IFNAME]) {
|
||||
nla_strscpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
|
||||
} else {
|
||||
snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
|
||||
name_assign_type = NET_NAME_ENUM;
|
||||
}
|
||||
|
||||
dest_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN);
|
||||
if (IS_ERR(dest_net))
|
||||
return PTR_ERR(dest_net);
|
||||
|
||||
if (tb[IFLA_LINK_NETNSID]) {
|
||||
int id = nla_get_s32(tb[IFLA_LINK_NETNSID]);
|
||||
|
||||
link_net = get_net_ns_by_id(dest_net, id);
|
||||
if (!link_net) {
|
||||
NL_SET_ERR_MSG(extack, "Unknown network namespace id");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
err = -EPERM;
|
||||
if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN))
|
||||
goto out;
|
||||
} else {
|
||||
link_net = NULL;
|
||||
}
|
||||
|
||||
dev = rtnl_create_link(link_net ? : dest_net, ifname,
|
||||
name_assign_type, ops, tb, extack);
|
||||
if (IS_ERR(dev)) {
|
||||
err = PTR_ERR(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->ifindex = ifm->ifi_index;
|
||||
|
||||
if (link_net)
|
||||
net = link_net;
|
||||
if (peer_net)
|
||||
net = peer_net;
|
||||
|
||||
if (ops->newlink) {
|
||||
err = ops->newlink(net, dev, tb, data, extack);
|
||||
/* Drivers should call free_netdev() in ->destructor
|
||||
* and unregister it on failure after registration
|
||||
* so that device could be finally freed in rtnl_unlock.
|
||||
*/
|
||||
if (err < 0) {
|
||||
/* If device is not registered at all, free it now */
|
||||
if (dev->reg_state == NETREG_UNINITIALIZED)
|
||||
free_netdev(dev);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
err = register_netdevice(dev);
|
||||
if (err < 0) {
|
||||
free_netdev(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
err = rtnl_configure_link(dev, ifm);
|
||||
if (err < 0)
|
||||
goto out_unregister;
|
||||
if (link_net) {
|
||||
err = dev_change_net_namespace(dev, dest_net, ifname);
|
||||
if (err < 0)
|
||||
goto out_unregister;
|
||||
}
|
||||
if (tb[IFLA_MASTER]) {
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack);
|
||||
if (err)
|
||||
goto out_unregister;
|
||||
}
|
||||
out:
|
||||
if (link_net)
|
||||
put_net(link_net);
|
||||
put_net(dest_net);
|
||||
return err;
|
||||
out_unregister:
|
||||
if (ops->newlink) {
|
||||
LIST_HEAD(list_kill);
|
||||
|
||||
ops->dellink(dev, &list_kill);
|
||||
unregister_netdevice_many(&list_kill);
|
||||
} else {
|
||||
unregister_netdevice(dev);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
struct rtnl_newlink_tbs {
|
||||
struct nlattr *tb[IFLA_MAX + 1];
|
||||
struct nlattr *attr[RTNL_MAX_TYPE + 1];
|
||||
struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
|
||||
};
|
||||
|
||||
static struct net *rtnl_get_peer_net(struct sk_buff *skb,
|
||||
const struct rtnl_link_ops *ops,
|
||||
struct nlattr *tbp[],
|
||||
struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *tb[IFLA_MAX + 1], **attrs;
|
||||
struct net *net;
|
||||
int err;
|
||||
|
||||
if (!data || !data[ops->peer_type]) {
|
||||
attrs = tbp;
|
||||
} else {
|
||||
err = rtnl_nla_parse_ifinfomsg(tb, data[ops->peer_type], extack);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (ops->validate) {
|
||||
err = ops->validate(tb, NULL, extack);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
attrs = tb;
|
||||
}
|
||||
|
||||
net = rtnl_link_get_net_ifla(attrs);
|
||||
if (IS_ERR_OR_NULL(net))
|
||||
return net;
|
||||
|
||||
if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
|
||||
put_net(net);
|
||||
return ERR_PTR(-EPERM);
|
||||
}
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct rtnl_newlink_tbs *tbs,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
|
||||
struct nlattr ** const tb = tbs->tb;
|
||||
const struct rtnl_link_ops *m_ops;
|
||||
struct net_device *master_dev;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
const struct rtnl_link_ops *ops;
|
||||
struct nlattr *tb[IFLA_MAX + 1];
|
||||
struct net *dest_net, *link_net;
|
||||
struct net *peer_net = NULL;
|
||||
struct nlattr **slave_data;
|
||||
char kind[MODULE_NAME_LEN];
|
||||
struct net_device *dev;
|
||||
struct ifinfomsg *ifm;
|
||||
char ifname[IFNAMSIZ];
|
||||
struct nlattr **data;
|
||||
bool link_specified;
|
||||
int err;
|
||||
@ -3264,86 +3437,110 @@ replay:
|
||||
return -EINVAL;
|
||||
|
||||
if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
|
||||
err = nla_parse_nested_deprecated(attr, ops->maxtype,
|
||||
err = nla_parse_nested_deprecated(tbs->attr, ops->maxtype,
|
||||
linkinfo[IFLA_INFO_DATA],
|
||||
ops->policy, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
data = attr;
|
||||
data = tbs->attr;
|
||||
}
|
||||
if (ops->validate) {
|
||||
err = ops->validate(tb, data, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (ops->peer_type) {
|
||||
peer_net = rtnl_get_peer_net(skb, ops, tb, data, extack);
|
||||
if (IS_ERR(peer_net))
|
||||
return PTR_ERR(peer_net);
|
||||
}
|
||||
}
|
||||
|
||||
slave_data = NULL;
|
||||
if (m_ops) {
|
||||
if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE)
|
||||
return -EINVAL;
|
||||
if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE) {
|
||||
err = -EINVAL;
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
if (m_ops->slave_maxtype &&
|
||||
linkinfo[IFLA_INFO_SLAVE_DATA]) {
|
||||
err = nla_parse_nested_deprecated(slave_attr,
|
||||
err = nla_parse_nested_deprecated(tbs->slave_attr,
|
||||
m_ops->slave_maxtype,
|
||||
linkinfo[IFLA_INFO_SLAVE_DATA],
|
||||
m_ops->slave_policy,
|
||||
extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
slave_data = slave_attr;
|
||||
goto put_net;
|
||||
slave_data = tbs->slave_attr;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
int status = 0;
|
||||
|
||||
if (nlh->nlmsg_flags & NLM_F_EXCL)
|
||||
return -EEXIST;
|
||||
if (nlh->nlmsg_flags & NLM_F_REPLACE)
|
||||
return -EOPNOTSUPP;
|
||||
if (nlh->nlmsg_flags & NLM_F_EXCL) {
|
||||
err = -EEXIST;
|
||||
goto put_net;
|
||||
}
|
||||
if (nlh->nlmsg_flags & NLM_F_REPLACE) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
if (linkinfo[IFLA_INFO_DATA]) {
|
||||
if (!ops || ops != dev->rtnl_link_ops ||
|
||||
!ops->changelink)
|
||||
return -EOPNOTSUPP;
|
||||
!ops->changelink) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
err = ops->changelink(dev, tb, data, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto put_net;
|
||||
status |= DO_SETLINK_NOTIFY;
|
||||
}
|
||||
|
||||
if (linkinfo[IFLA_INFO_SLAVE_DATA]) {
|
||||
if (!m_ops || !m_ops->slave_changelink)
|
||||
return -EOPNOTSUPP;
|
||||
if (!m_ops || !m_ops->slave_changelink) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
err = m_ops->slave_changelink(master_dev, dev, tb,
|
||||
slave_data, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto put_net;
|
||||
status |= DO_SETLINK_NOTIFY;
|
||||
}
|
||||
|
||||
return do_setlink(skb, dev, ifm, extack, tb, status);
|
||||
err = do_setlink(skb, dev, ifm, extack, tb, status);
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
|
||||
/* No dev found and NLM_F_CREATE not set. Requested dev does not exist,
|
||||
* or it's for a group
|
||||
*/
|
||||
if (link_specified)
|
||||
return -ENODEV;
|
||||
if (tb[IFLA_GROUP])
|
||||
return rtnl_group_changelink(skb, net,
|
||||
nla_get_u32(tb[IFLA_GROUP]),
|
||||
ifm, extack, tb);
|
||||
return -ENODEV;
|
||||
if (link_specified) {
|
||||
err = -ENODEV;
|
||||
goto put_net;
|
||||
}
|
||||
if (tb[IFLA_GROUP]) {
|
||||
err = rtnl_group_changelink(skb, net,
|
||||
nla_get_u32(tb[IFLA_GROUP]),
|
||||
ifm, extack, tb);
|
||||
goto put_net;
|
||||
}
|
||||
err = -ENODEV;
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
if (tb[IFLA_MAP] || tb[IFLA_PROTINFO])
|
||||
return -EOPNOTSUPP;
|
||||
if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
if (!ops) {
|
||||
#ifdef CONFIG_MODULES
|
||||
@ -3357,109 +3554,31 @@ replay:
|
||||
}
|
||||
#endif
|
||||
NL_SET_ERR_MSG(extack, "Unknown device type");
|
||||
return -EOPNOTSUPP;
|
||||
err = -EOPNOTSUPP;
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
if (!ops->alloc && !ops->setup)
|
||||
return -EOPNOTSUPP;
|
||||
err = rtnl_newlink_create(skb, ifm, ops, peer_net, tb, data, extack);
|
||||
|
||||
if (tb[IFLA_IFNAME]) {
|
||||
nla_strscpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
|
||||
} else {
|
||||
snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
|
||||
name_assign_type = NET_NAME_ENUM;
|
||||
}
|
||||
put_net:
|
||||
if (peer_net)
|
||||
put_net(peer_net);
|
||||
|
||||
dest_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN);
|
||||
if (IS_ERR(dest_net))
|
||||
return PTR_ERR(dest_net);
|
||||
|
||||
if (tb[IFLA_LINK_NETNSID]) {
|
||||
int id = nla_get_s32(tb[IFLA_LINK_NETNSID]);
|
||||
|
||||
link_net = get_net_ns_by_id(dest_net, id);
|
||||
if (!link_net) {
|
||||
NL_SET_ERR_MSG(extack, "Unknown network namespace id");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
err = -EPERM;
|
||||
if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN))
|
||||
goto out;
|
||||
} else {
|
||||
link_net = NULL;
|
||||
}
|
||||
|
||||
dev = rtnl_create_link(link_net ? : dest_net, ifname,
|
||||
name_assign_type, ops, tb, extack);
|
||||
if (IS_ERR(dev)) {
|
||||
err = PTR_ERR(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->ifindex = ifm->ifi_index;
|
||||
|
||||
if (ops->newlink) {
|
||||
err = ops->newlink(link_net ? : net, dev, tb, data, extack);
|
||||
/* Drivers should call free_netdev() in ->destructor
|
||||
* and unregister it on failure after registration
|
||||
* so that device could be finally freed in rtnl_unlock.
|
||||
*/
|
||||
if (err < 0) {
|
||||
/* If device is not registered at all, free it now */
|
||||
if (dev->reg_state == NETREG_UNINITIALIZED)
|
||||
free_netdev(dev);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
err = register_netdevice(dev);
|
||||
if (err < 0) {
|
||||
free_netdev(dev);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
err = rtnl_configure_link(dev, ifm);
|
||||
if (err < 0)
|
||||
goto out_unregister;
|
||||
if (link_net) {
|
||||
err = dev_change_net_namespace(dev, dest_net, ifname);
|
||||
if (err < 0)
|
||||
goto out_unregister;
|
||||
}
|
||||
if (tb[IFLA_MASTER]) {
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack);
|
||||
if (err)
|
||||
goto out_unregister;
|
||||
}
|
||||
out:
|
||||
if (link_net)
|
||||
put_net(link_net);
|
||||
put_net(dest_net);
|
||||
return err;
|
||||
out_unregister:
|
||||
if (ops->newlink) {
|
||||
LIST_HEAD(list_kill);
|
||||
|
||||
ops->dellink(dev, &list_kill);
|
||||
unregister_netdevice_many(&list_kill);
|
||||
} else {
|
||||
unregister_netdevice(dev);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr **attr;
|
||||
struct rtnl_newlink_tbs *tbs;
|
||||
int ret;
|
||||
|
||||
attr = kmalloc_array(RTNL_MAX_TYPE + 1, sizeof(*attr), GFP_KERNEL);
|
||||
if (!attr)
|
||||
tbs = kmalloc(sizeof(*tbs), GFP_KERNEL);
|
||||
if (!tbs)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = __rtnl_newlink(skb, nlh, attr, extack);
|
||||
kfree(attr);
|
||||
ret = __rtnl_newlink(skb, nlh, tbs, extack);
|
||||
kfree(tbs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -239,6 +239,8 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
|
||||
struct nf_exp_event_notifier *notify;
|
||||
struct nf_conntrack_ecache *e;
|
||||
|
||||
lockdep_nfct_expect_lock_held();
|
||||
|
||||
rcu_read_lock();
|
||||
notify = rcu_dereference(net->ct.nf_expect_event_cb);
|
||||
if (!notify)
|
||||
|
||||
@ -53,6 +53,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
|
||||
struct nf_conn_help *master_help = nfct_help(exp->master);
|
||||
struct net *net = nf_ct_exp_net(exp);
|
||||
|
||||
lockdep_nfct_expect_lock_held();
|
||||
WARN_ON(!master_help);
|
||||
WARN_ON(timer_pending(&exp->timeout));
|
||||
|
||||
@ -107,6 +108,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
|
||||
|
||||
bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
|
||||
{
|
||||
lockdep_nfct_expect_lock_held();
|
||||
|
||||
if (del_timer(&exp->timeout)) {
|
||||
nf_ct_unlink_expect(exp);
|
||||
nf_ct_expect_put(exp);
|
||||
@ -164,6 +167,8 @@ nf_ct_find_expectation(struct net *net,
|
||||
struct nf_conntrack_expect *i, *exp = NULL;
|
||||
unsigned int h;
|
||||
|
||||
lockdep_nfct_expect_lock_held();
|
||||
|
||||
if (!net->ct.expect_count)
|
||||
return NULL;
|
||||
|
||||
@ -416,6 +421,8 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
|
||||
unsigned int h;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_nfct_expect_lock_held();
|
||||
|
||||
if (!master_help) {
|
||||
ret = -ESHUTDOWN;
|
||||
goto out;
|
||||
@ -469,8 +476,9 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
|
||||
|
||||
nf_ct_expect_insert(expect);
|
||||
|
||||
spin_unlock_bh(&nf_conntrack_expect_lock);
|
||||
nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
|
||||
spin_unlock_bh(&nf_conntrack_expect_lock);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
spin_unlock_bh(&nf_conntrack_expect_lock);
|
||||
|
||||
@ -3430,33 +3430,40 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!skb2)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_bh(&nf_conntrack_expect_lock);
|
||||
exp = nf_ct_expect_find_get(net, &zone, &tuple);
|
||||
if (!exp)
|
||||
if (!exp) {
|
||||
spin_unlock_bh(&nf_conntrack_expect_lock);
|
||||
kfree_skb(skb2);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (cda[CTA_EXPECT_ID]) {
|
||||
__be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
|
||||
|
||||
if (id != nf_expect_get_id(exp)) {
|
||||
nf_ct_expect_put(exp);
|
||||
spin_unlock_bh(&nf_conntrack_expect_lock);
|
||||
kfree_skb(skb2);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (skb2 == NULL) {
|
||||
nf_ct_expect_put(exp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).portid,
|
||||
nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp);
|
||||
rcu_read_unlock();
|
||||
nf_ct_expect_put(exp);
|
||||
if (err <= 0)
|
||||
goto free;
|
||||
spin_unlock_bh(&nf_conntrack_expect_lock);
|
||||
|
||||
if (err <= 0) {
|
||||
kfree_skb(skb2);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
|
||||
if (err < 0)
|
||||
@ -3464,8 +3471,6 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
|
||||
|
||||
return 0;
|
||||
|
||||
free:
|
||||
kfree_skb(skb2);
|
||||
out:
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return err == -EAGAIN ? -ENOBUFS : err;
|
||||
@ -3509,21 +3514,25 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
spin_lock_bh(&nf_conntrack_expect_lock);
|
||||
|
||||
/* bump usage count to 2 */
|
||||
exp = nf_ct_expect_find_get(net, &zone, &tuple);
|
||||
if (!exp)
|
||||
if (!exp) {
|
||||
spin_unlock_bh(&nf_conntrack_expect_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (cda[CTA_EXPECT_ID]) {
|
||||
__be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
|
||||
if (ntohl(id) != (u32)(unsigned long)exp) {
|
||||
nf_ct_expect_put(exp);
|
||||
spin_unlock_bh(&nf_conntrack_expect_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* after list removal, usage count == 1 */
|
||||
spin_lock_bh(&nf_conntrack_expect_lock);
|
||||
if (del_timer(&exp->timeout)) {
|
||||
nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
|
||||
nlmsg_report(nlh));
|
||||
|
||||
@ -3938,6 +3938,9 @@ struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, stru
|
||||
skb_do_redirect(skb);
|
||||
*ret = __NET_XMIT_STOLEN;
|
||||
return NULL;
|
||||
case TC_ACT_CONSUMED:
|
||||
*ret = __NET_XMIT_STOLEN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return skb;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user