summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTaehee Yoo <ap420073@gmail.com>2019-10-21 14:47:50 -0400
committerDavid S. Miller <davem@davemloft.net>2019-10-24 17:53:48 -0400
commit5343da4c17429efaa5fb1594ea96aee1a283e694 (patch)
tree55be074795063b493aea2c39124916ca8208daa9 /net
parent82ecff655e7968151b0047f1b5de03b249e5c1c4 (diff)
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 <ap420073@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c272
1 files changed, 227 insertions, 45 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index bf3ed413abaf..ab0edfc4a422 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -146,6 +146,7 @@
146#include "net-sysfs.h" 146#include "net-sysfs.h"
147 147
148#define MAX_GRO_SKBS 8 148#define MAX_GRO_SKBS 8
149#define MAX_NEST_DEV 8
149 150
150/* This should be increased if a protocol with a bigger head is added. */ 151/* This should be increased if a protocol with a bigger head is added. */
151#define GRO_MAX_HEAD (MAX_HEADER + 128) 152#define GRO_MAX_HEAD (MAX_HEADER + 128)
@@ -6644,6 +6645,21 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
6644} 6645}
6645EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); 6646EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
6646 6647
6648static 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
6647static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev, 6663static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
6648 struct list_head **iter) 6664 struct list_head **iter)
6649{ 6665{
@@ -6661,28 +6677,93 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
6661 return upper->dev; 6677 return upper->dev;
6662} 6678}
6663 6679
6680static 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
6664int netdev_walk_all_upper_dev_rcu(struct net_device *dev, 6726int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
6665 int (*fn)(struct net_device *dev, 6727 int (*fn)(struct net_device *dev,
6666 void *data), 6728 void *data),
6667 void *data) 6729 void *data)
6668{ 6730{
6669 struct net_device *udev; 6731 struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
6670 struct list_head *iter; 6732 struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
6671 int ret; 6733 int ret, cur = 0;
6672 6734
6673 for (iter = &dev->adj_list.upper, 6735 now = dev;
6674 udev = netdev_next_upper_dev_rcu(dev, &iter); 6736 iter = &dev->adj_list.upper;
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;
6681 6737
6682 /* then look at all of its upper devices */ 6738 while (1) {
6683 ret = netdev_walk_all_upper_dev_rcu(udev, fn, data); 6739 if (now != dev) {
6684 if (ret) 6740 ret = fn(now, data);
6685 return ret; 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;
6686 } 6767 }
6687 6768
6688 return 0; 6769 return 0;
@@ -6790,23 +6871,42 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
6790 void *data), 6871 void *data),
6791 void *data) 6872 void *data)
6792{ 6873{
6793 struct net_device *ldev; 6874 struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
6794 struct list_head *iter; 6875 struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
6795 int ret; 6876 int ret, cur = 0;
6796 6877
6797 for (iter = &dev->adj_list.lower, 6878 now = dev;
6798 ldev = netdev_next_lower_dev(dev, &iter); 6879 iter = &dev->adj_list.lower;
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;
6805 6880
6806 /* then look at all of its lower devices */ 6881 while (1) {
6807 ret = netdev_walk_all_lower_dev(ldev, fn, data); 6882 if (now != dev) {
6808 if (ret) 6883 ret = fn(now, data);
6809 return ret; 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;
6810 } 6910 }
6811 6911
6812 return 0; 6912 return 0;
@@ -6827,28 +6927,93 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
6827 return lower->dev; 6927 return lower->dev;
6828} 6928}
6829 6929
6830int netdev_walk_all_lower_dev_rcu(struct net_device *dev, 6930static u8 __netdev_upper_depth(struct net_device *dev)
6831 int (*fn)(struct net_device *dev, 6931{
6832 void *data), 6932 struct net_device *udev;
6833 void *data) 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
6947static u8 __netdev_lower_depth(struct net_device *dev)
6834{ 6948{
6835 struct net_device *ldev; 6949 struct net_device *ldev;
6836 struct list_head *iter; 6950 struct list_head *iter;
6837 int ret; 6951 u8 max_depth = 0;
6838 6952
6839 for (iter = &dev->adj_list.lower, 6953 for (iter = &dev->adj_list.lower,
6840 ldev = netdev_next_lower_dev_rcu(dev, &iter); 6954 ldev = netdev_next_lower_dev(dev, &iter);
6841 ldev; 6955 ldev;
6842 ldev = netdev_next_lower_dev_rcu(dev, &iter)) { 6956 ldev = netdev_next_lower_dev(dev, &iter)) {
6843 /* first is the lower device itself */ 6957 if (max_depth < ldev->lower_level)
6844 ret = fn(ldev, data); 6958 max_depth = ldev->lower_level;
6845 if (ret) 6959 }
6846 return ret;
6847 6960
6848 /* then look at all of its lower devices */ 6961 return max_depth;
6849 ret = netdev_walk_all_lower_dev_rcu(ldev, fn, data); 6962}
6850 if (ret) 6963
6851 return ret; 6964static 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
6970static 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
6976int 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;
6852 } 7017 }
6853 7018
6854 return 0; 7019 return 0;
@@ -7105,6 +7270,9 @@ static int __netdev_upper_dev_link(struct net_device *dev,
7105 if (netdev_has_upper_dev(upper_dev, dev)) 7270 if (netdev_has_upper_dev(upper_dev, dev))
7106 return -EBUSY; 7271 return -EBUSY;
7107 7272
7273 if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV)
7274 return -EMLINK;
7275
7108 if (!master) { 7276 if (!master) {
7109 if (netdev_has_upper_dev(dev, upper_dev)) 7277 if (netdev_has_upper_dev(dev, upper_dev))
7110 return -EEXIST; 7278 return -EEXIST;
@@ -7131,6 +7299,12 @@ static int __netdev_upper_dev_link(struct net_device *dev,
7131 if (ret) 7299 if (ret)
7132 goto rollback; 7300 goto rollback;
7133 7301
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
7134 return 0; 7308 return 0;
7135 7309
7136rollback: 7310rollback:
@@ -7213,6 +7387,12 @@ void netdev_upper_dev_unlink(struct net_device *dev,
7213 7387
7214 call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, 7388 call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
7215 &changeupper_info.info); 7389 &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);
7216} 7396}
7217EXPORT_SYMBOL(netdev_upper_dev_unlink); 7397EXPORT_SYMBOL(netdev_upper_dev_unlink);
7218 7398
@@ -9212,6 +9392,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
9212 9392
9213 dev->gso_max_size = GSO_MAX_SIZE; 9393 dev->gso_max_size = GSO_MAX_SIZE;
9214 dev->gso_max_segs = GSO_MAX_SEGS; 9394 dev->gso_max_segs = GSO_MAX_SEGS;
9395 dev->upper_level = 1;
9396 dev->lower_level = 1;
9215 9397
9216 INIT_LIST_HEAD(&dev->napi_list); 9398 INIT_LIST_HEAD(&dev->napi_list);
9217 INIT_LIST_HEAD(&dev->unreg_list); 9399 INIT_LIST_HEAD(&dev->unreg_list);