Commit f662df45 authored by Filipe Brandenburger's avatar Filipe Brandenburger Committed by Pavel Emelyanov

restore: preserve dumpable flag when it is set to 2

Commit d5bb7e97 started to preserve the dumpable flag across migration by
using prctl to get the value on dump and set it back on restore.

On some situations, the dumpable flag can be set to 2.  This happens when it is
not reset (with prctl) after using setuid() or after using execv() on a binary
that has executable but not read permissions, when the fs.suid_dumpable sysctl
is also set to 2.  However, it is not possible to set it to 2 using prctl,
which would make criu restore fail.

Fix this by checking for the value before passing it to prctl.  In case the
value of the dumpable flag was 2 at the source, check whether it is already 2
at the destination, which is likely to happen if the fs.suid_dumpable sysctl is
also set to 2 where restore is running.  In that case, preserve the value,
otherwise reset it to 0 which is the most secure fallback.

Fixes: d5bb7e97

Tested:
- Using dumpable02 zdtm test after setting fs.suid_dumpable to 2.
  # sysctl -w fs.suid_dumpable=2
  # test/zdtm.sh ns/static/dumpable02
  4: DEBUG: before dump: dumpable=2
  4: DEBUG: after restore: dumpable=2
  4: PASS
  Test: zdtm/live/static/dumpable02, Result: PASS
Signed-off-by: 's avatarFilipe Brandenburger <filbranden@google.com>
Acked-by: 's avatarAndrew Vagin <avagin@parallels.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 9f30b9e7
...@@ -191,16 +191,41 @@ static int restore_creds(CredsEntry *ce) ...@@ -191,16 +191,41 @@ static int restore_creds(CredsEntry *ce)
static int restore_dumpable_flag(MmEntry *mme) static int restore_dumpable_flag(MmEntry *mme)
{ {
int current_dumpable;
int ret; int ret;
if (mme->has_dumpable) { if (!mme->has_dumpable) {
pr_warn("Dumpable flag not present in criu dump.\n");
return 0;
}
if (mme->dumpable == 0 || mme->dumpable == 1) {
ret = sys_prctl(PR_SET_DUMPABLE, mme->dumpable, 0, 0, 0); ret = sys_prctl(PR_SET_DUMPABLE, mme->dumpable, 0, 0, 0);
if (ret) { if (ret) {
pr_err("Unable to set PR_SET_DUMPABLE: %d\n", ret); pr_err("Unable to set PR_SET_DUMPABLE: %d\n", ret);
return -1; return -1;
} }
return 0;
} }
/*
* If dumpable flag is present but it is not 0 or 1, then we can not
* use prctl to set it back. Try to see if it is already correct
* (which is likely if sysctl fs.suid_dumpable is the same when dump
* and restore are run), in which case there is nothing to do.
* Otherwise, set dumpable to 0 which should be a secure fallback.
*/
current_dumpable = sys_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
if (mme->dumpable != current_dumpable) {
pr_warn("Dumpable flag [%d] does not match current [%d]. "
"Will fallback to setting it to 0 to disable it.\n",
mme->dumpable, current_dumpable);
ret = sys_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
if (ret) {
pr_err("Unable to set PR_SET_DUMPABLE: %d\n", ret);
return -1;
}
}
return 0; return 0;
} }
......
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