From 4327682120ec909523a586ee8324bfa74c82e2c7 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Thu, 18 May 2023 02:08:25 +0800 Subject: [PATCH] Add mnt ns attach support for `su` --- native/src/su/su.cpp | 19 +++++++++++++++++-- native/src/su/su.hpp | 2 +- native/src/su/su_daemon.cpp | 12 ++++++++---- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/native/src/su/su.cpp b/native/src/su/su.cpp index 5ca0decc6..9cfd9cdce 100644 --- a/native/src/su/su.cpp +++ b/native/src/su/su.cpp @@ -31,6 +31,7 @@ int quit_signals[] = { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGI "Options:\n" " -c, --command COMMAND pass COMMAND to the invoked shell\n" " -z, --context CONTEXT change SELinux context\n" + " -t, --target PID PID to take mount namespace from\n" " -h, --help display this help message and exit\n" " -, -l, --login pretend the shell to be a login shell\n" " -m, -p,\n" @@ -86,6 +87,7 @@ int su_client_main(int argc, char *argv[]) { { "version", no_argument, nullptr, 'v' }, { "context", required_argument, nullptr, 'z' }, { "mount-master", no_argument, nullptr, 'M' }, + { "target", required_argument, nullptr, 't' }, { nullptr, 0, nullptr, 0 }, }; @@ -99,7 +101,7 @@ int su_client_main(int argc, char *argv[]) { strcpy(argv[i], "-M"); } - while ((c = getopt_long(argc, argv, "c:hlmps:Vvuz:M", long_opts, nullptr)) != -1) { + while ((c = getopt_long(argc, argv, "c:hlmps:Vvuz:Mt:", long_opts, nullptr)) != -1) { switch (c) { case 'c': for (int i = optind - 1; i < argc; ++i) { @@ -131,7 +133,20 @@ int su_client_main(int argc, char *argv[]) { su_req.context = optarg; break; case 'M': - su_req.mount_master = true; + case 't': + if (su_req.target != -1) { + fprintf(stderr, "Can't use -M and -t at the same time\n"); + usage(EXIT_FAILURE); + } + if (optarg == nullptr) { + su_req.target = 0; + } else { + su_req.target = parse_int(optarg); + if (*optarg == '-' || su_req.target == -1) { + fprintf(stderr, "Invalid PID: %s\n", optarg); + usage(EXIT_FAILURE); + } + } break; default: /* Bionic getopt_long doesn't terminate its error output by newline */ diff --git a/native/src/su/su.hpp b/native/src/su/su.hpp index 5da86e5e5..2c9b14719 100644 --- a/native/src/su/su.hpp +++ b/native/src/su/su.hpp @@ -45,7 +45,7 @@ struct su_req_base { uid_t uid = AID_ROOT; bool login = false; bool keepenv = false; - bool mount_master = false; + pid_t target = -1; } __attribute__((packed)); struct su_request : public su_req_base { diff --git a/native/src/su/su_daemon.cpp b/native/src/su/su_daemon.cpp index 7d29ab93b..1ceb6b556 100644 --- a/native/src/su/su_daemon.cpp +++ b/native/src/su/su_daemon.cpp @@ -395,20 +395,24 @@ void su_daemon_handler(int client, const sock_cred *cred) { close(client); // Handle namespaces - if (ctx.req.mount_master) + if (ctx.req.target == -1) + ctx.req.target = ctx.pid; + else if (ctx.req.target == 0) ctx.info->cfg[SU_MNT_NS] = NAMESPACE_MODE_GLOBAL; + else if (ctx.info->cfg[SU_MNT_NS] == NAMESPACE_MODE_GLOBAL) + ctx.info->cfg[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER; switch (ctx.info->cfg[SU_MNT_NS]) { case NAMESPACE_MODE_GLOBAL: LOGD("su: use global namespace\n"); break; case NAMESPACE_MODE_REQUESTER: - LOGD("su: use namespace of pid=[%d]\n", ctx.pid); - if (switch_mnt_ns(ctx.pid)) + LOGD("su: use namespace of pid=[%d]\n", ctx.req.target); + if (switch_mnt_ns(ctx.req.target)) LOGD("su: setns failed, fallback to global\n"); break; case NAMESPACE_MODE_ISOLATE: LOGD("su: use new isolated namespace\n"); - switch_mnt_ns(ctx.pid); + switch_mnt_ns(ctx.req.target); xunshare(CLONE_NEWNS); xmount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr); break;