从源码的角度去调试分析 CVE-2021-3156: Heap-Based Buffer Overflow in Sudo (Baron Samedit)
说实话我没有分析 cve 的习惯,我只是喜欢 RTFSC,其实是我太菜了。。。。。。
开始吧,我选用的是 sudo 1.9.0 版本,因为 没有为什么我随便选的(affects all legacy versions from 1.8.2 to 1.8.31p2 and all stable versions from 1.9.0 to 1.9.5p1 in their default configuration.)
/* * Command line argument parsing. * Sets nargc and nargv which corresponds to the argc/argv we'll use * for the command to be run (if we are running one). */ // 参数 argc argv 都是直接从 main 函数的 argc argv 传过来的 int parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv, struct sudo_settings **settingsp, char ***env_addp) { int mode = 0; /* what mode is sudo to be run in? */// sudo 的运行模式 int flags = 0; /* mode flags */// sudo 的运行模式的标识 int valid_flags = DEFAULT_VALID_FLAGS; // 用来校验 flags 是否合法 int ch, i; char *cp; constchar *progname; // 运行的程序名,判别运行的是 sudo 还是 sudoedit int proglen;
/* XXX - should fill in settings at the end to avoid dupes */ for (;;) { /* * Some trickiness is required to allow environment variables * to be interspersed with command line options. */ // 解析 -xxx 参数,我删掉了其他无关的 case,我们只用到了 -s if ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch (ch) { ....... case's': sudo_settings[ARG_USER_SHELL].value = "true"; SET(flags, MODE_SHELL); // 加上 MODE_SHELL break; ...... }
/* Load plugins. */ if (!sudo_load_plugins(&policy_plugin, &io_plugins, &audit_plugins, &approval_plugins)) sudo_fatalx(U_("fatal error, unable to load plugins"));
/* Allocate event base so plugin can use it. */ if ((sudo_event_base = sudo_ev_base_alloc()) == NULL) sudo_fatalx("%s", U_("unable to allocate memory"));
int sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], bool verbose, void *closure) { char *iolog_path = NULL; mode_t cmnd_umask = ACCESSPERMS; structsudo_nss *nss; int cmnd_status = -1, oldlocale, validated; int ret = -1;
/* Environment variables specified on the command line. */ if (env_add != NULL && env_add[0] != NULL) sudo_user.env_vars = env_add;
/* * Make a local copy of argc/argv, with special handling * for pseudo-commands and the '-i' option. */ if (argc == 0) { ...... } else { /* Must leave an extra slot before NewArgv for bash's --login */ NewArgc = argc;
if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL) { NewArgv[0] = strdup(runas_pw->pw_shell); if (NewArgv[0] == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); goto done; } sudoers_gc_add(GC_PTR, NewArgv[0]); } }
/* If given the -P option, set the "preserve_groups" flag. */ // 没有 -P,不会进入这个判断 if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS)) def_preserve_groups = true;
/* Find command in path and apply per-command Defaults. */ cmnd_status = set_cmnd(); if (cmnd_status == NOT_FOUND_ERROR) goto done;
/* * Fill in user_cmnd, user_args, user_base and user_stat variables * and apply any command-specific defaults entries. */ staticint set_cmnd(void) { structsudo_nss *nss; char *path = user_path; int ret = FOUND; debug_decl(set_cmnd, SUDOERS_DEBUG_PLUGIN);
/* Allocate user_stat for find_path() and match functions. */ user_stat = calloc(1, sizeof(struct stat)); if (user_stat == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); debug_return_int(NOT_FOUND_ERROR); }
/* Default value for cmnd, overridden below. */ // 这里 user_cmnd == NULL 成立 if (user_cmnd == NULL) user_cmnd = NewArgv[0];