Message ID | 20210210120425.53438-3-lmb@cloudflare.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Expose network namespace cookies to user space | expand |
On Wed, Feb 10, 2021 at 12:04:23PM +0000, Lorenz Bauer wrote: > Network namespaces have a globally unique non-zero identifier aka a > cookie, in line with socket cookies. Add an ioctl to retrieve the > cookie from user space without going via BPF. > > Cc: linux-api@vger.kernel.org > Signed-off-by: Lorenz Bauer <lmb@cloudflare.com> > --- > fs/nsfs.c | 9 +++++++++ > include/net/net_namespace.h | 11 +++++++++++ > include/uapi/linux/nsfs.h | 2 ++ > 3 files changed, 22 insertions(+) > > diff --git a/fs/nsfs.c b/fs/nsfs.c > index 800c1d0eb0d0..d7865e39c049 100644 > --- a/fs/nsfs.c > +++ b/fs/nsfs.c > @@ -11,6 +11,7 @@ > #include <linux/user_namespace.h> > #include <linux/nsfs.h> > #include <linux/uaccess.h> > +#include <net/net_namespace.h> > > #include "internal.h" > > @@ -191,6 +192,8 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl, > struct user_namespace *user_ns; > struct ns_common *ns = get_proc_ns(file_inode(filp)); > uid_t __user *argp; > + struct net *net_ns; > + u64 cookie; > uid_t uid; > > switch (ioctl) { > @@ -209,6 +212,12 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl, > argp = (uid_t __user *) arg; > uid = from_kuid_munged(current_user_ns(), user_ns->owner); > return put_user(uid, argp); > + case NS_GET_COOKIE: > + if (ns->ops->type != CLONE_NEWNET) > + return -EINVAL; > + net_ns = container_of(ns, struct net, ns); > + cookie = net_gen_cookie(net_ns); > + return put_user(cookie, (u64 __user *)arg); Hey Lorenz, Just to make sure: is it intentional that any user can retrieve the cookie associated with any network namespace, i.e. you don't require any form of permission checking in the owning user namespace of the network namespace? Christian
On Mon, 1 Mar 2021 at 10:04, Christian Brauner <christian.brauner@ubuntu.com> wrote: > > Hey Lorenz, > > Just to make sure: is it intentional that any user can retrieve the > cookie associated with any network namespace, i.e. you don't require any > form of permission checking in the owning user namespace of the network > namespace? > > Christian Hi Christian, I've decided to drop the patch set for now, but that was my intention, yes. Is there a downside I'm not aware of? Lorenz
On Tue, Mar 02, 2021 at 09:47:10AM +0000, Lorenz Bauer wrote: > On Mon, 1 Mar 2021 at 10:04, Christian Brauner > <christian.brauner@ubuntu.com> wrote: > > > > Hey Lorenz, > > > > Just to make sure: is it intentional that any user can retrieve the > > cookie associated with any network namespace, i.e. you don't require any > > form of permission checking in the owning user namespace of the network > > namespace? > > > > Christian > > Hi Christian, > > I've decided to drop the patch set for now, but that was my intention, yes. Is > there a downside I'm not aware of? It depends on whether this cookie is in any way security or at least information sensitive. For example, would leaking it between unprivileged containers with different user+network namespace pairs allow one container to gain access to information about the other container that it shouldn't. Christian
diff --git a/fs/nsfs.c b/fs/nsfs.c index 800c1d0eb0d0..d7865e39c049 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -11,6 +11,7 @@ #include <linux/user_namespace.h> #include <linux/nsfs.h> #include <linux/uaccess.h> +#include <net/net_namespace.h> #include "internal.h" @@ -191,6 +192,8 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl, struct user_namespace *user_ns; struct ns_common *ns = get_proc_ns(file_inode(filp)); uid_t __user *argp; + struct net *net_ns; + u64 cookie; uid_t uid; switch (ioctl) { @@ -209,6 +212,12 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl, argp = (uid_t __user *) arg; uid = from_kuid_munged(current_user_ns(), user_ns->owner); return put_user(uid, argp); + case NS_GET_COOKIE: + if (ns->ops->type != CLONE_NEWNET) + return -EINVAL; + net_ns = container_of(ns, struct net, ns); + cookie = net_gen_cookie(net_ns); + return put_user(cookie, (u64 __user *)arg); default: return -ENOTTY; } diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 29567875f428..bbd22dfa9345 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -226,6 +226,17 @@ struct net *get_net_ns_by_fd(int fd); u64 __net_gen_cookie(struct net *net); +static inline u64 net_gen_cookie(struct net *net) +{ + u64 cookie; + + preempt_disable(); + cookie = __net_gen_cookie(net); + preempt_enable(); + + return cookie; +} + #ifdef CONFIG_SYSCTL void ipx_register_sysctl(void); void ipx_unregister_sysctl(void); diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h index a0c8552b64ee..86611c2cf908 100644 --- a/include/uapi/linux/nsfs.h +++ b/include/uapi/linux/nsfs.h @@ -15,5 +15,7 @@ #define NS_GET_NSTYPE _IO(NSIO, 0x3) /* Get owner UID (in the caller's user namespace) for a user namespace */ #define NS_GET_OWNER_UID _IO(NSIO, 0x4) +/* Returns a unique non-zero identifier for a network namespace */ +#define NS_GET_COOKIE _IO(NSIO, 0x5) #endif /* __LINUX_NSFS_H */
Network namespaces have a globally unique non-zero identifier aka a cookie, in line with socket cookies. Add an ioctl to retrieve the cookie from user space without going via BPF. Cc: linux-api@vger.kernel.org Signed-off-by: Lorenz Bauer <lmb@cloudflare.com> --- fs/nsfs.c | 9 +++++++++ include/net/net_namespace.h | 11 +++++++++++ include/uapi/linux/nsfs.h | 2 ++ 3 files changed, 22 insertions(+)