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,12 +524,87 @@ const struct fdtype_ops unix_dump_ops = { ...@@ -528,12 +524,87 @@ 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,
UnixSkEntry *ue, const struct fd_parms *p)
{
char *name = d->name;
bool deleted = false;
char rpath[PATH_MAX];
struct ns_id *ns;
struct stat st;
int mntns_root;
int ret;
if (d->namelen == 0 || name[0] == '\0')
return 0;
ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc);
if (!ns) {
ret = -ENOENT;
goto out;
}
mntns_root = mntns_get_root_fd(ns);
if (mntns_root < 0) {
ret = -ENOENT;
goto out;
}
if (name[0] != '/') {
/*
* Relative names are be resolved later at first
* dump attempt.
*/
ret = resolve_rel_name(id, d, p, &ue->name_dir);
if (ret < 0)
goto out;
goto postprone;
}
snprintf(rpath, sizeof(rpath), ".%s", name);
if (fstatat(mntns_root, rpath, &st, 0)) {
if (errno != ENOENT) {
pr_warn("Can't stat socket %#x(%s), skipping: %m (err %d)\n",
id, rpath, errno);
goto skip;
}
pr_info("unix: Dropping path %s for unlinked sk %#x\n",
name, id);
deleted = true;
} else if ((st.st_ino != d->vfs_ino) ||
!phys_stat_dev_match(st.st_dev, d->vfs_dev, ns, name)) {
pr_info("unix: Dropping path %s for unlinked bound "
"sk %#x.%#x real %#x.%#x\n",
name, (int)st.st_dev, (int)st.st_ino,
(int)d->vfs_dev, (int)d->vfs_ino);
deleted = true;
}
d->mode = st.st_mode;
d->uid = st.st_uid;
d->gid = st.st_gid;
d->deleted = deleted;
postprone:
return 0;
out:
xfree(name);
return ret;
skip:
ret = 1;
goto out;
}
/* /*
* Returns: < 0 on error, 0 if OK, 1 to skip the socket * 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) static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg *m, struct nlattr **tb)
{ {
int len, ret; int len;
char *name; char *name;
len = nla_len(tb[UNIX_DIAG_NAME]); len = nla_len(tb[UNIX_DIAG_NAME]);
...@@ -544,87 +615,25 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg ...@@ -544,87 +615,25 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg
memcpy(name, nla_data(tb[UNIX_DIAG_NAME]), len); memcpy(name, nla_data(tb[UNIX_DIAG_NAME]), len);
name[len] = '\0'; name[len] = '\0';
if (name[0] != '\0') { if (name[0]) {
struct unix_diag_vfs *uv; struct unix_diag_vfs *uv;
bool deleted = false;
char rpath[PATH_MAX];
struct ns_id *ns;
struct stat st;
int mntns_root;
if (!tb[UNIX_DIAG_VFS]) { if (!tb[UNIX_DIAG_VFS]) {
pr_err("Bound socket w/o inode %#x\n", m->udiag_ino); pr_err("Bound socket w/o inode %#x\n", m->udiag_ino);
goto skip; goto skip;
} }
ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc);
if (!ns) {
ret = -ENOENT;
goto out;
}
mntns_root = mntns_get_root_fd(ns);
if (mntns_root < 0) {
ret = -ENOENT;
goto out;
}
uv = RTA_DATA(tb[UNIX_DIAG_VFS]); uv = RTA_DATA(tb[UNIX_DIAG_VFS]);
if (name[0] != '/') { d->vfs_dev = uv->udiag_vfs_dev;
/* d->vfs_ino = uv->udiag_vfs_ino;
* Relative names are be resolved later at first
* 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;
goto postprone;
}
snprintf(rpath, sizeof(rpath), ".%s", name);
if (fstatat(mntns_root, rpath, &st, 0)) {
if (errno != ENOENT) {
pr_warn("Can't stat socket %#x(%s), skipping: %m (err %d)\n",
m->udiag_ino, rpath, errno);
goto skip;
}
pr_info("unix: Dropping path %s for unlinked sk %#x\n",
name, m->udiag_ino);
deleted = true;
} else if ((st.st_ino != uv->udiag_vfs_ino) ||
!phys_stat_dev_match(st.st_dev, uv->udiag_vfs_dev, ns, name)) {
pr_info("unix: Dropping path %s for unlinked bound "
"sk %#x.%#x real %#x.%#x\n",
name, (int)st.st_dev, (int)st.st_ino,
(int)uv->udiag_vfs_dev, (int)uv->udiag_vfs_ino);
deleted = true;
}
d->mode = st.st_mode;
d->uid = st.st_uid;
d->gid = st.st_gid;
d->deleted = deleted;
} }
postprone:
d->namelen = len; d->namelen = len;
d->name = name; d->name = name;
return 0; return 0;
out:
xfree(name);
return ret;
skip: skip:
ret = 1; xfree(name);
goto out; return 1;
} }
static int unix_collect_one(const struct unix_diag_msg *m, static int unix_collect_one(const struct unix_diag_msg *m,
......
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