Skip to content

Commit

Permalink
Add support for running traced commands as a specified user
Browse files Browse the repository at this point in the history
This change adds a new command-line option `-u/--user=<username>`.
The primary motivation for this feature is to address the limitations when the traced command invokes a `setuid` system call (such as those executed by the `yay` command, which internally calls `sudo pacman ...`). Ordinary users cannot `ptrace` a `setuid` call, which leads to errors like "sudo: effective uid is not 0..." and the subsequent termination of the process.

To circumvent this issue, the tracer process can start with root privileges, and the tracee process executes the commands to be traced as the specified user. For example:

    sudo mgraftcp -u username command_to_trace

This allows tracing commands that invoke setuid system calls, which would
otherwise fail due to insufficient privileges when run as a non-root user.
  • Loading branch information
hmgle committed May 30, 2024
1 parent a18d303 commit 8c62a84
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 3 deletions.
7 changes: 7 additions & 0 deletions conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ int conf_init(struct graftcp_conf *conf)
conf->blackip_file_path = NULL;
conf->whiteip_file_path = NULL;
conf->ignore_local = NULL;
conf->username = NULL;
return 0;
}

Expand Down Expand Up @@ -200,6 +201,10 @@ void conf_free(struct graftcp_conf *conf)
free(conf->ignore_local);
conf->ignore_local = NULL;
}
if (conf->username) {
free(conf->username);
conf->username = NULL;
}
}

static char *xdg_config_path_dup(void)
Expand Down Expand Up @@ -283,4 +288,6 @@ void conf_override(struct graftcp_conf *w, const struct graftcp_conf *r)
w->whiteip_file_path = r->whiteip_file_path;
if (r->ignore_local)
w->ignore_local = r->ignore_local;
if (r->username)
w->username = r->username;
}
1 change: 1 addition & 0 deletions conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct graftcp_conf {
char *blackip_file_path;
char *whiteip_file_path;
bool *ignore_local;
char *username;
};

typedef int (*config_cb)(const char *, const char *, struct graftcp_conf *);
Expand Down
50 changes: 47 additions & 3 deletions graftcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
#define ENABLE_SECCOMP_BPF
Expand Down Expand Up @@ -47,6 +49,10 @@ int LOCAL_PIPE_FD;
cidr_trie_t *BLACKLIST_IP = NULL;
cidr_trie_t *WHITELACKLIST_IP = NULL;


static uid_t run_uid;
static gid_t run_gid;

static int exit_code = 0;

static void load_ip_file(char *path, cidr_trie_t **trie)
Expand Down Expand Up @@ -308,7 +314,7 @@ void do_child(int argc, char **argv)
}
}

void init(int argc, char **argv)
void init(struct graftcp_conf *conf, int argc, char **argv)
{
pid_t child;
struct proc_info *pi;
Expand All @@ -318,6 +324,21 @@ void init(int argc, char **argv)
perror("fork");
exit(errno);
} else if (child == 0) {
if (conf->username) {
if (initgroups(conf->username, run_gid) < 0) {
perror("initgroups");
exit(errno);
}

if (setregid(run_gid, run_gid) < 0) {
perror("setregid");
exit(errno);
}
if (setreuid(run_uid, run_uid) < 0) {
perror("setreuid");
exit(errno);
}
}
#ifdef ENABLE_SECCOMP_BPF
install_seccomp();
#endif
Expand Down Expand Up @@ -495,6 +516,8 @@ static void usage(char **argv)
" -n --not-ignore-local\n"
" Connecting to local is not changed by default, this\n"
" option will redirect it to SOCKS5\n"
" -u --user=<username>\n"
" Run command as USERNAME handling setuid and/or setgid\n"
" -V --version\n"
" Show version\n"
" -h --help\n"
Expand All @@ -514,6 +537,7 @@ int client_main(int argc, char **argv)
{"local-fifo", required_argument, 0, 'f'},
{"blackip-file", required_argument, 0, 'b'},
{"whiteip-file", required_argument, 0, 'w'},
{"user", required_argument, 0, 'u'},
{"not-ignore-local", no_argument, 0, 'n'},
{0, 0, 0, 0}
};
Expand All @@ -525,6 +549,7 @@ int client_main(int argc, char **argv)
.blackip_file_path = NULL,
.whiteip_file_path = NULL,
.ignore_local = &DEFAULT_IGNORE_LOCAL,
.username = NULL,
};

__defer_free char *conf_file_path = NULL;
Expand All @@ -533,7 +558,7 @@ int client_main(int argc, char **argv)
conf_init(&file_conf);
conf_init(&cmd_conf);

while ((opt = getopt_long(argc, argv, "+Vha:p:f:b:w:c:n", long_opts,
while ((opt = getopt_long(argc, argv, "+Vha:p:f:b:w:c:u:n", long_opts,
&index)) != -1) {
switch (opt) {
case 'a':
Expand All @@ -559,6 +584,9 @@ int client_main(int argc, char **argv)
case 'c':
conf_file_path = strdup(optarg);
break;
case 'u':
cmd_conf.username = strdup(optarg);
break;
case 'V':
fprintf(stderr, "graftcp %s\n", VERSION);
exit(0);
Expand Down Expand Up @@ -609,7 +637,23 @@ int client_main(int argc, char **argv)
exit(errno);
}

init(argc - optind, argv + optind);
if (conf.username) {
struct passwd *pent;

if (getuid() != 0 || geteuid() != 0) {
fprintf(stderr, "You must be root to use the -u option\n");
exit(1);
}
pent = getpwnam(conf.username);
if (pent == NULL) {
fprintf(stderr, "Cannot find user '%s'\n", conf.username);
exit(1);
}
run_gid = pent->pw_gid;
run_uid = pent->pw_uid;
}

init(&conf, argc - optind, argv + optind);
if (do_trace() < 0)
return -1;
return exit_code;
Expand Down

0 comments on commit 8c62a84

Please sign in to comment.