Mr Dk.'s BlogMr Dk.'s Blog
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🐧 Linux Kernel Comments
    • Chapter 2 - 微型计算机组成结构

      • Chapter 2 - 微型计算机组成结构
    • Chapter 3 - 内核编程语言和环境

      • Chapter 3 - 内核编程语言和环境
    • Chapter 4 - 80X86 保护模式及其编程

      • Chapter 4.1-4.2 - 80X86 系统寄存器和系统指令 & 保护模式内存管理
      • Chapter 4.3 - 分段机制
      • Chapter 4.4 - 分页机制
      • Chapter 4.5 - 保护
      • Chapter 4.6 - 中断和异常处理
      • Chapter 4.7 - 任务管理
      • Chapter 4.8 - 保护模式编程初始化
      • Chapter 4.9 - 一个简单的多任务内核实例
    • Chapter 5 - Linux 内核体系结构

      • Chapter 5.1-5.2 - Linux 内核模式 & 体系结构
      • Chapter 5.3 - Linux 内核对内存的管理和使用
      • Chapter 5.4-5.6 - 中断机制 & 系统调用 & 系统时间和定时
      • Chapter 5.7-5.9 - Linux 进程控制 & 堆栈使用 & 文件系统
    • Chapter 6 - 引导启动程序 (boot)

      • Chapter 6 - 引导启动程序 (boot)
    • Chapter 7 - 初始化程序 (init)

      • Chapter 7 - 初始化程序 (init)
    • Chapter 8 - 内核代码

      • Chapter 8.1 - 内核代码总体功能
      • Chapter 8.2 - asm.s 程序
      • Chapter 8.3 - traps.c 程序
      • Chapter 8.4 - sys_call.s 程序
      • Chapter 8.5 - mktime.c 程序
      • Chapter 8.6 - sched.c 程序
      • Chapter 8.7 - signal.c 程序
      • Chapter 8.8 - exit.c 程序
      • Chapter 8.9 - fork.c 程序
      • Chapter 8.10 - sys.c 程序
    • Chapter 9 - 块设备驱动程序

      • Chapter 9.1 - 块设备驱动程序 总体功能
      • Chapter 9.2 - blk.h 文件
      • Chapter 9.3 - hd.c 程序
      • Chapter 9.4 - ll_rw_blk.c 程序
      • Chapter 9.5 - ramdisk.c 程序
    • Chapter 10 - 字符设备驱动程序

      • Chapter 10.1 - 字符设备驱动程序 总体功能
      • Chapter 10.2 - keyboard.S 程序
      • Chapter 10.3 - console.c 程序
      • Chapter 10.4 - serial.c 程序
      • Chapter 10.5 - rs_io.s 程序
      • Chapter 10.6 - tty_io.c 程序
      • Chapter 10.7 - tty_ioctl.c 程序
    • Chapter 12 - 文件系统

      • Chapter 12.1 - 文件系统 总体功能
      • Chapter 12.2 - buffer.c 程序
      • Chapter 12.3 - bitmap.c 程序
      • Chapter 12.4 - truncate.c 程序
      • Chapter 12.5 - inode.c 程序
      • Chapter 12.6 - super.c 程序
      • Chapter 12.7 - namei.c 程序
      • Chapter 12.9 - block_dev.c 程序
      • Chapter 12.10 - file_dev.c 程序
      • Chapter 12.11 - pipe.c 程序
      • Chapter 12.12 - char_dev.c 程序
      • Chapter 12.13 - read_write.c 程序
      • Chapter 12.14 - open.c 程序
      • Chapter 12.15 - exec.c 程序
      • Chapter 12.16 - stat.c 程序
      • Chapter 12.17 - fcntl.c 程序
      • Chapter 12.18 - ioctl.c 程序
      • Chapter 12.19 - select.c 程序

Chapter 8.10 - sys.c 程序

Created by : Mr Dk.

2019 / 08 / 21 15:30

Ningbo, Zhejiang, China


8.10 sys.c 程序

8.10.1 功能描述

该程序中包含有很多系统调用功能的实现函数,其中返回值为 -ENOSYS 的表示本版 Linux 内核中还没有实现。程序中包含很多关于 ID 的操作,一个用户有用户 ID (uid) 和用户组 ID (gid),是 passwd 文件中对该用户设置的 ID。在每个文件的 inode 中,都保存着宿主的 uid 和 gid,指明了文件拥有者和所属用户组,用于访问或执行文件时的权限判别。另外,在进程的任务数据结构中,保存了三种用户 ID 和组 ID。

TypeUIDGID
进程 IDuid - 拥有该进程的用户gid - 拥有该进程的用户组
有效 IDeuid - 指明访问文件的权限egid - 指明访问文件的权限
保存 IDsuid - 当执行文件的 set-user-ID 置位时,suid 保存着执行文件的 uid;否则 suid 等于进程的 euidsgid - 当执行文件的 set-group-ID 置位时,sgid 中保存着执行文件的 gid;否则 sgid 等于进程的 egid

suid 和 sgid 用于进程访问设置了 set-user-ID 或 set-group-ID 标志的文件

  • 当执行程序时,euid 通常就是 uid,因此进程只能访问进程的有效用户规定的文件
  • 如果文件的 set-user-ID 置位,那么进程的 euid 会被设置为该文件宿主的 uid,因此进程可以访问设置了这种标志的受限文件

比如 Linux 中的 passwd 命令,允许普通用户修改自己的口令。实际上需要超级用户的权限。

8.10.2 代码注释

系统调用 sys_ftime()

系统调用 sys_break()

系统调用 sys_ptrace()

系统调用 sys_gtty()

系统调用 sys_rename()

系统调用 sys_prof()

系统调用 sys_setregid()

设置当前任务的 gid、egid。

int sys_setregid(int rgid, int egid)
{
    if (rgid > 0) {
        if ((current->gid == rgid) || suser())
            current->gid = rgid;
        else
            // 没有超级用户特权
            return (-EPERM);
    }
    if (egid > 0) {
        if ((current->gid == egid) || (current->egid == egid) || suser()) {
            current->egid = egid;
            current->sgid = egid;
        } else
            // 没有超级用户特权
            return (-EPERM);
    }
    return 0;
}

系统调用 sys_setreuid()

设置任务的 uid 和 euid。

int sys_setreuid(int ruid, int euid)
{
    int old_ruid = current->uid;
    
    if (ruid > 0) {
        if ((current->euid == ruid) || (old_ruid == ruid) || suser())
            current->uid = ruid;
        else
            return (-EPERM);
    }
    if (euid > 0) {
        if ((old_ruid == euid) || (current->euid == euid) || suser()) {
            current->euid = euid;
            current->suid = euid;
        } else {
            current->uid = old_ruid;
            return (-EPERM);
        }
    }
    return 0;
}

系统调用 sys_setgid()

设置进程组号。

int sys_setgid(int gid)
{
    if (suser())
        // 超级用户
        current->gid = current->egid = current->sgid = gid;
    else if ((gid == current->gid) || (gid == current->sgid))
        current->egid = gid;
    else
        return -EPERM;
    return 0;
}

系统调用 sys_setuid()

设置任务的 uid。

int sys_setuid(int uid)
{
    if (suser())
        current->uid = current->euid = current->suid = uid;
    else if ((uid == current->uid) || (uid == current->suid))
        current->euid = uid;
    else
        return -EPERM;
    return (0);
}

系统调用 sys_phys()

系统调用 sys_lock()

系统调用 sys_mpx()

系统调用 sys_ulimit()

系统调用 sys_time()

返回 1970.1.1 00:00:00 开始计时的秒数。

int sys_time(long * tloc)
{
    int i;
    
    i = CURRENT_TIME;
    if (tloc) {
        verify_area(tloc, 4);
        put_fs_long(i, (unsigned long *) tloc);
    }
    return i;
}

系统调用 sys_stime()

设置系统开机时间。参数是从 1970.1.1 00:00:00 开始的秒数。调用进程必须具有超级用户权限。

int sys_stime(long * tptr)
{
    if (!suser())
        return -EPERM;
    
    // 函数提供的当前时间 - 已经运行的时间 == 新开机时间
    startup_time = get_fs_long((unsigned long *) tptr) - jiffies/HZ;
    jiffies_offset = 0;
    return 0;
}

系统调用 sys_times()

获取当前任务运行时间统计值。

int sys_times(struct tms * tbuf)
{
    if (tbuf) {
        verify_area(tbuf, sizeof *tbuf);
        put_fs_long(current->utime, (unsigned long *) &tbuf->tms_utime);
        put_fs_long(current->stime, (unsigned long *) &tbuf->tms_stime);
        put_fs_long(current->cutime, (unsigned long *) &tbuf->tms_cutime);
        put_fs_long(current->cstime, (unsigned long *) &tbuf->tms_cstime);
    }
    return jiffies;
}

系统调用 sys_brk()

设置程序数据段末尾位置。

  • 参数数值合理
  • 系统确实有足够的内存
  • 进程没有超越其最大数据段大小

数据段需要大于代码段结尾,小于堆栈结尾。这个函数不会被用户直接调用,而是由 libc 库函数进行包装。

int sys_brk(unsigned long end_data_seg)
{
    if (end_data_seg >= current->end_code &&
        end_data_seg < current->start_stack - 16384)
        current->brk = end_data_seg;
    return current->brk;
}

系统调用 sys_setpgid()

设置指定进程的进程组号。

int sys_setpgid(int pid, int pgid)
{
    int i;
    
    if (!pid)
        pid = current->pid;
    if (!pgid)
        pgid = current->pid;
    if (pgid < 0)
        return -EINVAL;
    
    for (i = 0; i < NR_TASKS; i++)
        if (task[i] && (task[i]->pid == pid) &&
            ((task[i]->p_pptr == current) || (task[i] == current))) {
            // 任务的父进程是当前进程 或 任务就是当前进程
            
            if (task[i]->leader)
                // 会话首领
                return -EPERM;
            if ((task[i]->session != current->session) ||
                ((pgid != pid) && (session_of_pgrp(pgid) != current->session)))
                // 任务的会话与当前进程不同
                // pgid 进程组所属会话号与当前进程所属会话号不同
                return -EPERM;
            // 设置进程的组号
            task[i]->pgrp = pgid;
            return 0;
        }
    // 进程不存在
    return -ESRCH;
}

系统调用 sys_getpgrp()

返回当前进程的进程组号。

int sys_getpgrp(void)
{
    return current->pgrp;
}

系统调用 sys_setsid()

系统调用 sys_getgroups()

系统调用 sys_setgroups()

检查当前进程是否在指定的用户组中 - in_group_p()

int in_group_p(gid_t grp)
{
    int i;
    
    if (grp == current->egid)
        return 1;
    for (i = 0; i < NGROUPS; i++) {
        if (current->groups[i] == NOGROUP) // 扫描完全部有效项
            break;
        if (current->groups[i] == grp) // 扫描到用户组号
            return 1;
    }
    return 0;
}

utsname 结构

static struct utisname thisname = {
    UTS_SYSNAME,    // 当前操作系统名称 "Linux"
    UTS_NODENAME,   // 网络结点名称 (主机名) "(none)"
    UTS_RELEASE,    // 当前操作系统 release "0"
    UTS_VERSION,    // 操作系统版本 "0.12"
    UTS_MACHINE     // 系统运行的硬件类型名称 "i386"
};

系统调用 sys_uname()

获取系统名称等信息。

int sys_uname(struct utsname * name)
{
    int i;
    
    if (!name)
        return -ERROR;
    verify_area(name, sizeof *name); // 检测用户空间内存
    for (i = 0; i < sizeof *name; i++)
        put_fs_byte(((char *) &thisname)[i], i + (char *) name);
    return 0;
}

系统调用 sys_sethostname()

系统调用 sys_getrlimit()

系统调用 sys_setrlimit()

系统调用 sys_getrusage()

当前进程或其子进程的资源使用情况。

系统调用 sys_gettimeofday()

取得系统当前时间。

系统调用 sys_settimeofday()

设置系统当前时间。

将从 CMOS 中读取的时间调整为 GMT 时间保存 adjust_clock()

void adjust_clock()
{
    startup_time += sys_tz.tz_minuteswest * 60;
}

系统调用 sys_umask()

设置当前进程创建文件属性屏蔽码,并返回原屏蔽码。

int sys_umask(int mask)
{
    int old = current->umask;
    
    current->umask = mask & 0777;
    return (old);
}
Edit this page on GitHub
Prev
Chapter 8.9 - fork.c 程序