Linuxカーネルのソースコードを読む(その5:umaskのデフォルト値を調べてみた)

umaskのデフォルト値について,カーネルソースコードから /etc/の下の設定ファイルまで全部調べました.

作業メモを公開します.

umaskのデフォルト値

シェル(bash)から見ると, umask の初期値はディストリビューションによって異なります.

ディストリビューション umaskの値(8進数) (symbolic表現)
redhat/centos 0002 u=rwx,g=rwx,o=rx
debian 0022 u=rwx,g=rx,o=rx

そもそも umask って何?

umaskは新規ファイルや新規ディレクトリの作成時のパーミッションを決める変数(マスク値)ですが,ここではその実装を調べます.

結論から言うとumaskの実体はシステムコールです.Linuxカーネル version 6.2.10 の場合,umaskは kernel/sys.c の1866行目で実装されています.

https://elixir.bootlin.com/linux/v6.2.10/source/kernel/sys.c#L1866

SYSCALL_DEFINE1(umask, int, mask)
{
	mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
	return mask;
}

大雑把に言うと,プロセス毎に割り当てられたメモリ領域があって,そこにumaskという変数が割り当てられています.ファイルやディレクトリを新規作成する場合は適宜 umaskの変数の値が参照されます.

umaskの値を変更するには,ユーザー空間からは

  • umask コマンド(bashの場合は build-in)
  • libcの umask関数

を使いますが,これらも内部では上記のシステムコールを実行し,カーネル内部の値を読み書きしています.

umaskのデフォルト値はどこで設定されている?

カーネルソースコードを調べて, fs->umask の値を設定している箇所を探します.

と言っても grepコマンドを使えば数秒で見つかります.

$ cd linux-6.2.10/kernel/
$ grep "fs->umask" . -r
./umh.c:        current->fs->umask = 0022;
./sys.c:        mask = xchg(&current->fs->umask, mask & S_IRWXUGO);

該当箇所は2箇所だけです.umh.cとsys.c の2つです.

後者sys.cは上記のumaskシステムコールの実装ですから,初期値を設定しているのは前者の umh.c です.

umh.c を見てみます.冒頭のコメント文に以下の記載があります

/*
 * umh - the kernel usermode helper
 */

umhはUser Mode Helper の略だそうです.ソースを眺めると,ユーザー空間のプロセスを生成する際のヘルパ関数を実装していることが解ります.

fs->umask を初期化しているのは umh.c の 83 行目でした.

https://elixir.bootlin.com/linux/v6.2.10/source/kernel/umh.c#L83

        /*
         * Initial kernel threads share ther FS with init, in order to
         * get the init root directory. But we've now created a new
         * thread that is going to execve a user process and has its own
         * 'struct fs_struct'. Reset umask to the default.
         */
        current->fs->umask = 0022;

ということで,カーネルではumaskの初期値を0022に設定していました.

centOSは umaskの値を再設定している

ここまでをまとめると

  • カーネルはumaskを 0022 に設定している
  • debianbash上では umask は 0022 のまま
  • centOSbash上では umask が 0002 に変更されている

ということになります

centOS はどこかで umaskの値を変更しているようです

centOSの /etc の下を覗いてみる

centOSbash を起動する際に umask コマンドを実行している可能性があります

/etc の下のファイルを片っ端から grep で見てみます

$ grep umask /etc -r

以下のファイルで umask 002 を実行していました

  • /etc/bashrc
  • /etc/profile

/etc/profileの該当箇所

# By default, we want umask to get set. This sets it for login shell
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
    umask 002
else
    umask 022
fi

/etc/bashrcの該当箇所

    # By default, we want umask to get set. This sets it for non-login shell.
    # Current threshold for system reserved uid/gids is 200
    # You could check uidgid reservation validity in
    # /usr/share/doc/setup-*/uidgid file
    if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
       umask 002
    else
       umask 022
    fi

コメントに書いてあるように uid/gid が200以上の場合は umaskが002,それ以外の場合は umask が022になる,ということです

debianでも確認してみる

一応 debian でも/etcの下を覗いてみます

$ grep umask  /etc -r 

/etc/login.defs で UMASKの記述が見つかりました.引用するとこんな感じ

#
# Login configuration initializations:
#
#       ERASECHAR       Terminal ERASE character ('\010' = backspace).
#       KILLCHAR        Terminal KILL character ('\025' = CTRL/U).
#       UMASK           Default "umask" value.
#
# The ERASECHAR and KILLCHAR are used only on System V machines.
# 
# UMASK is the default umask value for pam_umask and is used by
# useradd and newusers to set the mode of the new home directories.
# 022 is the "historical" value in Debian for UMASK
# 027, or even 077, could be considered better for privacy
# There is no One True Answer here : each sysadmin must make up his/her
# mind.
#
# If USERGROUPS_ENAB is set to "yes", that will modify this UMASK default value
# for private user groups, i. e. the uid is the same as gid, and username is
# the same as the primary group name: for these, the user permissions will be
# used as group permissions, e. g. 022 will become 002.
#
# Prefix these values with "0" to get octal, "0x" to get hexadecimal.
#
ERASECHAR       0177
KILLCHAR        025
UMASK           022

書いてあることは

  • /etc/login.defs で UMASKの値が指定できる
  • UMASKを参照するのは以下のモジュール・コマンド
    • pam_umask :ログイン時に実行するモジュール.
    • useradd/newusersコマンド:新規ユーザを作成するコマンド.ユーザ用のホームディレクトリを作成する際のパーミッションがlogin.defs のUMASKの値で決定されている模様.

さらに

  • 0022 は "historical" な値
  • 更に USERGROUPS_ENAB をyesに設定すると0022が0002になる場合がある(詳細は原文を読んでください)

とも書いてあります

ただし,手元のdebianは pam_umask を使用しておらず,/etc/login.defs の設定は利用されていませんでした.

まとめ

  • umaskはシステムコール
  • umaskの初期値はカーネルで 0022 に設定されている
  • centOSは/etc/bashrcと/etc/profileで UIDが200以上の場合はumaskを 0002 に変更している
  • pam_umask を使うと /etc/login.defs の設定に従ってumaskの値を変更できそう(未確認)