/********************************* /*有关uid的几个问题的思考 /* by Patrick /* 2004-7-29 /* /* /*ps:这篇文章是个人学习的笔记 /*如果您可以从中获益,可以随意复制 /********************************* /**************************************** 如果当前进程具有超级权限 则: 调用setuid(uid)时,该进程可以将自己的:实际用户id,有效用户id,保存的set-user-id设置成其参数uid的值。 既是说,特权用户进程可以将自己改变成任意进程。 如果当前进程是非特权用户 则: 调用setuid(uid)时,如果uid是其实际用户id或保存的set-user-id,就把有效用户id设置成uid的值;如果uid不等于这两个值则将errno设置成EPERM(可供用perror()使用),并出错返回。 既是说,非特权用户不能随意改变自己,这里涉及到保存的set-user-id,所以后面再详细说。
/**************************************** 一个系统启动后,用户从login登录后,会产生一个用户进程,该进程和所有进程一样有七个id值: 实际用户id,有效用户id,保存的set-user-id 实际组id,有效组id,添加组id,保存的set-group-id 这里只说uid的问题,这3个uid来自我们登录名。 (这中间的创建过程我想明白再说) 至此我们有了一个用户shell进程,当执行程序时,通常由fork+exec族函数来做。 由用户进程fork出来的子进程继承父进程的实际uid,和有效uid值(还要继承一些东西,在此先屏蔽掉),子进程再调用exec族,调用时: 如果文件的set-user-id没有置位(st_mode中),那这个子进程的实际uid,有效uid不变,保存的set-user-id从有效用户id复制。 如果文件的set-user-id置位,那这个子进程的实际uid不变,有效uid设置为程序文件的用户id,保存的set-user-id从有效用户id复制。 文件的set-user-id位应该只能由所有者置位,特权用户可以置位所有文件。 /************************************* 说一下正常setuid函数的作用: 引用APUE上的例子(经过简化改遍): 有一个文件A所有者为root,我们需要对它进行操作,但该文件只允许root操作。 所以系统又提供一个程序用来操作这个文件,该程序通过给定的几个受限操作来限制用户,并且所有者为root,且set-user-id置位。 1),那我们执行次程序后进程中: 实际用户id=普通 有效用户id=root 保存的set-user-id=root 2),程序去操作文件A,因为程序有效用户id是root,所以可以操作。 3),然后程序执行setuid(getuid()),此时进程: 实际用户id=普通 有效用户id=普通 保存的set-user-id=root 此时进程就不再有特权。 4),当执行完一些操作后又要操作文件A,则程序执行setuid(rootid),这里的rootid是程序保存的rootid,可以通过复制进程的保存的set-user-id得来。此时进程: 实际用户id=普通 有效用户id=root 保存的set-user-id=root 5),现在程序又可以操作文件A了 综述:有效用户id在需要时变成特权id,不需要时通过setuid(getuid())变回实际用户id,失去特权,这样特权uid只用在最需要的时候,可以一定程度增强安全性。可以想象如果文件A是一个锁,经历这5部刚好是:加锁--操作--解锁的过程(实际APUE上也是将文件A说成是一个锁,我将它简化了)。事实上用户对密码的修改也是这样做的。 /**************************************** 再说一下setuid的非正常作用: 一个普通用户如果想写一个程序,里面包括了setuid(uid)函数,并将其set-user-id置位,那么即使执行自己这个程序,他也扩展不了权限,因为执行程序时,用户进程的几个uid都是自己,执行程序后,实际用户id还是被置为自己,到程序中的setuid(uid)时setuid()的uid只能来自该进程的实际uid和保存的set-user-id,这个函数的这个特性就限制了当前非特权进程不能通过自己来越权。 但是如果有一个程序,它的所有者是root,且有缓冲区溢出问题,且文件的set-user-id位被root置位,那么普通用户执行这样的程序时,实际用户id被设置成root,当前进程的三个uid分别为:实际用户id为普通用户,有效用户id为root,保存的set-user-id为root,此时如果通过改变进程的流程,去执行一个程序,那么它将以root的身份执行这个程序,因为很多程序是通过检查有效用户id(不是实际用户id)识别用户身份。 /********************************************* 有关改变进程流程可以去google搜索相关资料,个人认为主要是因为目前系统的内存分配问题,具体就是堆栈共享一处内存: -------------------内存高址 栈低固定 . . . ------------------<-栈顶 . . . 堆区 ------------------- 数据段 ------------------- 文本段 -------------------内存低址 /* THE END */ /***************By Patrick*****************/ 有关UNIX系统中的uid问题的一些见解和学习记录
难免有错,欢迎指正! |