sk-unix: resolve fake queuers vs scm fds in unix sockets fallacy

Long story short: we face standard "which was first chicken or egg?"
problem here.

1) In add_fake_unix_queuers() for each unpared established unix socket
we want to add a "fake" queuer. And we want to decide at this point
which task should create this queuer and we just try to copy the task
from original socket. But original socket can have no task yet too,
because it can have no open fds, instead it is residing inside other
unix socket.

2) In prepare_scms we look through the packets from all unix sockets and
detect file descriptors in them.

3) We need to add those packets in special queuer's list so that queuer
can understand when all files we need to put in it are already created.
So it means that we need to have "fake" queuers present at this point.

4) At the same time it is also a point to understand which task should
create those descriptors from unix sockets and we just try to copy the
task from the queuer who would put them to unix socket.

You can imagine that queuers should be created (1) before we try to copy
task from them (3) and their peer socket may only give the task to
queuers (1) after it copyes the task from it's ancestor unix socket (4).

So let's fix it with:

- Split "fake" queuer owner task detection into separate step after
handling scm

- When handling scm, if queuer has no owner task, take it from original
socket

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
(cherry picked from commit 82641caf2580bd941cd78df32193556ed1ae31c2)
Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com>
Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
This commit is contained in:
Pavel Tikhomirov 2022-12-14 17:28:47 +03:00 committed by Alexander Mikhalitsyn
parent 7a0366369a
commit 8c9a5a2690
3 changed files with 51 additions and 6 deletions

View file

@ -360,6 +360,10 @@ static int root_prepare_shared(void)
if (ret)
goto err;
ret = add_fake_unix_queuers_finish();
if (ret)
goto err;
ret = run_post_prepare();
if (ret)
goto err;

View file

@ -40,6 +40,7 @@ extern int collect_sockets(struct ns_id *);
extern struct collect_image_info inet_sk_cinfo;
extern struct collect_image_info unix_sk_cinfo;
extern int add_fake_unix_queuers(void);
extern int add_fake_unix_queuers_finish(void);
extern int fix_external_unix_sockets(void);
extern int prepare_scms(void);
extern int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids);

View file

@ -1058,6 +1058,18 @@ static struct unix_sk_info *find_queuer_for(int id)
return NULL;
}
static struct unix_sk_info *find_unix_socket(int id)
{
struct unix_sk_info *ui;
list_for_each_entry(ui, &unix_sockets, list) {
if (ui->ue->id == id)
return ui;
}
return NULL;
}
static struct fdinfo_list_entry *get_fle_for_task(struct file_desc *tgt, struct pstree_item *owner, bool force_master)
{
struct fdinfo_list_entry *fle;
@ -1115,13 +1127,14 @@ static struct fdinfo_list_entry *get_fle_for_task(struct file_desc *tgt, struct
int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids)
{
struct fdinfo_list_entry *fle;
struct unix_sk_info *ui;
struct pstree_item *owner;
int i;
ui = find_queuer_for(id_for);
if (!ui) {
pr_err("Can't find sender for %#x\n", id_for);
pr_err("Can't find %#x\n", id_for);
return -1;
}
@ -1129,7 +1142,14 @@ int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids)
/*
* This is the task that will restore this socket
*/
owner = file_master(&ui->d)->task;
fle = try_file_master(&ui->d);
if (!fle) {
struct unix_sk_info *peer;
peer = find_unix_socket(id_for);
fle = file_master(&peer->d);
}
owner = fle->task;
pr_info("-> will set up deps\n");
/*
@ -2215,7 +2235,6 @@ static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer)
static int add_fake_queuer(struct unix_sk_info *ui)
{
struct unix_sk_info *peer;
struct pstree_item *task;
UnixSkEntry *peer_ue;
SkOptsEntry *skopts;
FownEntry *fown;
@ -2250,9 +2269,7 @@ static int add_fake_queuer(struct unix_sk_info *ui)
file_desc_add(&peer->d, peer_ue->id, &unix_desc_ops);
list_del_init(&peer->d.fake_master_list);
list_add(&peer->list, &unix_sockets);
task = file_master(&ui->d)->task;
return (get_fle_for_task(&peer->d, task, true) == NULL);
return 0;
}
int add_fake_unix_queuers(void)
@ -2272,6 +2289,29 @@ int add_fake_unix_queuers(void)
return 0;
}
static int add_fake_queuer_finish(struct unix_sk_info *queuer)
{
struct pstree_item *task = file_master(&queuer->peer->d)->task;
return get_fle_for_task(&queuer->d, task, true) == NULL;
}
int add_fake_unix_queuers_finish(void)
{
struct unix_sk_info *ui;
pr_info("Adding fake unix queuers (finish)\n");
list_for_each_entry(ui, &unix_sockets, list) {
if (ui->ue->ino != FAKE_INO)
continue;
if (add_fake_queuer_finish(ui))
return -1;
}
return 0;
}
/* This function is called from post prepare only */
static int interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *peer)
{