0007-cgroup-fix-cgroup_sk_alloc-for-sk_clone_lock.patch 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Cong Wang <[email protected]>
  3. Date: Tue, 16 Jun 2020 11:03:52 -0700
  4. Subject: [PATCH] cgroup: fix cgroup_sk_alloc() for sk_clone_lock()
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. When we clone a socket in sk_clone_lock(), its sk_cgrp_data is
  9. copied, so the cgroup refcnt must be taken too. And, unlike the
  10. sk_alloc() path, sock_update_netprioidx() is not called here.
  11. Therefore, it is safe and necessary to grab the cgroup refcnt
  12. even when cgroup_sk_alloc is disabled.
  13. sk_clone_lock() is in BH context anyway, the in_interrupt()
  14. would terminate this function if called there. And for sk_alloc()
  15. skcd->val is always zero. So it's safe to factor out the code
  16. to make it more readable.
  17. Fixes: 090e28b229af92dc5b ("netprio_cgroup: Fix unlimited memory leak of v2 cgroups")
  18. Reported-by: Cameron Berkenpas <[email protected]>
  19. Reported-by: Peter Geis <[email protected]>
  20. Reported-by: Lu Fengqi <[email protected]>
  21. Reported-by: Daniël Sonck <[email protected]>
  22. Tested-by: Cameron Berkenpas <[email protected]>
  23. Cc: Daniel Borkmann <[email protected]>
  24. Cc: Zefan Li <[email protected]>
  25. Cc: Tejun Heo <[email protected]>
  26. Signed-off-by: Cong Wang <[email protected]>
  27. Signed-off-by: Thomas Lamprecht <[email protected]>
  28. ---
  29. include/linux/cgroup.h | 2 ++
  30. kernel/cgroup/cgroup.c | 26 ++++++++++++++------------
  31. net/core/sock.c | 2 +-
  32. 3 files changed, 17 insertions(+), 13 deletions(-)
  33. diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
  34. index 57577075d204..14452a801d95 100644
  35. --- a/include/linux/cgroup.h
  36. +++ b/include/linux/cgroup.h
  37. @@ -822,6 +822,7 @@ extern spinlock_t cgroup_sk_update_lock;
  38. void cgroup_sk_alloc_disable(void);
  39. void cgroup_sk_alloc(struct sock_cgroup_data *skcd);
  40. +void cgroup_sk_clone(struct sock_cgroup_data *skcd);
  41. void cgroup_sk_free(struct sock_cgroup_data *skcd);
  42. static inline struct cgroup *sock_cgroup_ptr(struct sock_cgroup_data *skcd)
  43. @@ -847,6 +848,7 @@ static inline struct cgroup *sock_cgroup_ptr(struct sock_cgroup_data *skcd)
  44. #else /* CONFIG_CGROUP_DATA */
  45. static inline void cgroup_sk_alloc(struct sock_cgroup_data *skcd) {}
  46. +static inline void cgroup_sk_clone(struct sock_cgroup_data *skcd) {}
  47. static inline void cgroup_sk_free(struct sock_cgroup_data *skcd) {}
  48. #endif /* CONFIG_CGROUP_DATA */
  49. diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
  50. index 7c9e97553a00..d56ee72f4a07 100644
  51. --- a/kernel/cgroup/cgroup.c
  52. +++ b/kernel/cgroup/cgroup.c
  53. @@ -6382,18 +6382,6 @@ void cgroup_sk_alloc(struct sock_cgroup_data *skcd)
  54. if (cgroup_sk_alloc_disabled)
  55. return;
  56. - /* Socket clone path */
  57. - if (skcd->val) {
  58. - /*
  59. - * We might be cloning a socket which is left in an empty
  60. - * cgroup and the cgroup might have already been rmdir'd.
  61. - * Don't use cgroup_get_live().
  62. - */
  63. - cgroup_get(sock_cgroup_ptr(skcd));
  64. - cgroup_bpf_get(sock_cgroup_ptr(skcd));
  65. - return;
  66. - }
  67. -
  68. /* Don't associate the sock with unrelated interrupted task's cgroup. */
  69. if (in_interrupt())
  70. return;
  71. @@ -6415,6 +6403,20 @@ void cgroup_sk_alloc(struct sock_cgroup_data *skcd)
  72. rcu_read_unlock();
  73. }
  74. +void cgroup_sk_clone(struct sock_cgroup_data *skcd)
  75. +{
  76. + /* Socket clone path */
  77. + if (skcd->val) {
  78. + /*
  79. + * We might be cloning a socket which is left in an empty
  80. + * cgroup and the cgroup might have already been rmdir'd.
  81. + * Don't use cgroup_get_live().
  82. + */
  83. + cgroup_get(sock_cgroup_ptr(skcd));
  84. + cgroup_bpf_get(sock_cgroup_ptr(skcd));
  85. + }
  86. +}
  87. +
  88. void cgroup_sk_free(struct sock_cgroup_data *skcd)
  89. {
  90. struct cgroup *cgrp = sock_cgroup_ptr(skcd);
  91. diff --git a/net/core/sock.c b/net/core/sock.c
  92. index 0adf7a9e5a90..6ef468767ab0 100644
  93. --- a/net/core/sock.c
  94. +++ b/net/core/sock.c
  95. @@ -1836,7 +1836,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
  96. /* sk->sk_memcg will be populated at accept() time */
  97. newsk->sk_memcg = NULL;
  98. - cgroup_sk_alloc(&newsk->sk_cgrp_data);
  99. + cgroup_sk_clone(&newsk->sk_cgrp_data);
  100. rcu_read_lock();
  101. filter = rcu_dereference(sk->sk_filter);