Port ms commit c62cce2caee5

Each socket operates in a network namespace where it has been created,
so if we want to dump and restore a socket, we have to know its network
namespace.

We have a socket_diag to get information about sockets, it doesn't
report sockets which are not bound or connected.

This patch introduces a new socket ioctl, which is called SIOCGSKNS
and used to get a file descriptor for a socket network namespace.

A task must have CAP_NET_ADMIN in a target network namespace to
use this ioctl.

Cc: "David S. Miller" <[email protected]>
Cc: Eric W. Biederman <[email protected]>
Signed-off-by: Andrei Vagin <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Kirill Tkhai <[email protected]>
---
 fs/proc/namespaces.c         |    2 +-
 include/linux/proc_ns.h      |    8 ++++++++
 include/uapi/linux/sockios.h |    1 +
 net/socket.c                 |   32 ++++++++++++++++++++++++++++++++
 4 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 626d943b23f8..d03078162944 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -130,7 +130,7 @@ static struct dentry *proc_ns_get_dentry(struct super_block 
*sb,
        return __proc_ns_get_dentry(sb, ns, ns_ops);
 }
 
-static int open_related_ns(struct vfsmount *mnt, struct proc_ns *ns,
+int open_related_ns(struct vfsmount *mnt, struct proc_ns *ns,
                const struct proc_ns_operations *relative_ns_ops,
                void *(*get_ns)(void *ns,
                        const struct proc_ns_operations *ns_ops)) {
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index af898ed6fbad..53d7aca52478 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -78,4 +78,12 @@ static inline bool proc_ns_inode(struct inode *inode) { 
return false; }
 
 #endif /* CONFIG_PROC_FS */
 
+struct vfsmount;
+int open_related_ns(struct vfsmount *mnt, struct proc_ns *ns,
+                   const struct proc_ns_operations *relative_ns_ops,
+                   void *(*get_ns)(void *ns,
+                   const struct proc_ns_operations *ns_ops));
+
+int open_net_ns_fd(struct net *net);
+
 #endif /* _LINUX_PROC_NS_H */
diff --git a/include/uapi/linux/sockios.h b/include/uapi/linux/sockios.h
index e888b1aed69f..cf0a25ebc74c 100644
--- a/include/uapi/linux/sockios.h
+++ b/include/uapi/linux/sockios.h
@@ -84,6 +84,7 @@
 #define SIOCWANDEV     0x894A          /* get/set netdev parameters    */
 
 #define SIOCOUTQNSD    0x894B          /* output queue size (not sent only) */
+#define SIOCGSKNS      0x894C          /* get socket network namespace */
 
 /* ARP cache control calls. */
                    /*  0x8950 - 0x8952  * obsolete calls, don't re-use */
diff --git a/net/socket.c b/net/socket.c
index b76a5da91122..b79c1d5efee5 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -67,6 +67,7 @@
 #include <linux/rcupdate.h>
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
+#include <linux/proc_ns.h>
 #include <linux/seq_file.h>
 #include <linux/mutex.h>
 #include <linux/if_bridge.h>
@@ -1026,6 +1027,29 @@ static long sock_do_ioctl(struct net *net, struct socket 
*sock,
  *     what to do with it - that's up to the protocol still.
  */
 
+static void *get_net_ns(void *ns, const struct proc_ns_operations *ns_ops)
+{
+       struct net *net = ns;
+       return get_net(net);
+}
+
+int open_net_ns_fd(struct net *net)
+{
+       struct proc_ns ns = { .ns = net, .ns_ops = &netns_operations, };
+       struct vfsmount *proc_mnt;
+       int ret;
+
+       proc_mnt = mntget(task_active_pid_ns(current)->proc_mnt);
+       if (IS_ERR(proc_mnt))
+               return PTR_ERR(proc_mnt);
+
+       ret = open_related_ns(proc_mnt, &ns, ns.ns_ops, get_net_ns);
+       mntput(proc_mnt);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(open_net_ns_fd);
+
 static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
        struct socket *sock;
@@ -1093,6 +1117,13 @@ static long sock_ioctl(struct file *file, unsigned cmd, 
unsigned long arg)
                                err = dlci_ioctl_hook(cmd, argp);
                        mutex_unlock(&dlci_ioctl_mutex);
                        break;
+               case SIOCGSKNS:
+                       err = -EPERM;
+                       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+                               break;
+
+                       err = open_net_ns_fd(net);
+                       break;
                default:
                        err = sock_do_ioctl(net, sock, cmd, arg);
                        break;
@@ -3246,6 +3277,7 @@ static int compat_sock_ioctl_trans(struct file *file, 
struct socket *sock,
        case SIOCSIFVLAN:
        case SIOCADDDLCI:
        case SIOCDELDLCI:
+       case SIOCGSKNS:
                return sock_ioctl(file, cmd, arg);
 
        case SIOCGIFFLAGS:

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to