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. Signed-off-by: Josef Bacik --- 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 99caef43ff3c..88748be03505 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1185,10 +1185,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