給与明細を見ていて、なんか健康保険料がやたら高くないか……?と気になりました。要因の一つは見た目の問題です。今の会社はこれまで勤めてきた会社と給与制度が違ってボーナスがありません(年俸の12分の1 = 月給)から、同じ年収でもボーナスがある場合に比べて月給が高く見えます。でもこれは見た目だけの問題で気にしなくて良いです。
他の可能性があるとすると、所属する健康保険組合が全国健康保険協会(協会けんぽ)に変わったことです。協会けんぽ(令和6年3月〜、東京)の料率を調べると、
でした。ちなみに大手企業の健保は料率8〜9%くらいが多いらしいので、それと比べたら高いです。私のような40歳以降のおじさんだと、介護保険料1.6%が上乗せされるのでさらに高くなります。辛い。
会社の方針で協会けんぽから「VCスタートアップ健康保険組合」に切り替えるそうで、保険料率が下がるかもと案内がありました。うお〜良いじゃないかと思って調べてみると、
でした。若い人は確かに安くなります。ただ残念ながら40歳以降のおじさんの場合はあまり変わりません。介護保険が協会けんぽの1.6%より割高の2.18%に設定されているためです。スタートアップは若者が圧倒的に多いと思うので、若者が得する設計にするのは当然ですね。仕方ないね……。
この記事にコメントする
目次: 車
先週、ディーラーに半年点検に持っていったら毎度おなじみのバッテリーがイカレていて、日帰りの予定が1週間の入院と相成りました。バッテリー液の比重が1.2くらいになっていたみたいです(本来の比重は1.28)。今度こそバッテリー交換を提案されるかな?と思いきや「充電してみます!」とのことでした。
今回も何とかバッテリー君は復活してくれたようで良かったです。次はもうダメそうな雰囲気を感じましたけど……これまでのバッテリーに比べたら割と長期間耐えているのでまあ良いでしょう。
バッテリーが早々にイカレてしまう原因は、社外セキュリティの待機電力がでかいことと、あまりにも乗らなさすぎなことで、大阪に住んでいた10年以上前から原因は明確なんですが、ライフスタイルはそんな劇的に変えられないのです。
この記事にコメントする
目次: Linux
前回はsystemd --userの/proc/[pid]/ioが読めない件を紹介しました。今回はなぜ読めないのか、Linuxカーネルのコードを見て謎を追います。
// fs/proc/base.c
/*
* Thread groups
*/
static const struct pid_entry tgid_base_stuff[] = {
DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations),
DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
//...
#ifdef CONFIG_TASK_IO_ACCOUNTING
ONE("io", S_IRUSR, proc_tgid_io_accounting), //★★★★
#endif
int proc_tgid_io_accounting(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
return do_io_accounting(task, m, 1); //★★★★
}
// fs/proc/base.c
#ifdef CONFIG_TASK_IO_ACCOUNTING
static int do_io_accounting(struct task_struct *task, struct seq_file *m, int whole)
{
struct task_io_accounting acct;
int result;
result = down_read_killable(&task->signal->exec_update_lock);
if (result)
return result;
if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { //★★これ★★
result = -EACCES;
goto out_unlock;
}
if (whole) {
struct signal_struct *sig = task->signal;
struct task_struct *t;
unsigned int seq = 1;
unsigned long flags;
rcu_read_lock();
do {
seq++; /* 2 on the 1st/lockless path, otherwise odd */
flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq);
acct = sig->ioac;
__for_each_thread(sig, t)
task_io_accounting_add(&acct, &t->ioac);
} while (need_seqretry(&sig->stats_lock, seq));
done_seqretry_irqrestore(&sig->stats_lock, seq, flags);
rcu_read_unlock();
} else {
acct = task->ioac;
}
seq_printf(m,
"rchar: %llu\n"
"wchar: %llu\n"
"syscr: %llu\n"
"syscw: %llu\n"
"read_bytes: %llu\n"
"write_bytes: %llu\n"
"cancelled_write_bytes: %llu\n",
(unsigned long long)acct.rchar,
(unsigned long long)acct.wchar,
(unsigned long long)acct.syscr,
(unsigned long long)acct.syscw,
(unsigned long long)acct.read_bytes,
(unsigned long long)acct.write_bytes,
(unsigned long long)acct.cancelled_write_bytes);
result = 0;
out_unlock:
up_read(&task->signal->exec_update_lock);
return result;
}
// kernel/ptrace.c
bool ptrace_may_access(struct task_struct *task, unsigned int mode)
{
int err;
task_lock(task);
err = __ptrace_may_access(task, mode); //★★これ★★
task_unlock(task);
return !err;
}
/* Returns 0 on success, -errno on denial. */
static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
{
const struct cred *cred = current_cred(), *tcred;
struct mm_struct *mm;
kuid_t caller_uid;
kgid_t caller_gid;
if (!(mode & PTRACE_MODE_FSCREDS) == !(mode & PTRACE_MODE_REALCREDS)) {
WARN(1, "denying ptrace access check without PTRACE_MODE_*CREDS\n");
return -EPERM;
}
/* May we inspect the given task?
* This check is used both for attaching with ptrace
* and for allowing access to sensitive information in /proc.
*
* ptrace_attach denies several cases that /proc allows
* because setting up the necessary parent/child relationship
* or halting the specified task is impossible.
*/
/* Don't let security modules deny introspection */
if (same_thread_group(task, current))
return 0;
rcu_read_lock();
if (mode & PTRACE_MODE_FSCREDS) {
caller_uid = cred->fsuid;
caller_gid = cred->fsgid;
} else {
/*
* Using the euid would make more sense here, but something
* in userland might rely on the old behavior, and this
* shouldn't be a security problem since
* PTRACE_MODE_REALCREDS implies that the caller explicitly
* used a syscall that requests access to another process
* (and not a filesystem syscall to procfs).
*/
caller_uid = cred->uid;
caller_gid = cred->gid;
}
tcred = __task_cred(task);
if (uid_eq(caller_uid, tcred->euid) &&
uid_eq(caller_uid, tcred->suid) &&
uid_eq(caller_uid, tcred->uid) &&
gid_eq(caller_gid, tcred->egid) &&
gid_eq(caller_gid, tcred->sgid) &&
gid_eq(caller_gid, tcred->gid))
goto ok;
if (ptrace_has_cap(tcred->user_ns, mode))
goto ok;
rcu_read_unlock();
return -EPERM;
ok:
rcu_read_unlock();
/*
* If a task drops privileges and becomes nondumpable (through a syscall
* like setresuid()) while we are trying to access it, we must ensure
* that the dumpability is read after the credentials; otherwise,
* we may be able to attach to a task that we shouldn't be able to
* attach to (as if the task had dropped privileges without becoming
* nondumpable).
* Pairs with a write barrier in commit_creds().
*/
smp_rmb();
mm = task->mm;
if (mm &&
((get_dumpable(mm) != SUID_DUMP_USER) &&
!ptrace_has_cap(mm->user_ns, mode)))
return -EPERM;
return security_ptrace_access_check(task, mode); //★★これ★★
}
//security/security.c
int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
return call_int_hook(ptrace_access_check, child, mode);
}
// include/linux/ptrace.h
//★★modeに指定されているPTRACE_MODE_READ_FSCREDS = MODE_READ | MODE_FSCREDSのこと
#define PTRACE_MODE_READ 0x01
#define PTRACE_MODE_ATTACH 0x02
#define PTRACE_MODE_NOAUDIT 0x04
#define PTRACE_MODE_FSCREDS 0x08
#define PTRACE_MODE_REALCREDS 0x10
/* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */
#define PTRACE_MODE_READ_FSCREDS (PTRACE_MODE_READ | PTRACE_MODE_FSCREDS)
#define PTRACE_MODE_READ_REALCREDS (PTRACE_MODE_READ | PTRACE_MODE_REALCREDS)
#define PTRACE_MODE_ATTACH_FSCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS)
#define PTRACE_MODE_ATTACH_REALCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS)
まずはここまでです。それでも結構長いですね。呼び出しの順序はこんな感じです。
proc_tid_io_accounting()
do_io_acconting()
ptrace_may_access()
security_ptrace_access_check()
call_int_hook(ptrace_access_check)
最後のcall_int_hook()の後はセキュリティ機能(SELinuxとか)の有無によって呼び出される関数が変わるようですが、一番大本のコンフィグCONFIG_SECURITYが有効になっていると、ケーパビリティのチェックが実行されます。
// include/linux/capability.h
/*
* Check if "a" is a subset of "set".
* return true if ALL of the capabilities in "a" are also in "set"
* cap_issubset(0101, 1111) will return true
* return false if ANY of the capabilities in "a" are not in "set"
* cap_issubset(1111, 0101) will return false
*/
static inline bool cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
return !(a.val & ~set.val);
// security/commoncap.c
int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
int ret = 0;
const struct cred *cred, *child_cred;
const kernel_cap_t *caller_caps;
rcu_read_lock();
cred = current_cred();
child_cred = __task_cred(child);
if (mode & PTRACE_MODE_FSCREDS)
caller_caps = &cred->cap_effective; //★こちらを通る★
else
caller_caps = &cred->cap_permitted;
if (cred->user_ns == child_cred->user_ns &&
cap_issubset(child_cred->cap_permitted, *caller_caps)) //★★★★この条件を満たさない
goto out;
if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE))
goto out;
ret = -EPERM; //★★★★EPERMエラーが返される
out:
rcu_read_unlock();
return ret;
}
相手側(child, systemd --userのプロセス)のeffectiveなケーパビリティが、自分側(child, ユーザーが起動したcatとか)のケーパビリティのサブセットかどうか?を見る部分でエラーになります。
プロセスのケーパビリティを確認するには/proc/[pid]/statusを見ます。effectiveなケーパビリティはCapEffに表示されます。通常のプロセスは0ですが、systemd --userはCapEffに0ではない値が入っています。
$ cat /proc/1381/status | grep Cap CapInh: 0000000800000000 CapPrm: 0000000800000000 CapEff: 0000000800000000 CapBnd: 000001ffffffffff CapAmb: 0000000000000000
ケーパビリティを見やすく表示してくれるツールgetpcaps(Debianパッケージ名はlibcap2-bin)で見ると、
$ sudo getpcaps 1381 1381: cap_wake_alarm=eip
相手側のsystemd --userはcap_wake_alarmケーパビリティを持っていて、catなどは持っていません。従ってsystemd --userのケーパビリティはcatのケーパビリティのサブセット「ではない」です。先ほど紹介したコードにあったif文の条件を満たせずにEPERMが返されます。
この記事にコメントする
目次: Linux
LinuxのI/O統計情報(/proc/[pid]/io)はユーザーが自分と一致するプロセスなら基本的に読めるはずですが、1つだけ読めない変なプロセスがいることに気づきました。
$ LANG=C ls -l /proc/*/io | grep $USER | cut -d ' ' -f 9 | xargs cat > /dev/null
cat: /proc/1381/io: 許可がありません
cat: /proc/1744137/io: そのようなファイルやディレクトリはありません
cat: /proc/1744138/io: そのようなファイルやディレクトリはありません
cat: /proc/1744139/io: そのようなファイルやディレクトリはありません
$ ps 1381
PID TTY STAT TIME COMMAND
1381 ? Ss 0:00 /usr/lib/systemd/systemd --user
$ ps u 1381
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
katsuhi+ 1381 0.0 0.0 21512 11360 ? Ss 2024 0:00 /usr/lib/syst
$ /usr/lib/systemd/systemd --version
systemd 257 (257~rc3-1)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +IPE +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBCRYPTSETUP_PLUGINS +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK +BTF -XKBCOMMON -UTMP +SYSVINIT +LIBARCHIVE
プロセスID 1744137〜1744139は、/proc/[pid]/ioの列挙に使ったls, grep, cutが、xargs catを実行するときに終了しているためで、気にしなくて良いはずです。しかしプロセスID 1381のsystemd --userは何かおかしいです。自分のプロセスのはずなのに読み出せなくてEPERMが返ります。
不思議ですね。ファイルを読み出せるかどうかチェックするaccess()を使って調べましょう。
#include <stdio.h>
#include <unistd.h>
void usage(int argc, char *argv[])
{
printf("usage:\n"
" %s filepath [filepath2 ...]\n", argv[0]);
}
const char *is_ok(int v)
{
if (v == 0) {
return "ok";
} else {
return "ng";
}
}
int main(int argc, char *argv[])
{
if (argc < 2) {
usage(argc, argv);
return 1;
}
for (int i = 1; i < argc; i++) {
const char *path = argv[i];
int fok, rok, wok, xok;
fok = access(path, F_OK);
rok = access(path, R_OK);
wok = access(path, W_OK);
xok = access(path, X_OK);
printf("%20s: f:%s r:%s w:%s x:%s\n",
path, is_ok(fok), is_ok(rok), is_ok(wok), is_ok(xok));
}
return 0;
}
$ gcc -O2 main.c -o access_check
$ ./access_check /proc/1381/io
/proc/1381/io: f:ok r:ok w:ng x:ng
$ cat /proc/1381/io
cat: /proc/1381/io: 許可がありません
ファイルが存在し(f:ok)、読み出しが可能である(r:ok)と判定されますが、catで読もうとするとやはりEPERMが返されます。なんだこれは……?
この記事にコメントする
| < | 2025 | > | ||||
| << | < | 03 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
| - | - | - | - | - | - | 1 |
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 | - | - | - | - | - |
wiki
Linux JM
Java API
2002年
2003年
2004年
2005年
2006年
2007年
2008年
2009年
2010年
2011年
2012年
2013年
2014年
2015年
2016年
2017年
2018年
2019年
2020年
2021年
2022年
2023年
2024年
2025年
過去日記について
アクセス統計
サーバ一覧
サイトの情報合計:
本日: