What happens when you run sudo?

What happens when you run sudo? - DEV CommunitySo, what the heck happens when you sudo? If you’ve been working with computers, and specifically Uni... Tagged with unix, linux.https://dev.to/captainsafia/what-happens-when-you-run-sudo-2n02https://github.com/sudo-project/sudohttps://github.com/sudo-project/sudo

So, what the heck happens when you sudo?

If you’ve been working with computers, and specifically Unix-like systems, you’ve probably used the sudo command. It stands for s uper u ser d o. It runs whatever command you want to run as an administrator. It’s often used to give you the privilege to edit system files (like /etc/hosts) or to add directories to system directories and so on.

But how does it work?

If you’ve been around this blog long enough, you know what’s coming next. And you’re either terrified or excited.

It’s time to read some code!

Any command you run on a command line is likely implemented as C program. So, to figure out how sudo works under the hood, we just have to read some C code.

shudders uncontrollably

The home page for the sudo command can be found here. It appears that the latest stable release of sudo, as of writing this, is 1.8.22 which was released on January 16th, 2018. That’s surprisingly recent. In any case, I found the most recent version of the sudo command on GitHub. Time to dive in!

This is my first time reading the C code for a Unix command, so I have no idea where to start. Ideally, I’d like to find the entry point for the application. I assume that this is going to be the main function in some file called sudo.c. I found such an entry point in this file. The first couple of lines of the function seem to be related to variable setup and initialization mostly.

int nargc, ok, status = 0;
char **nargv,** env_add;
char **user_info,** command_info, **argv_out,** user_env_out;
struct sudo_settings *settings;
struct plugin_container *plugin, *next;
sigset_t mask;
debug_decl_vars(main, SUDO_DEBUG_MAIN)/* Make sure fds 0-2 are open and do OS-specific initialization. */
fix_fds();
os_init(argc, argv, envp);setlocale(LC_ALL, "");
bindtextdomain(PACKAGE_NAME, LOCALEDIR);
textdomain(PACKAGE_NAME);(void) tzset();

I could spend a lot of time looking into what each of these functions is, but life is short, and I don’t wanna go down that rabbit hole today. I skimmed through a couple more lines until I ran into a function that piqued my interest.

/* Make sure we are setuid root. */sudo_check_suid(argc > 0 ? argv[0] : "sudo");

Intriguing! What does setuid mean? It’s a way to set the user ID (or the group ID but let’s not get into that here) of the command that is going to be run. Maybe you want to run a command under your standard user (captainsafia), or maybe you wanna do it under a sudo. You would use setuid to accomplish this. So the sudo_check_suid function invokes the geteuid function which gets the user ID of the current running process. It checks to see if that is equal to the ROOT_UID (the user id of the root user) if not, it checks to see if the sudo binary is stored in the user’s PATH variable, which similarly, elevates the user to sudo.

If it does find the sudo binary in the user’s path, it sets a qualified variable to true and checks to see if the sudo command is running properly by calling stat and examining the properties of the stat struct. Here’s the sudo_check_suid function in its entirety.

static void
sudo_check_suid(const char *sudo)
{char pathbuf[PATH_MAX];struct stat sb;bool qualified;debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM)if (geteuid() != ROOT_UID) {/* Search for sudo binary in PATH if not fully qualified. */qualified = strchr(sudo, '/') != NULL;if (!qualified) {char *path = getenv_unhooked("PATH");if (path != NULL) {const char *cp, *ep;const char *pathend = path + strlen(path);for (cp = sudo_strsplit(path, pathend, ":", &ep); cp != NULL;cp = sudo_strsplit(NULL, pathend, ":", &ep)) {int len = snprintf(pathbuf, sizeof(pathbuf), "%.*s/%s",(int)(ep - cp), cp, sudo);if (len <= 0 || (size_t)len >= sizeof(pathbuf))continue;if (access(pathbuf, X_OK) == 0) {sudo = pathbuf;qualified = true;break;}}}}if (qualified && stat(sudo, &sb) == 0) {/* Try to determine why sudo was not running as root. */if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) {sudo_fatalx(U_("%s must be owned by uid %d and have the setuid bit set"),sudo, ROOT_UID);} else {sudo_fatalx(U_("effective uid is not %d, is %s on a file system ""with the 'nosuid' option set or an NFS file system without"" root privileges?"), ROOT_UID, sudo);}} else {sudo_fatalx(U_("effective uid is not %d, is sudo installed setuid root?"),ROOT_UID);}}debug_return;
}

Yes! It’s a lot of code. But don’t be frightened. C code is often excessively verbose because you have to do a lot of things like string concatenation and splitting and error checking manually (errr, more manually than you would in other languages). Higher level languages take care of a lot of this stuff for you. Thank you, Python and JavaScript (and others)!

At this point, I’m scrolling through the rest of the code for the main function in sudo.c and, boy, is there a lot going on! Most of it is setting configurations and warning the user if things aren’t set up correctly.

There was one line of code that caught my eye.

if (!sudo_load_plugins(&policy_plugin, &io_plugins))sudo_fatalx(U_("fatal error, unable to load plugins"));

sudo_load_plugins? What plugins are we loading? What’s going on here? It’s time to investigate!

It turns out that sudo_load_plugins is defined in another file. This function was really long, so I decided just to read the function definition to see if it could provide some information about what the function might do. Usually, in C, you pass pointers to objects into a function. The function then modifies the objects pointed to by those pointers and returns some status code. So by looking at the function definition, I can get a pretty good sense of what the function is doing. In this case, the function definition for sudo_load_plugins looks like this.

static bool
sudo_load_plugin(struct plugin_container *policy_plugin,struct plugin_container_list *io_plugins, struct plugin_info *info)

So the three structs that are modified in this function are the plugin_containerplugin_container_list, and plugin_info. I did some more digging around the code. I won’t narrate all that I did here because it would take a while but I’ll just summarize it here.

The sudo_load_plugins function is responsible for loading policy plugins. The policy plugins are used to define what the privileges the sudo command has for a particular user. If you were administering a Unix system, you could configure sudo never to be able to execute a certain command under sudo for any user or to add logging for sessions. That’s useful!

OK! Back to looking at the main function. The next interesting bit of code is a giant switch statement. It checks the value of the bitwise and the sudo_mode and MODE_MASK variables against a set of constants.

switch (sudo_mode & MODE_MASK) {

I won’t go into the details of the code line by line, but here’s the overall gist. As it turns out, the sudo command can be run in a variety of different modes. You can run it in one mode that allows you to preserve the SHELL variables used by the command (MODE_SHELL).

The last portion of the main function has an extra helpful comment to explain what is going on.

/*
* If the command was terminated by a signal, sudo needs to terminated
* the same way. Otherwise, the shell may ignore a keyboard-generated
* signal. However, we want to avoid having sudo dump core itself.
*/
if (WIFSIGNALED(status)) {struct sigaction sa;

So basically, if the command that we are running is sudo exits unexpectedly than so should sudo.

Phew! A lot was going on in that function. And to be honest, even more in the sudo command in general. I learned that there is a lot more to sudo than just sudo !!. I’m not a Unix system administrator or anything, so I wasn’t aware of all the ways that sudo can be used to monitor and restrict access to privileged commands across Unix systems. The more you know!

Thank you to Todd Miller, the maintainer of sudo, for maintaining such a valuable tool!

运行 sudo 时会发生什么?相关推荐

  1. java面试题40 当编译并运行下面程序时会发生什么结果()

    java面试题40 当编译并运行下面程序时会发生什么结果() 1 2 3 4 5 6 7 8 9 10 11 public class Bground extends Thread{     publ ...

  2. 在C#中,当您在null对象上调用扩展方法时会发生什么?

    本文翻译自:In C#, what happens when you call an extension method on a null object? Does the method get ca ...

  3. linux启动一个进程吗,当你在Linux上启动一个进程时会发生什么?

    本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时,我惊叹不已. 我们要做的是启动一个进程.我们已经在博客上讨论了很多关于系统调用 ...

  4. linux启动一个进程吗,你知道,当你在 Linux 上启动一个进程时会发生什么嘛?

    原标题:你知道,当你在 Linux 上启动一个进程时会发生什么嘛? 本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时,我惊叹不已 ...

  5. linux如何启动一个进程而不阻塞,当你在 Linux 上启动一个进程时会发生什么? | Linux 中国...

    原标题:当你在 Linux 上启动一个进程时会发生什么? | Linux 中国 本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时 ...

  6. javascript原型_在JavaScript中冻结原型时会发生什么

    javascript原型 Have you wondered what happens when you freeze the prototype of an object? Let's find o ...

  7. 网易云音乐的算法有什么特点_当算法设计音乐厅时会发生什么?

    网易云音乐的算法有什么特点 Here are three links worth your time: 这是三个值得您花费时间的链接: What happens when algorithms des ...

  8. [vue] 动态给vue的data添加一个新的属性时会发生什么?怎样解决?

    [vue] 动态给vue的data添加一个新的属性时会发生什么?怎样解决? 如果在实例创建之后添加新的属性到实例上,它不会触发视图更新.如果想要使添加的值做到响应式,应当使用$set()来添加对象. ...

  9. [vue] vue的属性名称与method的方法名称一样时会发生什么问题?

    [vue] vue的属性名称与method的方法名称一样时会发生什么问题? 键名优先级:props > data > methods 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃 ...

最新文章

  1. Base64编码原理与应用
  2. Unix高级环境编程 学习小结(一)
  3. 【CodeForces - 1150A】Stock Arbitraging (贪心,水题)
  4. Java总结:正则表达式
  5. 使用NAT网关轻松为单台云服务器设置多个公网IP
  6. MySQL存储过程中游标使用
  7. android java.rmi不存在_ANDROID_HOME'环境变量设置为不存在的路径Jenkins
  8. cron计划任务、权限和归属 、 使用LDAP认证 、 家目录漫游
  9. Hyper-V 2016 系列教程56 SCVMM 2016 Client的安装
  10. 接口测试之抓包工具fidder
  11. JS中的window对象和document对象是什么?有什么区别?
  12. 高德网络定位之“移动WiFi识别”
  13. 股市一跌再跌,是在提醒我们什么?
  14. Win8 许可证过期怎么重新激活?
  15. php开发游戏玩家属性,游戏数值策划属性篇(一)
  16. 高数 | 【微分方程】已知常系数微分方程特解,反求原方程
  17. 利用Office PPT录制演示视频
  18. Codeforces Round #439 (Div. 2) C.The Intriguing Obsession(组合数、记忆化搜索)
  19. Android 一个TextView中设置文字不同字体大小和颜色的最完整方法
  20. 《ucore lab1 练习5》实验报告

热门文章

  1. 开源一款超实用的 Dubbo 测试工具,已用半年,感觉很有feel~
  2. SpringBoot 中使用 @Valid 注解 + Exception 全局处理器优雅处理参数验证
  3. 由mysql将视图数据导入Spss,发现别名字段数据不准确
  4. Java并发编程-ConcurrentHashMap
  5. Spring框架----IOC的概念和作用之程序的耦合和解耦
  6. B/S开发框架Web安全问题及防范规范之挂马和WebShell
  7. thinkphp中I方法
  8. 10-12-顺序表地址排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版...
  9. ListView加ArrayAdapter结合android.R.layout.activity_list_item快速实现图文显示
  10. vs vue 查看webpack安装成功_在Vue+webpack中详细讲解基础配置