进程篇(4: 基本进程控制:其他相关控制)--请参照本博客“操作系统”专栏

1. 更改进程的用户ID和组ID:
为什么我们要更改用户ID和组ID的呢?

在UNIX系统中,特权是基于用户和组ID的。当用户需要增加特权,或要访问某个当前没有能力访问的文件时,我们需要更改自己的权限,以让新的ID具有合适的特权或访问权限。与此类似,当程序需要降低其特权或阻止对某些资源的访问时,也需要跟换用户ID或组ID;一般而言,在设计应用程序时,我们总是试图使用"最小特权"模型。依照此模型,我们的程序应当值具有为完成特定的任务所需要的最小特权


NAME
getuid, geteuid - get user identity
SYNOPSIS
#include <unistd.h>
#include <sys/types.h>

uid_t getuid(void);
uid_t geteuid(void);
DESCRIPTION
getuid() returns the real user ID of the calling process. [返回调用进程的实际用户id]
geteuid() returns the effective user ID of the calling process. [返回调用进程的有效用户id]
ERRORS
These functions are always successful.

下面我们编写一段代码返回当前进程的实际用户id和有效用户id:


 1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5
6 int
7 main(void)
8 {
9 printf("the real user id of this process: %d\n",getuid());
10 printf("the effective user id of this process: %d\n",geteuid());
11 exit(0);
12 }

在以普通用户模式(用户名: jiangheng 用户id: )运行下的结果是:

the real user id of this process: 1000
the effective user id of this process: 1000

下面是在普通用户模式下用id命令得到的用户信息:

uid=1000(jiangheng) gid=1000(jiangheng) 组=1000(jiangheng),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),112(lpadmin),118(sambashare)

在root用户下执行程序:

the real user id of this process: 0
the effective user id of this process: 0

可以用setuid来设置实际用户id和有效用户id。与此类似的是,可以使用setgid来设置实际组id和有效组id。下面是linux
manpage中对setuid函数的描述:


NAME
setuid - set user identity [设置用户身份]

SYNOPSIS
#include <sys/types.h>
#include <unistd.h>

int setuid(uid_t uid);

DESCRIPTION
setuid() sets the effective user ID of the calling process[setuid() 设置调用进程的有效用户id]. If the effective UID of the
caller is root, the real UID and saved set-user-ID are also set.[如果调用进程的有效用户id是root的话,实际用户id和保存的set-user-ID位也要被设置]

Under Linux, setuid() is implemented like the POSIX version with the _POSIX_SAVED_IDS
feature. This allows a set-user-ID (other than root) program to drop all of its user
privileges, do some un-privileged work, and then reengage the original effective user ID
in
a secure manner.[这个函数的主要用法是: 将用户的所有特权取消,然后做一些非特权化操作,最将用户的权限恢复]

If the user is root or the program is set-user-ID-root, special care must be taken. The
setuid() function checks the effective user ID of the caller and if it is the superuser,
all process-related user ID‘s are set to uid. After this has occurred, it is impossible
for
the program to regain root privileges.[将具有root权限的进程权限修改之后再也不能恢复它的用户权限]

Thus, a set-user-ID-root program wishing to temporarily drop root privileges, assume the
identity of an unprivileged user, and then regain root privileges afterward cannot use
setuid(). You can accomplish this with seteuid(2).

RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.

tips: 进程实际用户ID,进程有效用户ID,进程保存的设置用户ID详解:

  • 实际用户id和实际组id : 标示"我是谁",也就是登陆用户id和gid。真实用户ID用于标识由谁为正在运行的进程负责

  • 有效用户id和有效组id :
    进程用来决定我们对资源的访问权限,一般情况下有效用户id等于实际用户id,有效用户组id等于实际用户组id; 有效用户ID用于为新创建的文件分配所有权、检查文件访问许可,还用于通过kill系统调用向其它进程发送信号时的许可检查

  • 当保存的设置用户ID位被设置时,那么有效用户id等于文件所有者的uid,而不是实际用户id。

更改ID的若干规则:

  1). 如果进程具有超级用户特权,那么setuid函数将实际用户id,有效用户id,以及保存设置用户id设置为uid;

  2).
若进程没有超级用户权限,但是uid等于实际用户ID或保存的设置用户ID,那么setuid只将有效用户ID设置为uid。不改变实际用户id和保存的设置用户id;

3). 如果上述两个条件都不满足,那么将errno设置为EPERM,并返回-1;

关于内核所维护的三个用户id:

  (1). 只有超级用户进程可以更改实际用户id。

  (2).
当且仅当对程序文件设置了设置用户ID位时,exec函数才会设置有效用户id。如果设置用户ID位没有设置,那么exec函数不会改变有效用户ID,而将其维持为原值。

2. 解释器文件:
  让我们观察一个实例:当执行的文件是解释器文件时,内核是如何处理exec函数的参数以及该解释器文件第一行可选参数的。

进程篇(4: 基本进程控制:其他相关控制)--请参照本博客“操作系统”专栏

时间: 2025-01-02 03:09:27

进程篇(4: 基本进程控制:其他相关控制)--请参照本博客“操作系统”专栏的相关文章

进程篇(3: 基本进程控制:进程的退出)--请参照本博客“操作系统”专栏

1. exit函数: 进程的五种正常的结束方式: 在main函数中执行return语句,这等效于exit; 调用exit函数.此函数由ISO C定义,其操作包括运行各终止处理程序,然后关闭所有标准I/O流等. 调用_exit或_Exit函数,ISO C定义了_Exit函数,目的是为了为进程提供一种无需运行终止处理程序和信号处理程序而终止的方法.并不处理标准I/O流! 进程的最后一个线程在其启动例程中执行返回语句,然后该进程以终止状态0返回. 进程的最后一个线程调用pthread_exit函数.

进程篇(1: 进程运行环境)--请参照本博客“操作系统”专栏

2014年5月30日  下午1:40:59 1. Unix 进程执行环境: 1.1 终止处理程序: ISO C 规定,一个程序可以登记多达32个函数,这些函数将由exit自动调用.我们称这些函数为终止处理程序(exit handler),并调用atexit函数来登记这些函数.该函数的原型如下: 1 #include <stdlib.h>2 3 int atexit(void (*function)(void)); exit调用这些终止程序的顺序与他们登记时的顺序相反(先登记后调用).同一个函数

进程篇(2: C程序的存储空间布局)--请参照本博客“操作系统”专栏

1.  C程序的存储空间布局: C 程序由下面几个部分组成: 正文段(即是代码段): 这是由CPU执行的机器指令部分.通常,正文段是可以共享的,并常常是可读的,以防止程序因为意外原因而修改自身的代码! 初始化数据段(即数据段): 它包含了程序中需要明确的赋初值的变量. 非初始化数据段(bss段):在程序开始执行之前,内核将此段中的数据初始化为0或空指针. 栈.自动变量以及每次函数调用时所需保存的信息都存放在此段中.每次调用函数时,返回地址以及调用者的环境信息(如某些寄存器的值)都存放在栈中.然后

进程篇(3: 基本进程控制)--请参照本博客“操作系统”专栏

1. 进程标识符: 每个进程都有一个非负整型表示的唯一进程ID.但进程ID可以重用,当一个进程终止之后,其进程ID就可以再次被重用了. UNIX系统中常常有一些专用的进程: ID为0的进程通常是调度进程,常常被称为交换进程(swapper),该进程是内核的一部分,它并不执行磁盘上的任何程序,因此也被称为系统进程. ID为1的进程通常是init进程,在自举过程结束后由内核调用,在比较新的版本中是/sbin/init.此进程负责在自举内核后启动一个UNIX系统.init通常读取与系统有关的初始化文件

操作系统之进程篇(1)

1.进程介绍: 1.1 进程模型: 进程是一个程序的实际执行,包含了程序计数器的状态,寄存器和变量等等! 程序可以看成是一个状态的序列,程序在不同时刻呈现出不同的状态,而这种状态的前后交替过程可以看成是程序的执行过程.概念上来说,每个程序有自己的虚拟CPU,但在现实中CPU在不同的进程间来回切换,又称这种切换为伪并行! 进程和程序差别看似微小,实际上却是十分精妙; 可以将计算机执行程序的过程看成一次有趣的烹饪过程.食谱就是程序,厨师就是CPU,而食材是输入,得到的输出是鲜美可口的美食. 当厨师在

操作系统之进程篇(3)

1. 信号量机制的缺陷问题: 在上面的生产者消费者实例中,信号量的工作机制如下(我们以生产者的代码为例): 1 down(&empty); 2 down(&mutex); 3 enter_item(item); 4 up(&mutex); 5 up(&full); 如果交换1号和2号语句,变成: 1 down(&mutex); 2 down(&empty); 那么可能会出现下面的情形: mutex变成0,此时empty == 0,那么生产者阻塞; 此时消费者

操作系统之进程篇(2)

进程间通信(InterProcess Communication,IPC): 进程通信中遇到的三个问题: a) 进程之间如何进行信息的传递? b) 多个进程在执行自己的核心代码时如何能够不相互影响? c) 当进程之间出现相互依赖关系时,如何才能合理的调度进程的执行顺序! 1. 竞争情形: 当两个或多个进程同时读写某个共享资源的时候,程序运行的最终结果由各个进程的具体执行的情况所决定! 如何避免竞争情形的出现,那么我们首先引入关键代码区的定义: 程序中访问共享内存或其他共享资源的代码区被称为关键代

比较好的进程篇总结(转)

原文:http://www.cnitblog.com/guopingleee/archive/2007/09/18/33687.html 一.多进程程序的特点    由于UNIX系统是分时多用户系统, CPU按时间片分配给各个用户使用, 而在实质上应该说CPU按时间片分配给各个进程使用, 每个进程都有自己的运行环境以使得在CPU做进程切换时不会"忘记"该进程已计算了一半的"半成品". 以DOS的概念来说, 进程的切换都是一次"DOS中断"处理过程

操作系统之进程篇(4)--经典进程间通信(IPC)问题

1. 哲学家进餐问题: 问题描述: 五个哲学家在一个圆桌上进餐,每人的面前放了一盘意大利面,两个盘子之间有一个叉子,但是由于盘子里面的面条十分光滑,需要两个叉子才能进行就餐行为.餐桌的布局如下图所示: 假设哲学家的生活中只有两个活动:吃饭和思考[吃饭维持自身之生存,思考探究生存之意义],当然这样的哲学家在现实之中是不存在的.当一个哲学家在殚精竭虑之时,饥饿感随之而来,这是他会拿起左右手边的两个叉子来想享用这俗世之中的美味.酒足饭饱之后,又"躲进小楼成一统,管他春夏与秋冬"去了.问题是: