linux/unix编程手册-36_40

228 阅读5分钟

title: linux/unix编程手册-36_40 date: 2018-08-19 11:53:07 categories: programming tags: tips

linux/unix编程手册-36(进程资源)

进程资源的使用情况

#include<sys/resource.h>

int getrusage(int who, struct rusage *res_usage);

who的值

  • RUSAGE_SELF 调用进程
  • RUSAGE_CHILDREN返回调用进程的所有被终止和处于等待状态的子进程
  • RUSAGE_THREAD返回调用线程的相关信息(linux特有)

进程资源的限制

真实用户或特权用户可以在/proc/PID/limits文件查看响应进程的资源限制

# include<sys/resource.h>

int getrlimit(int resource, struct rlimit *rlim);

int setrlimit(int resource, const struct rlimit *rlim);

struct rlimit{
    rlim_t rlim_cur;    //软限制
    rlim_t rlim_max;    //硬限制
}
  • 软限制规定进程能够消耗资源数量
  • 软限制可以调整从0到硬限制之间的任何值
  • 特权可以增大和减小硬限制,非特权进程只能缩小

linux/unix编程手册-37(DEMON)

daemon的特征

  • 它的生命周期很长,一般直到系统关闭
  • 它在后台并不拥有控制终端。控制终端的缺失确保内核永远不会为daemon自动生成任何任务控制信号和终端相关信号。
  • 很多标准的daemon进程会作为特权进程运行(有效用户ID为0)
  • linux上特定的daemon会作为内核线程运行,其实现是内核的一部分,ps查看时,daemon进程的名称会用[]包起来,例如[kthreadd]

创建一个daemo

  • 执行一个fork(),之后父进程退出,子进程继续执行(成为了init的子进程)第一点的第一个解释有问题?
  • 子进程调用setsid()(因为子进程不会是进程组首进程不会失败)
  • 如果保证daemon不会请求一个控制终端(如果打开过设备终端需要以下确保):
    • 将所有可能应用到的终端设备上的open调用指定O_NOTIFY标记
    • setsid()之后再调用fork(),让父进程退出,让孙进程成为daemon,(BSD规定一个进程只能一个显式的ioctl() TIOCSCTTY获取一个控制终端???)
  • 清楚进程的umask
  • 修改进程的当前目录,一般为/,其他的话会导致无法卸载
  • 关闭daemon从父进程继承来的所有打开的文件描述符
  • 关闭了文件描述符0,1,2后,daemon 通常会打开/dev/null,并使用dup2()

使用SIGHUP重新初始化daemon

  • 修改daemon启动参数
  • 修改日志文件
  • 因为daemon没有终端,内核永远不会发送SIGHUP,可以通过SIGHUP解决以上问题

syslo记录消息错误

tip:syslogd会根据syslogd.conf会将消息重新分配到几个目标上(ex:/var/log/messages)

linux/unix编程手册-38(编写安全的特权进程)

一个程序可通过以下两种方式以特权进行

  • 程序设置了set-user-ID和set-group-Id

最小操作权限

  • 在特权程序设置如下
uid_t orig_euid;

orig_euid = geteuid();

if (seteuid(getuid()==-1)
    errExit("seteuid")
/* Do unprivileged work */

if (seteuid(orig_euid)==-1)
    errExit("seteuid")
/* DO privileged work */
  • 注意的是只有特权进程setuid(_id)才能将uid,euid,suid同时设置成_id。
  • 当euid不为0时,是无法修改suid,导致suid不会被重置,进程无法真正的放弃特权。
  • CAP_SETUID可能导致修改用户异常
  • 在执行另一个程序之前永久的删除权限(exec(),system(),popen()
  • 避免执行拥有权限的shell
  • exec()之前关闭所有用不到的文件描述符(close-on-exec)

避免暴露敏感信息

  • 虚拟内存叶换出
  • 核心转储文件的生成

确定进程边界

  • securebits
  • chroot(限制不了set-user-id-root程序)

文件操作和文件I/O注意

不相信输入和环境

缓冲区溢出(一些溢出的库函数)

DOS

linux/unix编程手册-39(能力)

能力的基本原理

进程分两类

  • 有效用户为0超级金城
  • 其他需要根据用户和组确定权限的进程

进程和文件能力

进程能力集

  • 许可的:许可的集合是能够被添加到有效的和可继承的集合中的能力的受限超集;如果进程从许可集中删除了一个能力,将自己无法重新获得
  • 有效的:只有许可集中有这个能力,进程才能从有效集中删除这个能力临时禁用,之后可再还原
  • 当这个进程执行一个程序时可将这些权限带入许可集

可以在/proc/PID/status文件中的CapInh, CapPrm, CapEff中查看能力集的16进制表示(64位)

能力集可以具体到线程/proc/PID/task/TID/status

fork()出的子进程会继承父进程的能力集

会类似于uid, euid, suid

文件能力集

  • 许可的:在exec()中可将这组能力添加到进程的许可集中
  • 有效的:只有一位,如果启用了,在调用exec()之后进程的新许可集中启用的能力在进程的新有效集合中也会被启用。如果被禁用了exec()之后,进程的新有效集一开始是空的
  • 可继承的:这个集合讲和进程的可继承集取掩码来确定执行exec()之后进程的许可集启用的能力集

exec()中转变进程

内核会根据以下规则计算进程的新能力

  • PN(permitted)=(P(inheritable) & F(inheritable)) | (F(permitted) & cap_bset)
  • PN(effective)=F(effective)?PN(permitted):0
  • PN(inheritable)=P(inheritable)

如果执行一个set-user-ID-root的程序,计算简化为

  • PN(permitted)=P(inheritable) | cap_bset
  • PN(effective)=PN(permitted)

其他略

cap_bset为进程级别的能力边界值,一般是全为1(init进程是全1),一个进程具备了CAP_SETPCAP能力后可以不可逆的修改cap_bset, 在status里面是CapBnd

linux/unix编程手册-40(登录记账)

  • utmp维护这当前登录进系统的用户记录。登录时写入(会包含一个ut_user),登出时删除(/var/run/utmp; _PATH_UTMP)
  • wtmp包含所有用户登录和登出行为的留痕信息,登录时记录和utmp记录一致,登出时记录和登入时记录相同除了ut_user字段置位0(/var/log/wtmp; _PATH_WTMP)
  • lastlog 最后一次登录的时间(/var/log/lastlog;_PATH_LASTLOG) 略略了
#include<unistd.h>
char *getlogin(void);