Skip to content

Commit 90d52d4

Browse files
committed
Merge branch 'netns-uevent-filtering'
Christian Brauner says: ==================== netns: uevent filtering This is the new approach to uevent filtering as discussed (see the threads in [1], [2], and [3]). It only contains *non-functional changes*. This series deals with with fixing up uevent filtering logic: - uevent filtering logic is simplified - locking time on uevent_sock_list is minimized - tagged and untagged kobjects are handled in separate codepaths - permissions for userspace are fixed for network device uevents in network namespaces owned by non-initial user namespaces Udev is now able to see those events correctly which it wasn't before. For example, moving a physical device into a network namespace not owned by the initial user namespaces before gave: root@xen1:~# udevadm --debug monitor -k calling: monitor monitor will print the received events for: KERNEL - the kernel uevent sender uid=65534, message ignored sender uid=65534, message ignored sender uid=65534, message ignored sender uid=65534, message ignored sender uid=65534, message ignored and now after the discussion and solution in [3] correctly gives: root@xen1:~# udevadm --debug monitor -k calling: monitor monitor will print the received events for: KERNEL - the kernel uevent KERNEL[625.301042] add /devices/pci0000:00/0000:00:02.0/0000:01:00.1/net/enp1s0f1 (net) KERNEL[625.301109] move /devices/pci0000:00/0000:00:02.0/0000:01:00.1/net/enp1s0f1 (net) KERNEL[625.301138] move /devices/pci0000:00/0000:00:02.0/0000:01:00.1/net/eth1 (net) KERNEL[655.333272] remove /devices/pci0000:00/0000:00:02.0/0000:01:00.1/net/eth1 (net) Thanks! Christian [1]: https://lkml.org/lkml/2018/4/4/739 [2]: https://lkml.org/lkml/2018/4/26/767 [3]: https://lkml.org/lkml/2018/4/26/738 ==================== Acked-by: "Eric W. Biederman" <[email protected]> Signed-off-by: David S. Miller <[email protected]>
2 parents e33200b + a349843 commit 90d52d4

File tree

1 file changed

+126
-52
lines changed

1 file changed

+126
-52
lines changed

lib/kobject_uevent.c

Lines changed: 126 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/socket.h>
2323
#include <linux/skbuff.h>
2424
#include <linux/netlink.h>
25+
#include <linux/uidgid.h>
2526
#include <linux/uuid.h>
2627
#include <linux/ctype.h>
2728
#include <net/sock.h>
@@ -231,30 +232,6 @@ int kobject_synth_uevent(struct kobject *kobj, const char *buf, size_t count)
231232
return r;
232233
}
233234

234-
#ifdef CONFIG_NET
235-
static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
236-
{
237-
struct kobject *kobj = data, *ksobj;
238-
const struct kobj_ns_type_operations *ops;
239-
240-
ops = kobj_ns_ops(kobj);
241-
if (!ops && kobj->kset) {
242-
ksobj = &kobj->kset->kobj;
243-
if (ksobj->parent != NULL)
244-
ops = kobj_ns_ops(ksobj->parent);
245-
}
246-
247-
if (ops && ops->netlink_ns && kobj->ktype->namespace) {
248-
const void *sock_ns, *ns;
249-
ns = kobj->ktype->namespace(kobj);
250-
sock_ns = ops->netlink_ns(dsk);
251-
return sock_ns != ns;
252-
}
253-
254-
return 0;
255-
}
256-
#endif
257-
258235
#ifdef CONFIG_UEVENT_HELPER
259236
static int kobj_usermode_filter(struct kobject *kobj)
260237
{
@@ -296,15 +273,44 @@ static void cleanup_uevent_env(struct subprocess_info *info)
296273
}
297274
#endif
298275

299-
static int kobject_uevent_net_broadcast(struct kobject *kobj,
300-
struct kobj_uevent_env *env,
276+
#ifdef CONFIG_NET
277+
static struct sk_buff *alloc_uevent_skb(struct kobj_uevent_env *env,
301278
const char *action_string,
302279
const char *devpath)
303280
{
304-
int retval = 0;
305-
#if defined(CONFIG_NET)
281+
struct netlink_skb_parms *parms;
282+
struct sk_buff *skb = NULL;
283+
char *scratch;
284+
size_t len;
285+
286+
/* allocate message with maximum possible size */
287+
len = strlen(action_string) + strlen(devpath) + 2;
288+
skb = alloc_skb(len + env->buflen, GFP_KERNEL);
289+
if (!skb)
290+
return NULL;
291+
292+
/* add header */
293+
scratch = skb_put(skb, len);
294+
sprintf(scratch, "%s@%s", action_string, devpath);
295+
296+
skb_put_data(skb, env->buf, env->buflen);
297+
298+
parms = &NETLINK_CB(skb);
299+
parms->creds.uid = GLOBAL_ROOT_UID;
300+
parms->creds.gid = GLOBAL_ROOT_GID;
301+
parms->dst_group = 1;
302+
parms->portid = 0;
303+
304+
return skb;
305+
}
306+
307+
static int uevent_net_broadcast_untagged(struct kobj_uevent_env *env,
308+
const char *action_string,
309+
const char *devpath)
310+
{
306311
struct sk_buff *skb = NULL;
307312
struct uevent_sock *ue_sk;
313+
int retval = 0;
308314

309315
/* send netlink message */
310316
list_for_each_entry(ue_sk, &uevent_sock_list, list) {
@@ -314,37 +320,99 @@ static int kobject_uevent_net_broadcast(struct kobject *kobj,
314320
continue;
315321

316322
if (!skb) {
317-
/* allocate message with the maximum possible size */
318-
size_t len = strlen(action_string) + strlen(devpath) + 2;
319-
char *scratch;
320-
321323
retval = -ENOMEM;
322-
skb = alloc_skb(len + env->buflen, GFP_KERNEL);
324+
skb = alloc_uevent_skb(env, action_string, devpath);
323325
if (!skb)
324326
continue;
325-
326-
/* add header */
327-
scratch = skb_put(skb, len);
328-
sprintf(scratch, "%s@%s", action_string, devpath);
329-
330-
skb_put_data(skb, env->buf, env->buflen);
331-
332-
NETLINK_CB(skb).dst_group = 1;
333327
}
334328

335-
retval = netlink_broadcast_filtered(uevent_sock, skb_get(skb),
336-
0, 1, GFP_KERNEL,
337-
kobj_bcast_filter,
338-
kobj);
329+
retval = netlink_broadcast(uevent_sock, skb_get(skb), 0, 1,
330+
GFP_KERNEL);
339331
/* ENOBUFS should be handled in userspace */
340332
if (retval == -ENOBUFS || retval == -ESRCH)
341333
retval = 0;
342334
}
343335
consume_skb(skb);
344-
#endif
336+
345337
return retval;
346338
}
347339

340+
static int uevent_net_broadcast_tagged(struct sock *usk,
341+
struct kobj_uevent_env *env,
342+
const char *action_string,
343+
const char *devpath)
344+
{
345+
struct user_namespace *owning_user_ns = sock_net(usk)->user_ns;
346+
struct sk_buff *skb = NULL;
347+
int ret = 0;
348+
349+
skb = alloc_uevent_skb(env, action_string, devpath);
350+
if (!skb)
351+
return -ENOMEM;
352+
353+
/* fix credentials */
354+
if (owning_user_ns != &init_user_ns) {
355+
struct netlink_skb_parms *parms = &NETLINK_CB(skb);
356+
kuid_t root_uid;
357+
kgid_t root_gid;
358+
359+
/* fix uid */
360+
root_uid = make_kuid(owning_user_ns, 0);
361+
if (uid_valid(root_uid))
362+
parms->creds.uid = root_uid;
363+
364+
/* fix gid */
365+
root_gid = make_kgid(owning_user_ns, 0);
366+
if (gid_valid(root_gid))
367+
parms->creds.gid = root_gid;
368+
}
369+
370+
ret = netlink_broadcast(usk, skb, 0, 1, GFP_KERNEL);
371+
/* ENOBUFS should be handled in userspace */
372+
if (ret == -ENOBUFS || ret == -ESRCH)
373+
ret = 0;
374+
375+
return ret;
376+
}
377+
#endif
378+
379+
static int kobject_uevent_net_broadcast(struct kobject *kobj,
380+
struct kobj_uevent_env *env,
381+
const char *action_string,
382+
const char *devpath)
383+
{
384+
int ret = 0;
385+
386+
#ifdef CONFIG_NET
387+
const struct kobj_ns_type_operations *ops;
388+
const struct net *net = NULL;
389+
390+
ops = kobj_ns_ops(kobj);
391+
if (!ops && kobj->kset) {
392+
struct kobject *ksobj = &kobj->kset->kobj;
393+
if (ksobj->parent != NULL)
394+
ops = kobj_ns_ops(ksobj->parent);
395+
}
396+
397+
/* kobjects currently only carry network namespace tags and they
398+
* are the only tag relevant here since we want to decide which
399+
* network namespaces to broadcast the uevent into.
400+
*/
401+
if (ops && ops->netlink_ns && kobj->ktype->namespace)
402+
if (ops->type == KOBJ_NS_TYPE_NET)
403+
net = kobj->ktype->namespace(kobj);
404+
405+
if (!net)
406+
ret = uevent_net_broadcast_untagged(env, action_string,
407+
devpath);
408+
else
409+
ret = uevent_net_broadcast_tagged(net->uevent_sock->sk, env,
410+
action_string, devpath);
411+
#endif
412+
413+
return ret;
414+
}
415+
348416
static void zap_modalias_env(struct kobj_uevent_env *env)
349417
{
350418
static const char modalias_prefix[] = "MODALIAS=";
@@ -703,19 +771,25 @@ static int uevent_net_init(struct net *net)
703771

704772
net->uevent_sock = ue_sk;
705773

706-
mutex_lock(&uevent_sock_mutex);
707-
list_add_tail(&ue_sk->list, &uevent_sock_list);
708-
mutex_unlock(&uevent_sock_mutex);
774+
/* Restrict uevents to initial user namespace. */
775+
if (sock_net(ue_sk->sk)->user_ns == &init_user_ns) {
776+
mutex_lock(&uevent_sock_mutex);
777+
list_add_tail(&ue_sk->list, &uevent_sock_list);
778+
mutex_unlock(&uevent_sock_mutex);
779+
}
780+
709781
return 0;
710782
}
711783

712784
static void uevent_net_exit(struct net *net)
713785
{
714786
struct uevent_sock *ue_sk = net->uevent_sock;
715787

716-
mutex_lock(&uevent_sock_mutex);
717-
list_del(&ue_sk->list);
718-
mutex_unlock(&uevent_sock_mutex);
788+
if (sock_net(ue_sk->sk)->user_ns == &init_user_ns) {
789+
mutex_lock(&uevent_sock_mutex);
790+
list_del(&ue_sk->list);
791+
mutex_unlock(&uevent_sock_mutex);
792+
}
719793

720794
netlink_kernel_release(ue_sk->sk);
721795
kfree(ue_sk);

0 commit comments

Comments
 (0)