2009年12月08日
情報科学類 オペレーティングシステム II
筑波大学 システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/literacy-2009/2009-12-08
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
1: /*
2: arg-print.c -- mainの引数を表示するプログラム
3: ~yas/syspro/proc/arg-print.c
4: Start: 1997/04/21 18:23:13
5: */
6:
7: #include <stdio.h>
8:
9: main( int argc, char *argv[], char *envp[] )
10: {
11: int i ;
12: printf("&argc == 0x%x, argc == %d\n", &argc, argc );
13: printf("&argv == 0x%x, argv == 0x%x\n",&argv, argv );
14: for( i=0 ; argv[i] ; i++ )
15: printf("argv[%d]==0x%x, \"%s\"\n",i,argv[i],argv[i] );
16: }
% cp ~yas/syspro/proc/arg-print.c .
% cc arg-print.c -o arg-print
% ./arg-print a b c
&argc == 0x6f461d2c, argc == 4
&argv == 0x6f461d20, argv == 0x6f461e28
argv[0]==0x6f4639c7, "./arg-print"
argv[1]==0x6f4639d3, "a"
argv[2]==0x6f4639d5, "b"
argv[3]==0x6f4639d7, "c"
% ./arg-print "a b c"
&argc == 0x33c0ba2c, argc == 2
&argv == 0x33c0ba20, argv == 0x33c0bb28
argv[0]==0x33c0d9c7, "./arg-print"
argv[1]==0x33c0d9d3, "a b c"
%
| 表示 | 説明 |
| STAT | State。状態。 |
| PID | Process ID。プロセス1つ1つに重複ないように(unique)割り当てた番号。 |
| PPID | Parent PID。親プロセスのPID。 |
| UID | User ID。プロセスを生成した利用者の識別子。 |
% ps l
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1013 20591 20590 15 0 9224 2696 rt_sig Ss pts/1 0:00 -tcsh
0 1013 20761 20591 16 0 3724 904 finish T pts/1 0:00 nm /usr/lib/l
0 1013 20762 20591 16 0 2720 624 finish T pts/1 0:00 lv
0 1013 20795 20591 16 0 4256 628 - R+ pts/1 0:00 ps l
%
/proc の下に、カーネル内のデータを取り出すための疑似的なファイ
ルが存在する。特に、/proc/PID の下には、プロセス識別子
がPID のプロセスの情報が現れる。詳しくは、man procを見なさい。
% echo $$
12507
% ls /proc/$$/
attr cpuset fd maps numa_maps schedstat status
auxv cwd io mem oom_adj smaps task
cmdline environ limits mounts oom_score stat wchan
coredump_filter exe loginuid mountstats root statm
% head -11 /proc/$$/status
Name: tcsh
State: S (sleeping)
SleepAVG: 98%
Tgid: 12507
Pid: 12507
PPid: 12506
TracerPid: 0
Uid: 1013 1013 1013 1013
Gid: 510 510 510 510
FDSize: 64
Groups: 20 510 1020 1065 1150
%
1: /*
2: fork-pid-ppid.c -- 画面に pid と ppid を表示するプログラム
3: ~yas/syspro/proc/fork-pid-ppid.c
4: Created on: 2009/12/08 00:50:25
5: */
6:
7: #include <sys/types.h> /* getpid(), getppid() */
8: #include <unistd.h> /* getpid(), getppid() */
9: #include <stdio.h>
10:
11: main()
12: {
13: pid_t pid, ppid;
14: fork();
15: pid = getpid();
16: ppid = getppid();
17: printf("pid=%d, ppid=%d\n", pid, ppid );
18: }
19:
% cc fork-pid-ppid.c -o fork-pid-ppid
% echo $$
11080
% ./fork-pid-ppid
pid=11650, ppid=11080
pid=11651, ppid=11650
% ./fork-pid-ppid
pid=11652, ppid=11080
pid=11653, ppid=11652
% ./fork-pid-ppid
pid=11654, ppid=11080
pid=11655, ppid=11654
% ./fork-pid-ppid
pid=11658, ppid=11657
pid=11657, ppid=11080
%
% id
uid=1013(yas) gid=510(prof) groups=20(games),510(prof),1020(c-admin),1065(c-spec),1150(tebiki)
%
getuid(), getgid(), getgroups() システム・コールを使っている。
1:
2: /*
3: id-simple.c -- a simple id command
4: Created on: 2009/12/07 22:16:23
5: */
6:
7: #include <unistd.h> /* getuid(), getgid(), getgroups() */
8: #include <sys/types.h> /* getuid(), getgid(), getgroups() */
9: #include <stdio.h> /* printf() */
10:
11: #define MAXNGROUPS 100
12:
13: main( int argc, char *argv[], char *envp[] )
14: {
15: uid_t uid ;
16: gid_t gid ;
17: gid_t groups[MAXNGROUPS];
18: int len, i;
19: uid = getuid();
20: gid = getgid();
21: len = getgroups(MAXNGROUPS,&groups[0]);
22: printf("uid=%d gid=%d groups=", uid, gid );
23: for( i=0; i<len; i++ )
24: printf("%d,", groups[i]);
25: printf("\n");
26: }
% cc id-simple.c -o id-simple
% ./id-simple
uid=1013 gid=510 groups=20,510,1020,1065,1150,
%
include/linux/sched.h
1166: struct task_struct {
1167: volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
...
1220:
1223: /* task state */
1224: struct linux_binfmt *binfmt;
1225: int exit_state;
...
1233: pid_t pid;
1234: pid_t tgid;
1244: struct task_struct *real_parent; /* real parent process */
1245: struct task_struct *parent; /* recipient of SIGCHLD, wait4() reports */
...
1249: struct list_head children; /* list of my children */
1250: struct list_head sibling; /* linkage in my parent's children list */
1251: struct task_struct *group_leader; /* threadgroup leader */
...
1267: /* PID/PID hash table linkage. */
1268: struct pid_link pids[PIDTYPE_MAX];
1269: struct list_head thread_group;
...
1288: const struct cred *real_cred; /* objective and real subjective task
1289: * credentials (COW) */
1290: const struct cred *cred; /* effective (overridable) subjective task
1291: * credentials (COW) */
...
1296: char comm[TASK_COMM_LEN]; /* executable name excluding path
1297: - access with [gs]et_task_comm (which lock
1298: it with task_lock())
1299: - initialized normally by flush_old_exec */
...
1483: };
STAT の部分に現れる。
一般的に、プロセスの基本は、3状態。
| 状態 | 説明 |
|---|---|
| Ready | CPUがあれば実行できる |
| Running | CPUが割り当てられ、実行中 |
| Blocked (waiting) | I/O完了待ち、ネットワークやユーザからの入力待ち。 |

図? プロセスの3状態
Linux のプロセスの状態はもう少し多い。 task_struct 構造体の state, exit_state の2つの変数で表現している。include/linux/sched.h 180: #define TASK_RUNNING 0 181: #define TASK_INTERRUPTIBLE 1 182: #define TASK_UNINTERRUPTIBLE 2 183: #define __TASK_STOPPED 4 184: #define __TASK_TRACED 8 185: /* in tsk->exit_state */ 186: #define EXIT_ZOMBIE 16 187: #define EXIT_DEAD 32 188: /* in tsk->state again */ 189: #define TASK_DEAD 64 190: #define TASK_WAKEKILL 128
| 一般的な状態 | Linuxの状態 | ps表示 | 説明 |
| Ready | TASK_RUNNING | R | 実行可能。CPU が割り当てられていれば実行中。 |
| Running | TASK_RUNNING | ||
| Blocked | TASK_INTERRUPTIBLE | S | キーボードや他のプロセスからの入力を待っている。 |
| TASK_UNINTERRUPTIBLE | D | ディスク入出力などの完了を待っている。割り込み不可。 | |
| __TASK_STOPPED, __TASK_TRACED | T | 一時的に停止しているか、デバッグの対象になっている。 | |
| TASK_DEAD | Z | 既に終了していて、終了処理の完了を待ってる。 |

図? プロセスの木構造

図? UIDの保存方法
include/linux/cred.h
30: struct group_info {
31: atomic_t usage;
32: int ngroups;
33: int nblocks;
34: gid_t small_block[NGROUPS_SMALL];
35: gid_t *blocks[0];
36: };
...
115: struct cred {
116: atomic_t usage;
117: uid_t uid; /* real UID of the task */
118: gid_t gid; /* real GID of the task */
119: uid_t suid; /* saved UID of the task */
120: gid_t sgid; /* saved GID of the task */
121: uid_t euid; /* effective UID of the task */
122: gid_t egid; /* effective GID of the task */
...
140: struct user_struct *user; /* real user ID subscription */
141: struct group_info *group_info; /* supplementary groups for euid/fsgid */
...
143: };
Unix には、set-uid のプログラムがある。ls -l で user の x の所が s になっ ている。
% ls -l /usr/bin | egrep '^...s'
...
-r-sr-xr-x 1 root wheel 70352 Jun 19 11:39 passwd
-r-sr-xr-x@ 1 root wheel 47296 Feb 24 2009 quota
...
-r-sr-xr-x@ 1 root wheel 48160 May 31 2008 su
-rwsr-xr-x@ 1 root wheel 149024 May 31 2008 top
...
%
このようなプログラムを実行すると、一時的にファイル所有者(この例では
root)の権限でプログラムが実行される。パスワードを変更したり、
ディスク・クォータを表示する時に、root の権限を使う。
include/linux/syscalls.h:
137:#define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(void)
kernel/timer.c:
1233: SYSCALL_DEFINE0(getpid)
1234: {
1235: return task_tgid_vnr(current);
1236: }
currentを引数にして task_tgid_vnr() という関数を呼ぶ。
include/linux/sched.h
1586: static inline pid_t task_tgid_vnr(struct task_struct *tsk)
1587: {
1588: return pid_vnr(task_tgid(tsk));
1589: }
引数で与えられた task_struct 構造体の tgid を返す。(実際にはもう少し複雑。)
kernel/timer.c
1244: SYSCALL_DEFINE0(getppid)
1245: {
1246: int pid;
1247:
1248: rcu_read_lock();
1249: pid = task_tgid_vnr(current->real_parent);
1250: rcu_read_unlock();
1251:
1252: return pid;
1253: }
currentのreal_parentを引数にして task_tgid_vnr() という関数を呼ぶ。
kernel/timer.c
1255: SYSCALL_DEFINE0(getuid)
1256: {
1257: /* Only we change this so SMP safe */
1258: return current_uid();
1259: }
current_uid() という関数(マクロ)を呼び出す。
include/linux/sched.h
305: #define current_cred_xxx(xxx) \
306: ({ \
307: current->cred->xxx; \
308: })
309:
310: #define current_uid() (current_cred_xxx(uid))
currentからcredを引き、その中の uid というフィールドを返す。
1: main() {
2: printf("pid=%d, ppid=%d\n",getpid(), getppid());
3: }
% ./a.out
pid=空欄A, ppid=空欄B
% ./a.out
pid=空欄C, ppid=空欄D
%
結果は、実行する度に異なる。結果として起こりえる例を1つ作りなさい。た
だし、ただし、PID としては、
1001,1002,1003,1004,1005,1006,1007,1008,1009,1010 の中から選びなさい。
また、短期間に連続してプログラムを実行するために、PID はオーバーフロー
しないものとする。
ヒント: current から出発する。 current_cred_xxx() マクロを使っても使わなくてもよい。