From 3df7546fc03b8f004eee0b9e3256369f7d096685 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 16 Dec 2024 19:38:40 +0900 Subject: tomoyo: don't emit warning in tomoyo_write_control() syzbot is reporting too large allocation warning at tomoyo_write_control(), for one can write a very very long line without new line character. To fix this warning, I use __GFP_NOWARN rather than checking for KMALLOC_MAX_SIZE, for practically a valid line should be always shorter than 32KB where the "too small to fail" memory-allocation rule applies. One might try to write a valid line that is longer than 32KB, but such request will likely fail with -ENOMEM. Therefore, I feel that separately returning -EINVAL when a line is longer than KMALLOC_MAX_SIZE is redundant. There is no need to distinguish over-32KB and over-KMALLOC_MAX_SIZE. Reported-by: syzbot+7536f77535e5210a5c76@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=7536f77535e5210a5c76 Reported-by: Leo Stone Closes: https://lkml.kernel.org/r/20241216021459.178759-2-leocstone@gmail.com Signed-off-by: Tetsuo Handa --- security/tomoyo/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 5c7b059a332a..972664962e8f 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -2665,7 +2665,7 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, if (head->w.avail >= head->writebuf_size - 1) { const int len = head->writebuf_size * 2; - char *cp = kzalloc(len, GFP_NOFS); + char *cp = kzalloc(len, GFP_NOFS | __GFP_NOWARN); if (!cp) { error = -ENOMEM; -- cgit v1.2.3 From 0476fd4ff45261744da6bb2df2f8080571902bf0 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 17 Dec 2024 18:55:32 +0900 Subject: tomoyo: use realpath if symlink's pathname refers to procfs Fedora 41 has reached Linux 6.12 kernel with TOMOYO enabled. I observed that /usr/lib/systemd/systemd executes /usr/lib/systemd/systemd-executor by passing dirfd == 9 or dirfd == 16 upon execveat(). Commit ada1986d0797 ("tomoyo: fallback to realpath if symlink's pathname does not exist") used realpath only if symlink's pathname does not exist. But an out of tree patch suggested that it will be reasonable to always use realpath if symlink's pathname refers to proc filesystem. Therefore, this patch changes the pathname used for checking "file execute" and the domainname used after a successful execve() request. Before: /usr/lib/systemd/systemd file execute proc:/self/fd/16 exec.realpath="/usr/lib/systemd/systemd-executor" exec.argv[0]="/usr/lib/systemd/systemd-executor" file execute proc:/self/fd/9 exec.realpath="/usr/lib/systemd/systemd-executor" exec.argv[0]="/usr/lib/systemd/systemd-executor" /usr/lib/systemd/systemd proc:/self/fd/16 file execute /usr/sbin/auditd exec.realpath="/usr/sbin/auditd" exec.argv[0]="/usr/sbin/auditd" /usr/lib/systemd/systemd proc:/self/fd/16 /usr/sbin/auditd /usr/lib/systemd/systemd proc:/self/fd/9 file execute /usr/bin/systemctl exec.realpath="/usr/bin/systemctl" exec.argv[0]="/usr/bin/systemctl" /usr/lib/systemd/systemd proc:/self/fd/9 /usr/bin/systemctl After: /usr/lib/systemd/systemd file execute /usr/lib/systemd/systemd-executor exec.realpath="/usr/lib/systemd/systemd-executor" exec.argv[0]="/usr/lib/systemd/systemd-executor" /usr/lib/systemd/systemd /usr/lib/systemd/systemd-executor file execute /usr/bin/systemctl exec.realpath="/usr/bin/systemctl" exec.argv[0]="/usr/bin/systemctl" file execute /usr/sbin/auditd exec.realpath="/usr/sbin/auditd" exec.argv[0]="/usr/sbin/auditd" /usr/lib/systemd/systemd /usr/lib/systemd/systemd-executor /usr/bin/systemctl /usr/lib/systemd/systemd /usr/lib/systemd/systemd-executor /usr/sbin/auditd Signed-off-by: Tetsuo Handa --- security/tomoyo/domain.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index aed9e3ef2c9e..3a7b0874cf44 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -722,10 +722,17 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ee->bprm = bprm; ee->r.obj = &ee->obj; ee->obj.path1 = bprm->file->f_path; - /* Get symlink's pathname of program. */ + /* + * Get symlink's pathname of program, but fallback to realpath if + * symlink's pathname does not exist or symlink's pathname refers + * to proc filesystem (e.g. /dev/fd/ or /proc/self/fd/ ). + */ exename.name = tomoyo_realpath_nofollow(original_name); + if (exename.name && !strncmp(exename.name, "proc:/", 6)) { + kfree(exename.name); + exename.name = NULL; + } if (!exename.name) { - /* Fallback to realpath if symlink's pathname does not exist. */ exename.name = tomoyo_realpath_from_path(&bprm->file->f_path); if (!exename.name) goto out; -- cgit v1.2.3 From 08ae2487b202ff92b1c6393f18630895f39460bf Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 6 Jan 2025 21:25:00 +0900 Subject: tomoyo: automatically use patterns for several situations in learning mode The "file_pattern" keyword was used for automatically recording patternized pathnames when using the learning mode. This keyword was removed in TOMOYO 2.4 because it is impossible to predefine all possible pathname patterns. However, since the numeric part of proc:/$PID/ , pipe:[$INO] and socket:[$INO] has no meaning except $PID == 1, automatically replacing the numeric part with \$ pattern helps reducing frequency of restarting the learning mode due to hitting the quota. Since replacing one digit with \$ pattern requires enlarging string buffer, and several programs access only $PID == 1, replace only two or more digits with \$ pattern. Signed-off-by: Tetsuo Handa --- security/tomoyo/common.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'security') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 972664962e8f..d9fa69632147 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -2024,6 +2024,36 @@ static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) if (!buffer) return; snprintf(buffer, len - 1, "%s", cp); + if (*cp == 'f' && strchr(buffer, ':')) { + /* Automatically replace 2 or more digits with \$ pattern. */ + char *cp2; + + /* e.g. file read proc:/$PID/stat */ + cp = strstr(buffer, " proc:/"); + if (cp && simple_strtoul(cp + 7, &cp2, 10) >= 10 && *cp2 == '/') { + *(cp + 7) = '\\'; + *(cp + 8) = '$'; + memmove(cp + 9, cp2, strlen(cp2) + 1); + goto ok; + } + /* e.g. file ioctl pipe:[$INO] $CMD */ + cp = strstr(buffer, " pipe:["); + if (cp && simple_strtoul(cp + 7, &cp2, 10) >= 10 && *cp2 == ']') { + *(cp + 7) = '\\'; + *(cp + 8) = '$'; + memmove(cp + 9, cp2, strlen(cp2) + 1); + goto ok; + } + /* e.g. file ioctl socket:[$INO] $CMD */ + cp = strstr(buffer, " socket:["); + if (cp && simple_strtoul(cp + 9, &cp2, 10) >= 10 && *cp2 == ']') { + *(cp + 9) = '\\'; + *(cp + 10) = '$'; + memmove(cp + 11, cp2, strlen(cp2) + 1); + goto ok; + } + } +ok: if (realpath) tomoyo_addprintf(buffer, len, " exec.%s", realpath); if (argv0) -- cgit v1.2.3