.. | .. |
---|
42 | 42 | goto fail; |
---|
43 | 43 | |
---|
44 | 44 | err = -ENOMEM; |
---|
45 | | - ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); |
---|
| 45 | + ns = kzalloc(sizeof(struct ipc_namespace), GFP_KERNEL); |
---|
46 | 46 | if (ns == NULL) |
---|
47 | 47 | goto fail_dec; |
---|
48 | 48 | |
---|
.. | .. |
---|
117 | 117 | |
---|
118 | 118 | static void free_ipc_ns(struct ipc_namespace *ns) |
---|
119 | 119 | { |
---|
| 120 | + /* mq_put_mnt() waits for a grace period as kern_unmount() |
---|
| 121 | + * uses synchronize_rcu(). |
---|
| 122 | + */ |
---|
| 123 | + mq_put_mnt(ns); |
---|
120 | 124 | sem_exit_ns(ns); |
---|
121 | 125 | msg_exit_ns(ns); |
---|
122 | 126 | shm_exit_ns(ns); |
---|
.. | .. |
---|
126 | 130 | ns_free_inum(&ns->ns); |
---|
127 | 131 | kfree(ns); |
---|
128 | 132 | } |
---|
| 133 | + |
---|
| 134 | +static LLIST_HEAD(free_ipc_list); |
---|
| 135 | +static void free_ipc(struct work_struct *unused) |
---|
| 136 | +{ |
---|
| 137 | + struct llist_node *node = llist_del_all(&free_ipc_list); |
---|
| 138 | + struct ipc_namespace *n, *t; |
---|
| 139 | + |
---|
| 140 | + llist_for_each_entry_safe(n, t, node, mnt_llist) |
---|
| 141 | + free_ipc_ns(n); |
---|
| 142 | +} |
---|
| 143 | + |
---|
| 144 | +/* |
---|
| 145 | + * The work queue is used to avoid the cost of synchronize_rcu in kern_unmount. |
---|
| 146 | + */ |
---|
| 147 | +static DECLARE_WORK(free_ipc_work, free_ipc); |
---|
129 | 148 | |
---|
130 | 149 | /* |
---|
131 | 150 | * put_ipc_ns - drop a reference to an ipc namespace. |
---|
.. | .. |
---|
148 | 167 | if (refcount_dec_and_lock(&ns->count, &mq_lock)) { |
---|
149 | 168 | mq_clear_sbinfo(ns); |
---|
150 | 169 | spin_unlock(&mq_lock); |
---|
151 | | - mq_put_mnt(ns); |
---|
152 | | - free_ipc_ns(ns); |
---|
| 170 | + |
---|
| 171 | + if (llist_add(&ns->mnt_llist, &free_ipc_list)) |
---|
| 172 | + schedule_work(&free_ipc_work); |
---|
153 | 173 | } |
---|
154 | 174 | } |
---|
155 | 175 | |
---|
.. | .. |
---|
177 | 197 | return put_ipc_ns(to_ipc_ns(ns)); |
---|
178 | 198 | } |
---|
179 | 199 | |
---|
180 | | -static int ipcns_install(struct nsproxy *nsproxy, struct ns_common *new) |
---|
| 200 | +static int ipcns_install(struct nsset *nsset, struct ns_common *new) |
---|
181 | 201 | { |
---|
| 202 | + struct nsproxy *nsproxy = nsset->nsproxy; |
---|
182 | 203 | struct ipc_namespace *ns = to_ipc_ns(new); |
---|
183 | 204 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || |
---|
184 | | - !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) |
---|
| 205 | + !ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN)) |
---|
185 | 206 | return -EPERM; |
---|
186 | 207 | |
---|
187 | | - /* Ditch state from the old ipc namespace */ |
---|
188 | | - exit_sem(current); |
---|
189 | 208 | put_ipc_ns(nsproxy->ipc_ns); |
---|
190 | 209 | nsproxy->ipc_ns = get_ipc_ns(ns); |
---|
191 | 210 | return 0; |
---|