システムコールを確認する

man whoami すると (1) と表示されるのでユーザコマンドであることがわかる。

% rpm -qif /usr/bin/whoami
Name        : coreutils                    Relocations: (not relocatable)
Version     : 5.96                              Vendor: (none)
Release     : 0vl1                          Build Date: 2006年06月13日 22時04分59秒
[省略]

whoami をインストールしたパッケージは coreutils だとわかる。そこでcoreutils-5.96.tar.bz2を入手した(ってどうしてここにいきなりこの tar を入手するのかがわからないんだけど、まあよい、先に進もう)。

展開すると src/whoami.c が見つかった。重要なのは 88行目と 89行目。

64 main (int argc, char **argv)
65 {
省略
88 uid = geteuid ();
89 pw = getpwuid (uid);
90  if (pw)
91    {
92      puts (pw->pw_name);
93      exit (EXIT_SUCCESS);
94    }
95  fprintf (stderr, _("%s: cannot find name for user ID %lu\n"),
96	   program_name, (unsigned long int) uid);
97  exit (EXIT_FAILURE);
98 }

重要なのは 88,89行目。man geteuid すると...

GETUID(2)           Linux Programmer's Manual           GETUID(2)

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 current process.

       geteuid() returns the effective user  ID  of  the  current
       process.

ERRORS
       These functions are always successful.

CONFORMING TO
       POSIX, 4.3BSD.

HISTORY
       In  Unix  V6 the getuid() call returned (euid << 8) + uid.
       Unix V7 introduced separate calls getuid() and  geteuid().

SEE ALSO
       setreuid(2), setuid(2)

Linux 0.99.11               1993-07-23                  GETUID(2)

ここでのポイントは3つ。

  • マニュアルが (2)なのでシステムコール
  • ヘッダファイルは unistd.h と sys/types.h
  • geteuid()関数は引数が不要で uid_t 型の値が戻る

システムコールとは何か

システムコールは、カーネルの一部なので、メモリ上のユーザプログラムとは違う場所に配置されていて、呼び出されるのを待っている。ユーザプログラムからはカーネルの番地がわからないので、CPU割り込み(ソフトウェア割り込み)をかけて番地を入手する。

ユーザプログラムで割り込み命令を発生させると、CPUはそのプログラムを中断して、割り込み処理プログラムを実行する。割り込み処理プログラムは、eaxレジスタの値によって分岐するプログラムを判断します。

Intelの場合は、include/asm-i386/unistd.hにシステムコールと関数名をひもづけしたファイルがある。

     1  #ifndef _ASM_I386_UNISTD_H_
     2  #define _ASM_I386_UNISTD_H_
     3
     4  /*
     5   * This file contains the system call numbers.
     6   */
省略
    11  #define __NR_read                 3
    12  #define __NR_write                4
    57  #define __NR_geteuid             49

これから read() システムコールの場合には eaxレジスタに 3 をセットし、write()システムコールの場合には eaxレジスタに 4 をセットすればいいことがわかる。

whoami.c にある geteuid()関数

whoami.c から geteuid()を実行するためには、eaxレジスタに49を設定する。