[PATCH 04/13] fcntl: use cred_ids_allow_sigio()
Josef Bacik
josef at toxicpanda.com
Sun Oct 18 17:31:46 UTC 2026
sigio_perm() has the four comparisons of kill_ok_by_cred(), and lets euid
0 signal anybody. Use the library.
The library compares credentials. F_SETOWN only copies the uid and the
euid of the caller into struct fown_struct, so keep a reference on its
credentials instead, as struct file does for whoever opened it. That makes
the sender of a SIGIO a credential like the sender of any other signal.
F_GETOWNER_UIDS goes on reporting uid 0 for a file whose owner was never
set.
The credentials now stay around until the owner is set again or the file
is released. Clearing the owner leaves them alone, as it left the two ids
alone, so that F_GETOWNER_UIDS goes on reporting them. Who may be
signalled does not change.
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef at toxicpanda.com>
---
fs/fcntl.c | 19 ++++++++++---------
include/linux/fs.h | 4 ++--
security/landlock/fs.h | 3 +--
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 9b71bc9d71d1..07fe32330bec 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -120,6 +120,7 @@ void file_f_owner_release(struct file *file)
f_owner = file_f_owner(file);
if (f_owner) {
put_pid(f_owner->pid);
+ put_cred(f_owner->cred);
kfree(f_owner);
}
}
@@ -140,10 +141,9 @@ void __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
f_owner->pid_type = type;
if (pid) {
- const struct cred *cred = current_cred();
security_file_set_fowner(filp);
- f_owner->uid = cred->uid;
- f_owner->euid = cred->euid;
+ put_cred(f_owner->cred);
+ f_owner->cred = get_current_cred();
}
}
write_unlock_irq(&f_owner->lock);
@@ -315,9 +315,12 @@ static int f_getowner_uids(struct file *filp, unsigned long arg)
f_owner = file_f_owner(filp);
if (f_owner) {
+ const struct cred *cred;
+
read_lock_irq(&f_owner->lock);
- src[0] = from_kuid(user_ns, f_owner->uid);
- src[1] = from_kuid(user_ns, f_owner->euid);
+ cred = f_owner->cred;
+ src[0] = from_kuid(user_ns, cred ? cred->uid : GLOBAL_ROOT_UID);
+ src[1] = from_kuid(user_ns, cred ? cred->euid : GLOBAL_ROOT_UID);
read_unlock_irq(&f_owner->lock);
}
@@ -847,10 +850,8 @@ static inline int sigio_perm(struct task_struct *p,
rcu_read_lock();
cred = __task_cred(p);
- ret = ((uid_eq(fown->euid, GLOBAL_ROOT_UID) ||
- uid_eq(fown->euid, cred->suid) || uid_eq(fown->euid, cred->uid) ||
- uid_eq(fown->uid, cred->suid) || uid_eq(fown->uid, cred->uid)) &&
- !security_file_send_sigiotask(p, fown, sig));
+ ret = cred_ids_allow_sigio(fown->cred, cred) &&
+ !security_file_send_sigiotask(p, fown, sig);
rcu_read_unlock();
return ret;
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 83d41d9f1130..51aff96e6aa7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1183,10 +1183,10 @@ static inline unsigned imajor(const struct inode *inode)
struct fown_struct {
struct file *file; /* backpointer for security modules */
- rwlock_t lock; /* protects pid, uid, euid fields */
+ rwlock_t lock; /* protects pid, cred fields */
struct pid *pid; /* pid or -pgrp where SIGIO should be sent */
enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */
- kuid_t uid, euid; /* uid/euid of process setting the owner */
+ const struct cred *cred; /* of the process setting the owner */
int signum; /* posix.1b rt signal to be delivered on IO */
};
diff --git a/security/landlock/fs.h b/security/landlock/fs.h
index 50b3ddb8ac1c..d3aa84820594 100644
--- a/security/landlock/fs.h
+++ b/security/landlock/fs.h
@@ -84,8 +84,7 @@ struct landlock_file_security {
* @fown_subject: Landlock credential of the task that set the PID that
* may receive a signal e.g., SIGURG when writing MSG_OOB to the
* related socket. This pointer is protected by the related
- * file->f_owner->lock, as for fown_struct's members: pid, uid, and
- * euid.
+ * file->f_owner->lock, as for fown_struct's members: pid and cred.
*/
struct landlock_cred_security fown_subject;
/**
--
2.55.0
More information about the Linux-security-module-archive
mailing list