mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-04 08:15:37 +00:00
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: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
committed by
Andrei Vagin
parent
0286752b45
commit
6d785e6cdd
185
criu/sk-unix.c
185
criu/sk-unix.c
@@ -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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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 = {
|
|||||||
.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
|
|||||||
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,
|
||||||
|
Reference in New Issue
Block a user