Commit 6d785e6c authored by Andrey Vagin's avatar Andrey Vagin Committed by Andrei Vagin

unix: resolve a socket file when a socket descriptor is available

unix_process_name() are called when sockets are being collected,
but at this moment we don't have socket descriptors.

A socket descriptor is reuired to get mnt_id, what will allow to resolve
a socket path in its mount namespace.
Acked-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 0286752b
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "external.h" #include "external.h"
#include "crtools.h" #include "crtools.h"
#include "fdstore.h" #include "fdstore.h"
#include "fdinfo.h"
#include "kerndat.h" #include "kerndat.h"
#include "protobuf.h" #include "protobuf.h"
...@@ -58,12 +59,6 @@ ...@@ -58,12 +59,6 @@
#define FAKE_INO 0 #define FAKE_INO 0
typedef struct {
char *dir;
unsigned int udiag_vfs_dev;
unsigned int udiag_vfs_ino;
} rel_name_desc_t;
struct unix_sk_desc { struct unix_sk_desc {
struct socket_desc sd; struct socket_desc sd;
unsigned int type; unsigned int type;
...@@ -73,9 +68,12 @@ struct unix_sk_desc { ...@@ -73,9 +68,12 @@ struct unix_sk_desc {
unsigned int wqlen; unsigned int wqlen;
unsigned int namelen; unsigned int namelen;
char *name; char *name;
rel_name_desc_t *rel_name;
unsigned int nr_icons; unsigned int nr_icons;
unsigned int *icons; unsigned int *icons;
unsigned int vfs_dev;
unsigned int vfs_ino;
unsigned char shutdown; unsigned char shutdown;
bool deleted; bool deleted;
...@@ -226,9 +224,8 @@ int kerndat_socket_unix_file(void) ...@@ -226,9 +224,8 @@ int kerndat_socket_unix_file(void)
return 0; return 0;
} }
static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p) static int resolve_rel_name(u32 id, struct unix_sk_desc *sk, const struct fd_parms *p, char **pdir)
{ {
rel_name_desc_t *rel_name = sk->rel_name;
const char *dirs[] = { "cwd", "root" }; const char *dirs[] = { "cwd", "root" };
struct pstree_item *task; struct pstree_item *task;
int mntns_root, i; int mntns_root, i;
...@@ -278,13 +275,13 @@ static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p) ...@@ -278,13 +275,13 @@ static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p)
goto err; goto err;
} }
if ((st.st_ino == rel_name->udiag_vfs_ino) && if ((st.st_ino == sk->vfs_ino) &&
phys_stat_dev_match(st.st_dev, rel_name->udiag_vfs_dev, ns, &path[1])) { phys_stat_dev_match(st.st_dev, sk->vfs_dev, ns, &path[1])) {
rel_name->dir = xstrdup(dir); *pdir = xstrdup(dir);
if (!rel_name->dir) if (!*pdir)
return -ENOMEM; return -ENOMEM;
pr_debug("Resolved relative socket name to dir %s\n", rel_name->dir); pr_debug("Resolved relative socket name to dir %s\n", *pdir);
sk->mode = st.st_mode; sk->mode = st.st_mode;
sk->uid = st.st_uid; sk->uid = st.st_uid;
sk->gid = st.st_gid; sk->gid = st.st_gid;
...@@ -293,10 +290,12 @@ static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p) ...@@ -293,10 +290,12 @@ static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p)
} }
err: err:
pr_err("Can't resolve name for socket %#x\n", rel_name->udiag_vfs_ino); pr_err("Can't resolve name for socket %#x\n", id);
return -ENOENT; return -ENOENT;
} }
static int unix_resolve_name(u32 id, struct unix_sk_desc *d,
UnixSkEntry *ue, const struct fd_parms *p);
static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
{ {
struct unix_sk_desc *sk, *peer; struct unix_sk_desc *sk, *peer;
...@@ -349,11 +348,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) ...@@ -349,11 +348,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
ue->opts = skopts; ue->opts = skopts;
ue->uflags = 0; ue->uflags = 0;
if (sk->rel_name) { if (unix_resolve_name(id, sk, ue, p))
if (resolve_rel_name(sk, p))
goto err; goto err;
ue->name_dir = sk->rel_name->dir;
}
/* /*
* Check if this socket is connected to criu service. * Check if this socket is connected to criu service.
...@@ -528,34 +524,19 @@ const struct fdtype_ops unix_dump_ops = { ...@@ -528,34 +524,19 @@ const struct fdtype_ops unix_dump_ops = {
.dump = dump_one_unix_fd, .dump = dump_one_unix_fd,
}; };
/* static int unix_resolve_name(u32 id, struct unix_sk_desc *d,
* Returns: < 0 on error, 0 if OK, 1 to skip the socket UnixSkEntry *ue, const struct fd_parms *p)
*/
static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg *m, struct nlattr **tb)
{ {
int len, ret; char *name = d->name;
char *name;
len = nla_len(tb[UNIX_DIAG_NAME]);
name = xmalloc(len + 1);
if (!name)
return -ENOMEM;
memcpy(name, nla_data(tb[UNIX_DIAG_NAME]), len);
name[len] = '\0';
if (name[0] != '\0') {
struct unix_diag_vfs *uv;
bool deleted = false; bool deleted = false;
char rpath[PATH_MAX]; char rpath[PATH_MAX];
struct ns_id *ns; struct ns_id *ns;
struct stat st; struct stat st;
int mntns_root; int mntns_root;
int ret;
if (!tb[UNIX_DIAG_VFS]) { if (d->namelen == 0 || name[0] == '\0')
pr_err("Bound socket w/o inode %#x\n", m->udiag_ino); return 0;
goto skip;
}
ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc);
if (!ns) { if (!ns) {
...@@ -569,21 +550,15 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg ...@@ -569,21 +550,15 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg
goto out; goto out;
} }
uv = RTA_DATA(tb[UNIX_DIAG_VFS]);
if (name[0] != '/') { if (name[0] != '/') {
/* /*
* Relative names are be resolved later at first * Relative names are be resolved later at first
* dump attempt. * dump attempt.
*/ */
rel_name_desc_t *rel_name = xzalloc(sizeof(*rel_name));
if (!rel_name) {
ret = -ENOMEM;
goto out;
}
rel_name->udiag_vfs_dev = uv->udiag_vfs_dev;
rel_name->udiag_vfs_ino = uv->udiag_vfs_ino;
d->rel_name = rel_name; ret = resolve_rel_name(id, d, p, &ue->name_dir);
if (ret < 0)
goto out;
goto postprone; goto postprone;
} }
...@@ -591,19 +566,19 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg ...@@ -591,19 +566,19 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg
if (fstatat(mntns_root, rpath, &st, 0)) { if (fstatat(mntns_root, rpath, &st, 0)) {
if (errno != ENOENT) { if (errno != ENOENT) {
pr_warn("Can't stat socket %#x(%s), skipping: %m (err %d)\n", pr_warn("Can't stat socket %#x(%s), skipping: %m (err %d)\n",
m->udiag_ino, rpath, errno); id, rpath, errno);
goto skip; goto skip;
} }
pr_info("unix: Dropping path %s for unlinked sk %#x\n", pr_info("unix: Dropping path %s for unlinked sk %#x\n",
name, m->udiag_ino); name, id);
deleted = true; deleted = true;
} else if ((st.st_ino != uv->udiag_vfs_ino) || } else if ((st.st_ino != d->vfs_ino) ||
!phys_stat_dev_match(st.st_dev, uv->udiag_vfs_dev, ns, name)) { !phys_stat_dev_match(st.st_dev, d->vfs_dev, ns, name)) {
pr_info("unix: Dropping path %s for unlinked bound " pr_info("unix: Dropping path %s for unlinked bound "
"sk %#x.%#x real %#x.%#x\n", "sk %#x.%#x real %#x.%#x\n",
name, (int)st.st_dev, (int)st.st_ino, name, (int)st.st_dev, (int)st.st_ino,
(int)uv->udiag_vfs_dev, (int)uv->udiag_vfs_ino); (int)d->vfs_dev, (int)d->vfs_ino);
deleted = true; deleted = true;
} }
...@@ -612,11 +587,8 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg ...@@ -612,11 +587,8 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg
d->gid = st.st_gid; d->gid = st.st_gid;
d->deleted = deleted; d->deleted = deleted;
}
postprone: postprone:
d->namelen = len;
d->name = name;
return 0; return 0;
out: out:
...@@ -627,6 +599,43 @@ skip: ...@@ -627,6 +599,43 @@ skip:
goto out; goto out;
} }
/*
* Returns: < 0 on error, 0 if OK, 1 to skip the socket
*/
static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg *m, struct nlattr **tb)
{
int len;
char *name;
len = nla_len(tb[UNIX_DIAG_NAME]);
name = xmalloc(len + 1);
if (!name)
return -ENOMEM;
memcpy(name, nla_data(tb[UNIX_DIAG_NAME]), len);
name[len] = '\0';
if (name[0]) {
struct unix_diag_vfs *uv;
if (!tb[UNIX_DIAG_VFS]) {
pr_err("Bound socket w/o inode %#x\n", m->udiag_ino);
goto skip;
}
uv = RTA_DATA(tb[UNIX_DIAG_VFS]);
d->vfs_dev = uv->udiag_vfs_dev;
d->vfs_ino = uv->udiag_vfs_ino;
}
d->namelen = len;
d->name = name;
return 0;
skip:
xfree(name);
return 1;
}
static int unix_collect_one(const struct unix_diag_msg *m, static int unix_collect_one(const struct unix_diag_msg *m,
struct nlattr **tb, struct ns_id *ns) struct nlattr **tb, struct ns_id *ns)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment