Skip to content

Commit 5343da4

Browse files
TaeheeYoodavem330
authored andcommitted
net: core: limit nested device depth
Current code doesn't limit the number of nested devices. Nested devices would be handled recursively and this needs huge stack memory. So, unlimited nested devices could make stack overflow. This patch adds upper_level and lower_level, they are common variables and represent maximum lower/upper depth. When upper/lower device is attached or dettached, {lower/upper}_level are updated. and if maximum depth is bigger than 8, attach routine fails and returns -EMLINK. In addition, this patch converts recursive routine of netdev_walk_all_{lower/upper} to iterator routine. Test commands: ip link add dummy0 type dummy ip link add link dummy0 name vlan1 type vlan id 1 ip link set vlan1 up for i in {2..55} do let A=$i-1 ip link add vlan$i link vlan$A type vlan id $i done ip link del dummy0 Splat looks like: [ 155.513226][ T908] BUG: KASAN: use-after-free in __unwind_start+0x71/0x850 [ 155.514162][ T908] Write of size 88 at addr ffff8880608a6cc0 by task ip/908 [ 155.515048][ T908] [ 155.515333][ T908] CPU: 0 PID: 908 Comm: ip Not tainted 5.4.0-rc3+ #96 [ 155.516147][ T908] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 155.517233][ T908] Call Trace: [ 155.517627][ T908] [ 155.517918][ T908] Allocated by task 0: [ 155.518412][ T908] (stack is not available) [ 155.518955][ T908] [ 155.519228][ T908] Freed by task 0: [ 155.519885][ T908] (stack is not available) [ 155.520452][ T908] [ 155.520729][ T908] The buggy address belongs to the object at ffff8880608a6ac0 [ 155.520729][ T908] which belongs to the cache names_cache of size 4096 [ 155.522387][ T908] The buggy address is located 512 bytes inside of [ 155.522387][ T908] 4096-byte region [ffff8880608a6ac0, ffff8880608a7ac0) [ 155.523920][ T908] The buggy address belongs to the page: [ 155.524552][ T908] page:ffffea0001822800 refcount:1 mapcount:0 mapping:ffff88806c657cc0 index:0x0 compound_mapcount:0 [ 155.525836][ T908] flags: 0x100000000010200(slab|head) [ 155.526445][ T908] raw: 0100000000010200 ffffea0001813808 ffffea0001a26c08 ffff88806c657cc0 [ 155.527424][ T908] raw: 0000000000000000 0000000000070007 00000001ffffffff 0000000000000000 [ 155.528429][ T908] page dumped because: kasan: bad access detected [ 155.529158][ T908] [ 155.529410][ T908] Memory state around the buggy address: [ 155.530060][ T908] ffff8880608a6b80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 155.530971][ T908] ffff8880608a6c00: fb fb fb fb fb f1 f1 f1 f1 00 f2 f2 f2 f3 f3 f3 [ 155.531889][ T908] >ffff8880608a6c80: f3 fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 155.532806][ T908] ^ [ 155.533509][ T908] ffff8880608a6d00: fb fb fb fb fb fb fb fb fb f1 f1 f1 f1 00 00 00 [ 155.534436][ T908] ffff8880608a6d80: f2 f3 f3 f3 f3 fb fb fb 00 00 00 00 00 00 00 00 [ ... ] Signed-off-by: Taehee Yoo <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 82ecff6 commit 5343da4

File tree

2 files changed

+231
-45
lines changed

2 files changed

+231
-45
lines changed

include/linux/netdevice.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,8 @@ enum netdev_priv_flags {
16491649
* @perm_addr: Permanent hw address
16501650
* @addr_assign_type: Hw address assignment type
16511651
* @addr_len: Hardware address length
1652+
* @upper_level: Maximum depth level of upper devices.
1653+
* @lower_level: Maximum depth level of lower devices.
16521654
* @neigh_priv_len: Used in neigh_alloc()
16531655
* @dev_id: Used to differentiate devices that share
16541656
* the same link layer address
@@ -1875,6 +1877,8 @@ struct net_device {
18751877
unsigned char perm_addr[MAX_ADDR_LEN];
18761878
unsigned char addr_assign_type;
18771879
unsigned char addr_len;
1880+
unsigned char upper_level;
1881+
unsigned char lower_level;
18781882
unsigned short neigh_priv_len;
18791883
unsigned short dev_id;
18801884
unsigned short dev_port;

net/core/dev.c

Lines changed: 227 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
#include "net-sysfs.h"
147147

148148
#define MAX_GRO_SKBS 8
149+
#define MAX_NEST_DEV 8
149150

150151
/* This should be increased if a protocol with a bigger head is added. */
151152
#define GRO_MAX_HEAD (MAX_HEADER + 128)
@@ -6644,6 +6645,21 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
66446645
}
66456646
EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
66466647

6648+
static struct net_device *netdev_next_upper_dev(struct net_device *dev,
6649+
struct list_head **iter)
6650+
{
6651+
struct netdev_adjacent *upper;
6652+
6653+
upper = list_entry((*iter)->next, struct netdev_adjacent, list);
6654+
6655+
if (&upper->list == &dev->adj_list.upper)
6656+
return NULL;
6657+
6658+
*iter = &upper->list;
6659+
6660+
return upper->dev;
6661+
}
6662+
66476663
static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
66486664
struct list_head **iter)
66496665
{
@@ -6661,28 +6677,93 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
66616677
return upper->dev;
66626678
}
66636679

6680+
static int netdev_walk_all_upper_dev(struct net_device *dev,
6681+
int (*fn)(struct net_device *dev,
6682+
void *data),
6683+
void *data)
6684+
{
6685+
struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
6686+
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
6687+
int ret, cur = 0;
6688+
6689+
now = dev;
6690+
iter = &dev->adj_list.upper;
6691+
6692+
while (1) {
6693+
if (now != dev) {
6694+
ret = fn(now, data);
6695+
if (ret)
6696+
return ret;
6697+
}
6698+
6699+
next = NULL;
6700+
while (1) {
6701+
udev = netdev_next_upper_dev(now, &iter);
6702+
if (!udev)
6703+
break;
6704+
6705+
next = udev;
6706+
niter = &udev->adj_list.upper;
6707+
dev_stack[cur] = now;
6708+
iter_stack[cur++] = iter;
6709+
break;
6710+
}
6711+
6712+
if (!next) {
6713+
if (!cur)
6714+
return 0;
6715+
next = dev_stack[--cur];
6716+
niter = iter_stack[cur];
6717+
}
6718+
6719+
now = next;
6720+
iter = niter;
6721+
}
6722+
6723+
return 0;
6724+
}
6725+
66646726
int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
66656727
int (*fn)(struct net_device *dev,
66666728
void *data),
66676729
void *data)
66686730
{
6669-
struct net_device *udev;
6670-
struct list_head *iter;
6671-
int ret;
6731+
struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
6732+
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
6733+
int ret, cur = 0;
66726734

6673-
for (iter = &dev->adj_list.upper,
6674-
udev = netdev_next_upper_dev_rcu(dev, &iter);
6675-
udev;
6676-
udev = netdev_next_upper_dev_rcu(dev, &iter)) {
6677-
/* first is the upper device itself */
6678-
ret = fn(udev, data);
6679-
if (ret)
6680-
return ret;
6735+
now = dev;
6736+
iter = &dev->adj_list.upper;
66816737

6682-
/* then look at all of its upper devices */
6683-
ret = netdev_walk_all_upper_dev_rcu(udev, fn, data);
6684-
if (ret)
6685-
return ret;
6738+
while (1) {
6739+
if (now != dev) {
6740+
ret = fn(now, data);
6741+
if (ret)
6742+
return ret;
6743+
}
6744+
6745+
next = NULL;
6746+
while (1) {
6747+
udev = netdev_next_upper_dev_rcu(now, &iter);
6748+
if (!udev)
6749+
break;
6750+
6751+
next = udev;
6752+
niter = &udev->adj_list.upper;
6753+
dev_stack[cur] = now;
6754+
iter_stack[cur++] = iter;
6755+
break;
6756+
}
6757+
6758+
if (!next) {
6759+
if (!cur)
6760+
return 0;
6761+
next = dev_stack[--cur];
6762+
niter = iter_stack[cur];
6763+
}
6764+
6765+
now = next;
6766+
iter = niter;
66866767
}
66876768

66886769
return 0;
@@ -6790,23 +6871,42 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
67906871
void *data),
67916872
void *data)
67926873
{
6793-
struct net_device *ldev;
6794-
struct list_head *iter;
6795-
int ret;
6874+
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
6875+
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
6876+
int ret, cur = 0;
67966877

6797-
for (iter = &dev->adj_list.lower,
6798-
ldev = netdev_next_lower_dev(dev, &iter);
6799-
ldev;
6800-
ldev = netdev_next_lower_dev(dev, &iter)) {
6801-
/* first is the lower device itself */
6802-
ret = fn(ldev, data);
6803-
if (ret)
6804-
return ret;
6878+
now = dev;
6879+
iter = &dev->adj_list.lower;
68056880

6806-
/* then look at all of its lower devices */
6807-
ret = netdev_walk_all_lower_dev(ldev, fn, data);
6808-
if (ret)
6809-
return ret;
6881+
while (1) {
6882+
if (now != dev) {
6883+
ret = fn(now, data);
6884+
if (ret)
6885+
return ret;
6886+
}
6887+
6888+
next = NULL;
6889+
while (1) {
6890+
ldev = netdev_next_lower_dev(now, &iter);
6891+
if (!ldev)
6892+
break;
6893+
6894+
next = ldev;
6895+
niter = &ldev->adj_list.lower;
6896+
dev_stack[cur] = now;
6897+
iter_stack[cur++] = iter;
6898+
break;
6899+
}
6900+
6901+
if (!next) {
6902+
if (!cur)
6903+
return 0;
6904+
next = dev_stack[--cur];
6905+
niter = iter_stack[cur];
6906+
}
6907+
6908+
now = next;
6909+
iter = niter;
68106910
}
68116911

68126912
return 0;
@@ -6827,28 +6927,93 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
68276927
return lower->dev;
68286928
}
68296929

6830-
int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
6831-
int (*fn)(struct net_device *dev,
6832-
void *data),
6833-
void *data)
6930+
static u8 __netdev_upper_depth(struct net_device *dev)
6931+
{
6932+
struct net_device *udev;
6933+
struct list_head *iter;
6934+
u8 max_depth = 0;
6935+
6936+
for (iter = &dev->adj_list.upper,
6937+
udev = netdev_next_upper_dev(dev, &iter);
6938+
udev;
6939+
udev = netdev_next_upper_dev(dev, &iter)) {
6940+
if (max_depth < udev->upper_level)
6941+
max_depth = udev->upper_level;
6942+
}
6943+
6944+
return max_depth;
6945+
}
6946+
6947+
static u8 __netdev_lower_depth(struct net_device *dev)
68346948
{
68356949
struct net_device *ldev;
68366950
struct list_head *iter;
6837-
int ret;
6951+
u8 max_depth = 0;
68386952

68396953
for (iter = &dev->adj_list.lower,
6840-
ldev = netdev_next_lower_dev_rcu(dev, &iter);
6954+
ldev = netdev_next_lower_dev(dev, &iter);
68416955
ldev;
6842-
ldev = netdev_next_lower_dev_rcu(dev, &iter)) {
6843-
/* first is the lower device itself */
6844-
ret = fn(ldev, data);
6845-
if (ret)
6846-
return ret;
6956+
ldev = netdev_next_lower_dev(dev, &iter)) {
6957+
if (max_depth < ldev->lower_level)
6958+
max_depth = ldev->lower_level;
6959+
}
68476960

6848-
/* then look at all of its lower devices */
6849-
ret = netdev_walk_all_lower_dev_rcu(ldev, fn, data);
6850-
if (ret)
6851-
return ret;
6961+
return max_depth;
6962+
}
6963+
6964+
static int __netdev_update_upper_level(struct net_device *dev, void *data)
6965+
{
6966+
dev->upper_level = __netdev_upper_depth(dev) + 1;
6967+
return 0;
6968+
}
6969+
6970+
static int __netdev_update_lower_level(struct net_device *dev, void *data)
6971+
{
6972+
dev->lower_level = __netdev_lower_depth(dev) + 1;
6973+
return 0;
6974+
}
6975+
6976+
int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
6977+
int (*fn)(struct net_device *dev,
6978+
void *data),
6979+
void *data)
6980+
{
6981+
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
6982+
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
6983+
int ret, cur = 0;
6984+
6985+
now = dev;
6986+
iter = &dev->adj_list.lower;
6987+
6988+
while (1) {
6989+
if (now != dev) {
6990+
ret = fn(now, data);
6991+
if (ret)
6992+
return ret;
6993+
}
6994+
6995+
next = NULL;
6996+
while (1) {
6997+
ldev = netdev_next_lower_dev_rcu(now, &iter);
6998+
if (!ldev)
6999+
break;
7000+
7001+
next = ldev;
7002+
niter = &ldev->adj_list.lower;
7003+
dev_stack[cur] = now;
7004+
iter_stack[cur++] = iter;
7005+
break;
7006+
}
7007+
7008+
if (!next) {
7009+
if (!cur)
7010+
return 0;
7011+
next = dev_stack[--cur];
7012+
niter = iter_stack[cur];
7013+
}
7014+
7015+
now = next;
7016+
iter = niter;
68527017
}
68537018

68547019
return 0;
@@ -7105,6 +7270,9 @@ static int __netdev_upper_dev_link(struct net_device *dev,
71057270
if (netdev_has_upper_dev(upper_dev, dev))
71067271
return -EBUSY;
71077272

7273+
if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV)
7274+
return -EMLINK;
7275+
71087276
if (!master) {
71097277
if (netdev_has_upper_dev(dev, upper_dev))
71107278
return -EEXIST;
@@ -7131,6 +7299,12 @@ static int __netdev_upper_dev_link(struct net_device *dev,
71317299
if (ret)
71327300
goto rollback;
71337301

7302+
__netdev_update_upper_level(dev, NULL);
7303+
netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
7304+
7305+
__netdev_update_lower_level(upper_dev, NULL);
7306+
netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, NULL);
7307+
71347308
return 0;
71357309

71367310
rollback:
@@ -7213,6 +7387,12 @@ void netdev_upper_dev_unlink(struct net_device *dev,
72137387

72147388
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
72157389
&changeupper_info.info);
7390+
7391+
__netdev_update_upper_level(dev, NULL);
7392+
netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
7393+
7394+
__netdev_update_lower_level(upper_dev, NULL);
7395+
netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, NULL);
72167396
}
72177397
EXPORT_SYMBOL(netdev_upper_dev_unlink);
72187398

@@ -9212,6 +9392,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
92129392

92139393
dev->gso_max_size = GSO_MAX_SIZE;
92149394
dev->gso_max_segs = GSO_MAX_SEGS;
9395+
dev->upper_level = 1;
9396+
dev->lower_level = 1;
92159397

92169398
INIT_LIST_HEAD(&dev->napi_list);
92179399
INIT_LIST_HEAD(&dev->unreg_list);

0 commit comments

Comments
 (0)