Skip to content

Commit 0597a4b

Browse files
committed
Add --ptrace to retain CAP_SYS_PTRACE for native debugging
1 parent 6e58e85 commit 0597a4b

1 file changed

Lines changed: 42 additions & 13 deletions

File tree

jrunas.cpp

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#include <signal.h>
1111
#include <stdlib.h>
1212
#include <string.h>
13+
#include <sys/capability.h>
1314
#include <sys/ioctl.h>
15+
#include <sys/prctl.h>
1416
#include <sys/stat.h>
1517
#include <sys/types.h>
1618
#include <sys/wait.h>
@@ -97,12 +99,33 @@ static void set_selinux_context(uid_t uid, const char* seinfo, const char* pkgna
9799
}
98100
}
99101

102+
static void retain_ptrace_capability() {
103+
__user_cap_header_struct hdr = {};
104+
hdr.version = _LINUX_CAPABILITY_VERSION_3;
105+
hdr.pid = 0;
106+
__user_cap_data_struct data[2] = {};
107+
const unsigned int idx = CAP_SYS_PTRACE >> 5;
108+
const unsigned int bit = 1u << (CAP_SYS_PTRACE & 31);
109+
data[idx].effective = bit;
110+
data[idx].permitted = bit;
111+
data[idx].inheritable = bit;
112+
if (capset(&hdr, data) != 0) error(1, errno, "capset(CAP_SYS_PTRACE) failed");
113+
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_SYS_PTRACE, 0, 0) != 0) {
114+
error(1, errno, "PR_CAP_AMBIENT_RAISE(CAP_SYS_PTRACE) failed");
115+
}
116+
}
117+
100118
static void become_app_and_exec(uid_t app_id, const char* seinfo, const char* pkgname,
101-
const std::string& data_dir, char** cmd_argv) {
119+
const std::string& data_dir, char** cmd_argv,
120+
bool keep_ptrace) {
102121
std::vector<gid_t> gids = get_supplementary_gids(app_id);
103122
if (setgroups(gids.size(), gids.data()) == -1) error(1, errno, "setgroups failed");
123+
if (keep_ptrace && prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
124+
error(1, errno, "PR_SET_KEEPCAPS failed");
125+
}
104126
if (setresgid(app_id, app_id, app_id) == -1) error(1, errno, "setresgid failed");
105127
if (setresuid(app_id, app_id, app_id) == -1) error(1, errno, "setresuid failed");
128+
if (keep_ptrace) retain_ptrace_capability();
106129

107130
set_selinux_context(app_id, seinfo, pkgname);
108131

@@ -145,7 +168,7 @@ static void write_all(int fd, const char* buf, size_t len) {
145168
}
146169

147170
static int run_on_pty(uid_t app_id, const char* seinfo, const char* pkgname,
148-
const std::string& data_dir, char** cmd_argv) {
171+
const std::string& data_dir, char** cmd_argv, bool keep_ptrace) {
149172
int ref_tty = isatty(STDOUT_FILENO) ? STDOUT_FILENO : STDIN_FILENO;
150173
struct termios ref_attr;
151174
bool have_attr = (tcgetattr(ref_tty, &ref_attr) == 0);
@@ -169,7 +192,7 @@ static int run_on_pty(uid_t app_id, const char* seinfo, const char* pkgname,
169192
dup2(slave, STDOUT_FILENO);
170193
dup2(slave, STDERR_FILENO);
171194
if (slave > STDERR_FILENO) close(slave);
172-
become_app_and_exec(app_id, seinfo, pkgname, data_dir, cmd_argv);
195+
become_app_and_exec(app_id, seinfo, pkgname, data_dir, cmd_argv, keep_ptrace);
173196
_exit(127);
174197
}
175198

@@ -228,18 +251,24 @@ static int run_on_pty(uid_t app_id, const char* seinfo, const char* pkgname,
228251
}
229252

230253
int main(int argc, char* argv[]) {
231-
if (argc < 2) {
232-
error(1, 0, "usage: jrunas <package-name> [--user <id>] [<command> [<args>]]");
254+
const char* usage =
255+
"usage: jrunas [--ptrace] <package-name> [--user <id>] [<command> [<args>]]";
256+
257+
int argi = 1;
258+
bool keep_ptrace = false;
259+
if (argi < argc && strcmp(argv[argi], "--ptrace") == 0) {
260+
keep_ptrace = true;
261+
argi++;
233262
}
234263

235-
char* pkgname = argv[1];
236-
int cmd_argv_offset = 2;
264+
if (argi >= argc) error(1, 0, "%s", usage);
265+
char* pkgname = argv[argi++];
237266

238267
int userId = 0;
239-
if (argc >= 4 && strcmp(argv[2], "--user") == 0) {
240-
userId = atoi(argv[3]);
268+
if (argc - argi >= 2 && strcmp(argv[argi], "--user") == 0) {
269+
userId = atoi(argv[argi + 1]);
241270
if (userId < 0) error(1, 0, "negative user id: %d", userId);
242-
cmd_argv_offset += 2;
271+
argi += 2;
243272
}
244273

245274
bool is_root = (getuid() == AID_ROOT);
@@ -264,12 +293,12 @@ int main(int argc, char* argv[]) {
264293
std::string data_dir = "/data/user/" + std::to_string(userId) + "/" + pkgname;
265294
check_data_path(pkgname, data_dir.c_str(), userAppId);
266295

267-
char** cmd_argv = argv + cmd_argv_offset;
296+
char** cmd_argv = argv + argi;
268297

269298
if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO)) {
270-
return run_on_pty(userAppId, info.seinfo.c_str(), pkgname, data_dir, cmd_argv);
299+
return run_on_pty(userAppId, info.seinfo.c_str(), pkgname, data_dir, cmd_argv, keep_ptrace);
271300
}
272301

273-
become_app_and_exec(userAppId, info.seinfo.c_str(), pkgname, data_dir, cmd_argv);
302+
become_app_and_exec(userAppId, info.seinfo.c_str(), pkgname, data_dir, cmd_argv, keep_ptrace);
274303
return 1;
275304
}

0 commit comments

Comments
 (0)