From f09d918b40dda0f59b3dfca8dc6bc19b4e601414 Mon Sep 17 00:00:00 2001 From: bol-van Date: Wed, 11 Jun 2025 20:15:43 +0300 Subject: [PATCH] nfqws,tpws: use initgroups() if --user specified --- docs/changes.txt | 1 + nfq/nfqws.c | 60 +++++++++++------------------------------------- nfq/params.c | 29 +++++++++++++++++++++++ nfq/params.h | 5 ++++ nfq/sec.c | 22 ++++++++++++++---- nfq/sec.h | 2 +- tpws/params.c | 21 +++++++++++++++++ tpws/params.h | 7 +++++- tpws/sec.c | 22 ++++++++++++++---- tpws/sec.h | 2 +- tpws/tpws.c | 51 +++++++++++----------------------------- 11 files changed, 125 insertions(+), 97 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 3e40f1de..5dea9826 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -508,6 +508,7 @@ v71.1 nfqws,tpws: much faster ipset implementation. move from hash to avl tree nfqws,tpws: check list files accessibility with dropped privs in --dry-run mode nfqws,tpws: --debug=android for NDK builds +nfqws,tpws: use initgroups instead of setgroups if --user specified nfqws: --filter-ssid (linux-only) install_easy: stop if running embedded release on traditional linux system (some files missing) install_bin: add "read elf" arch detection method diff --git a/nfq/nfqws.c b/nfq/nfqws.c index c929ab7d..f9fc47d6 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -297,7 +297,7 @@ static int nfq_main(void) return 1; } - if (params.droproot && !droproot(params.uid, params.gid, params.gid_count) || !dropcaps()) + if (params.droproot && !droproot(params.uid, params.user, params.gid, params.gid_count) || !dropcaps()) goto err; print_id(); if (params.droproot && !test_list_files()) @@ -439,7 +439,7 @@ static int dvt_main(void) goto exiterr; - if (params.droproot && !droproot(params.uid, params.gid, params.gid_count)) + if (params.droproot && !droproot(params.uid, params.user, params.gid, params.gid_count)) goto exiterr; print_id(); if (params.droproot && !test_list_files()) @@ -661,34 +661,9 @@ static int win_main(const char *windivert_filter) -#if !defined( __OpenBSD__) && !defined(__ANDROID__) -static void cleanup_args() -{ - wordfree(¶ms.wexp); -} -#endif - -static void cleanup_params(void) -{ -#if !defined( __OpenBSD__) && !defined(__ANDROID__) - cleanup_args(); -#endif - - ConntrackPoolDestroy(¶ms.conntrack); - - dp_list_destroy(¶ms.desync_profiles); - - hostlist_files_destroy(¶ms.hostlists); - ipset_files_destroy(¶ms.ipsets); - ipcacheDestroy(¶ms.ipcache); -#ifdef __CYGWIN__ - strlist_destroy(¶ms.ssid_filter); - strlist_destroy(¶ms.nlm_filter); -#endif -} static void exit_clean(int code) { - cleanup_params(); + cleanup_params(¶ms); exit(code); } @@ -1667,7 +1642,7 @@ static void exithelp(void) } static void exithelp_clean(void) { - cleanup_params(); + cleanup_params(¶ms); exithelp(); } @@ -2163,6 +2138,7 @@ int main(int argc, char **argv) #ifndef __CYGWIN__ case IDX_USER: { + free(params.user); params.user=NULL; struct passwd *pwd = getpwnam(optarg); if (!pwd) { @@ -2170,27 +2146,18 @@ int main(int argc, char **argv) exit_clean(1); } params.uid = pwd->pw_uid; - params.gid_count=MAX_GIDS; -#ifdef __APPLE__ - // silence warning - if (getgrouplist(optarg,pwd->pw_gid,(int*)params.gid,¶ms.gid_count)<0) -#else - if (getgrouplist(optarg,pwd->pw_gid,params.gid,¶ms.gid_count)<0) -#endif + params.gid[0]=pwd->pw_gid; + params.gid_count=1; + if (!(params.user=strdup(optarg))) { - DLOG_ERR("getgrouplist failed. too much groups ?\n"); + DLOG_ERR("strdup: out of memory\n"); exit_clean(1); } - if (!params.gid_count) - { - params.gid[0] = pwd->pw_gid; - params.gid_count = 1; - } params.droproot = true; break; } case IDX_UID: - params.droproot = true; + free(params.user); params.user=NULL; if (!parse_uid(optarg,¶ms.uid,params.gid,¶ms.gid_count,MAX_GIDS)) { DLOG_ERR("--uid should be : uid[:gid,gid,...]\n"); @@ -2201,6 +2168,7 @@ int main(int argc, char **argv) params.gid[0] = 0x7FFFFFFF; params.gid_count = 1; } + params.droproot = true; break; #endif case IDX_WSIZE: @@ -2999,7 +2967,7 @@ int main(int argc, char **argv) // do not need args from file anymore #if !defined( __OpenBSD__) && !defined(__ANDROID__) - cleanup_args(); + cleanup_args(¶ms); #endif argv=NULL; argc=0; @@ -3142,7 +3110,7 @@ int main(int argc, char **argv) #ifndef __CYGWIN__ if (params.droproot) { - if (!droproot(params.uid,params.gid,params.gid_count)) + if (!droproot(params.uid,params.user,params.gid,params.gid_count)) exit_clean(1); #ifdef __linux__ if (!dropcaps()) @@ -3177,7 +3145,7 @@ int main(int argc, char **argv) #endif ex: rawsend_cleanup(); - cleanup_params(); + cleanup_params(¶ms); #ifdef __CYGWIN__ if (hMutexArg) { diff --git a/nfq/params.c b/nfq/params.c index 25b6ea6b..aa9b9845 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -345,3 +345,32 @@ bool dp_list_need_all_out(struct desync_profile_list_head *head) return true; return false; } + + +#if !defined( __OpenBSD__) && !defined(__ANDROID__) +void cleanup_args(struct params_s *params) +{ + wordfree(¶ms->wexp); +} +#endif + +void cleanup_params(struct params_s *params) +{ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) + cleanup_args(params); +#endif + + ConntrackPoolDestroy(¶ms->conntrack); + + dp_list_destroy(¶ms->desync_profiles); + + hostlist_files_destroy(¶ms->hostlists); + ipset_files_destroy(¶ms->ipsets); + ipcacheDestroy(¶ms->ipcache); +#ifdef __CYGWIN__ + strlist_destroy(¶ms->ssid_filter); + strlist_destroy(¶ms->nlm_filter); +#else + free(params->user); params->user=NULL; +#endif +} diff --git a/nfq/params.h b/nfq/params.h index 1e108c08..8ee54744 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -200,6 +200,7 @@ struct params_s struct str_list_head ssid_filter,nlm_filter; #else bool droproot; + char *user; uid_t uid; gid_t gid[MAX_GIDS]; int gid_count; @@ -229,6 +230,10 @@ struct params_s extern struct params_s params; extern const char *progname; +#if !defined( __OpenBSD__) && !defined(__ANDROID__) +void cleanup_args(struct params_s *params); +#endif +void cleanup_params(struct params_s *params); int DLOG(const char *format, ...); int DLOG_ERR(const char *format, ...); diff --git a/nfq/sec.c b/nfq/sec.c index 34a428db..a219a049 100644 --- a/nfq/sec.c +++ b/nfq/sec.c @@ -295,7 +295,7 @@ bool can_drop_root(void) #endif } -bool droproot(uid_t uid, gid_t *gid, int gid_count) +bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count) { if (gid_count<1) { @@ -309,11 +309,23 @@ bool droproot(uid_t uid, gid_t *gid, int gid_count) return false; } #endif - // drop all SGIDs - if (setgroups(gid_count,gid)) + if (user) { - DLOG_PERROR("setgroups"); - return false; + // macos has strange supp gid handling. they cache only 16 groups and fail setgroups if more than 16 gids specified. + // better to leave it to the os + if (initgroups(user,gid[0])) + { + DLOG_PERROR("initgroups"); + return false; + } + } + else + { + if (setgroups(gid_count,gid)) + { + DLOG_PERROR("setgroups"); + return false; + } } if (setgid(gid[0])) { diff --git a/nfq/sec.h b/nfq/sec.h index cfa7b664..621eaddc 100644 --- a/nfq/sec.h +++ b/nfq/sec.h @@ -84,7 +84,7 @@ bool dropcaps(void); #ifndef __CYGWIN__ bool sec_harden(void); bool can_drop_root(void); -bool droproot(uid_t uid, gid_t *gid, int gid_count); +bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count); void print_id(void); #endif diff --git a/tpws/params.c b/tpws/params.c index 6789c7cc..c6a9670b 100644 --- a/tpws/params.c +++ b/tpws/params.c @@ -258,3 +258,24 @@ void dp_list_destroy(struct desync_profile_list_head *head) dp_entry_destroy(entry); } } + + +#if !defined( __OpenBSD__) && !defined(__ANDROID__) +void cleanup_args(struct params_s *params) +{ + wordfree(¶ms->wexp); +} +#endif +void cleanup_params(struct params_s *params) +{ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) + cleanup_args(params); +#endif + + dp_list_destroy(¶ms->desync_profiles); + + hostlist_files_destroy(¶ms->hostlists); + ipset_files_destroy(¶ms->ipsets); + ipcacheDestroy(¶ms->ipcache); + free(params->user); params->user=NULL; +} diff --git a/tpws/params.h b/tpws/params.h index 87935e31..4cf51816 100644 --- a/tpws/params.h +++ b/tpws/params.h @@ -117,8 +117,9 @@ struct params_s bool fix_seg_avail; bool no_resolve; bool skip_nodelay; - bool droproot; bool daemon; + bool droproot; + char *user; uid_t uid; gid_t gid[MAX_GIDS]; int gid_count; @@ -155,6 +156,10 @@ struct params_s extern struct params_s params; extern const char *progname; +#if !defined( __OpenBSD__) && !defined(__ANDROID__) +void cleanup_args(struct params_s *params); +#endif +void cleanup_params(struct params_s *params); int DLOG(const char *format, int level, ...); int DLOG_CONDUP(const char *format, ...); diff --git a/tpws/sec.c b/tpws/sec.c index 2adb19d0..ed6bd4d3 100644 --- a/tpws/sec.c +++ b/tpws/sec.c @@ -269,7 +269,7 @@ bool can_drop_root(void) #endif } -bool droproot(uid_t uid, gid_t *gid, int gid_count) +bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count) { if (gid_count<1) { @@ -283,11 +283,23 @@ bool droproot(uid_t uid, gid_t *gid, int gid_count) return false; } #endif - // drop all SGIDs - if (setgroups(gid_count,gid)) + if (user) { - DLOG_PERROR("setgroups"); - return false; + // macos has strange supp gid handling. they cache only 16 groups and fail setgroups if more than 16 gids specified. + // better to leave it to the os + if (initgroups(user,gid[0])) + { + DLOG_PERROR("initgroups"); + return false; + } + } + else + { + if (setgroups(gid_count,gid)) + { + DLOG_PERROR("setgroups"); + return false; + } } if (setgid(gid[0])) { diff --git a/tpws/sec.h b/tpws/sec.h index 8a513fa1..c75ad4bb 100644 --- a/tpws/sec.h +++ b/tpws/sec.h @@ -84,7 +84,7 @@ bool dropcaps(void); bool sec_harden(void); bool can_drop_root(); -bool droproot(uid_t uid, gid_t *gid, int gid_count); +bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count); void print_id(void); void daemonize(void); bool writepid(const char *filename); diff --git a/tpws/tpws.c b/tpws/tpws.c index 92dd21a1..893e433d 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -290,32 +290,14 @@ static void exithelp(void) ); exit(1); } -#if !defined( __OpenBSD__) && !defined(__ANDROID__) -static void cleanup_args() -{ - wordfree(¶ms.wexp); -} -#endif -static void cleanup_params(void) -{ -#if !defined( __OpenBSD__) && !defined(__ANDROID__) - cleanup_args(); -#endif - - dp_list_destroy(¶ms.desync_profiles); - - hostlist_files_destroy(¶ms.hostlists); - ipset_files_destroy(¶ms.ipsets); - ipcacheDestroy(¶ms.ipcache); -} static void exithelp_clean(void) { - cleanup_params(); + cleanup_params(¶ms); exithelp(); } static void exit_clean(int code) { - cleanup_params(); + cleanup_params(¶ms); exit(code); } static void nextbind_clean(void) @@ -982,6 +964,7 @@ void parse_params(int argc, char *argv[]) break; case IDX_USER: { + free(params.user); params.user=NULL; struct passwd *pwd = getpwnam(optarg); if (!pwd) { @@ -989,27 +972,18 @@ void parse_params(int argc, char *argv[]) exit_clean(1); } params.uid = pwd->pw_uid; - params.gid_count=MAX_GIDS; -#ifdef __APPLE__ - // silence warning - if (getgrouplist(optarg,pwd->pw_gid,(int*)params.gid,¶ms.gid_count)<0) -#else - if (getgrouplist(optarg,pwd->pw_gid,params.gid,¶ms.gid_count)<0) -#endif + params.gid[0]=pwd->pw_gid; + params.gid_count=1; + if (!(params.user=strdup(optarg))) { - DLOG_ERR("getgrouplist failed. too much groups ?\n"); + DLOG_ERR("strdup: out of memory\n"); exit_clean(1); } - if (!params.gid_count) - { - params.gid[0] = pwd->pw_gid; - params.gid_count = 1; - } params.droproot = true; break; } case IDX_UID: - params.droproot = true; + free(params.user); params.user=NULL; if (!parse_uid(optarg,¶ms.uid,params.gid,¶ms.gid_count,MAX_GIDS)) { DLOG_ERR("--uid should be : uid[:gid,gid,...]\n"); @@ -1020,6 +994,7 @@ void parse_params(int argc, char *argv[]) params.gid[0] = 0x7FFFFFFF; params.gid_count = 1; } + params.droproot = true; break; case IDX_MAXCONN: params.maxconn = atoi(optarg); @@ -1727,13 +1702,13 @@ void parse_params(int argc, char *argv[]) #if !defined( __OpenBSD__) && !defined(__ANDROID__) // do not need args from file anymore - cleanup_args(); + cleanup_args(¶ms); #endif if (bDry) { if (params.droproot) { - if (!droproot(params.uid,params.gid,params.gid_count)) + if (!droproot(params.uid,params.user,params.gid,params.gid_count)) exit_clean(1); #ifdef __linux__ if (!dropcaps()) @@ -2171,7 +2146,7 @@ int main(int argc, char *argv[]) } set_ulimit(); - if (params.droproot && !droproot(params.uid,params.gid,params.gid_count)) + if (params.droproot && !droproot(params.uid,params.user,params.gid,params.gid_count)) goto exiterr; #ifdef __linux__ if (!dropcaps()) @@ -2215,6 +2190,6 @@ exiterr: if (Fpid) fclose(Fpid); redir_close(); for(i=0;i<=params.binds_last;i++) if (listen_fd[i]!=-1) close(listen_fd[i]); - cleanup_params(); + cleanup_params(¶ms); return exit_v; }