Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/kernel.h>
0003 #include <linux/syscalls.h>
0004 #include <linux/fdtable.h>
0005 #include <linux/string.h>
0006 #include <linux/random.h>
0007 #include <linux/module.h>
0008 #include <linux/ptrace.h>
0009 #include <linux/init.h>
0010 #include <linux/errno.h>
0011 #include <linux/cache.h>
0012 #include <linux/bug.h>
0013 #include <linux/err.h>
0014 #include <linux/kcmp.h>
0015 #include <linux/capability.h>
0016 #include <linux/list.h>
0017 #include <linux/eventpoll.h>
0018 #include <linux/file.h>
0019 
0020 #include <asm/unistd.h>
0021 
0022 /*
0023  * We don't expose the real in-memory order of objects for security reasons.
0024  * But still the comparison results should be suitable for sorting. So we
0025  * obfuscate kernel pointers values and compare the production instead.
0026  *
0027  * The obfuscation is done in two steps. First we xor the kernel pointer with
0028  * a random value, which puts pointer into a new position in a reordered space.
0029  * Secondly we multiply the xor production with a large odd random number to
0030  * permute its bits even more (the odd multiplier guarantees that the product
0031  * is unique ever after the high bits are truncated, since any odd number is
0032  * relative prime to 2^n).
0033  *
0034  * Note also that the obfuscation itself is invisible to userspace and if needed
0035  * it can be changed to an alternate scheme.
0036  */
0037 static unsigned long cookies[KCMP_TYPES][2] __read_mostly;
0038 
0039 static long kptr_obfuscate(long v, int type)
0040 {
0041     return (v ^ cookies[type][0]) * cookies[type][1];
0042 }
0043 
0044 /*
0045  * 0 - equal, i.e. v1 = v2
0046  * 1 - less than, i.e. v1 < v2
0047  * 2 - greater than, i.e. v1 > v2
0048  * 3 - not equal but ordering unavailable (reserved for future)
0049  */
0050 static int kcmp_ptr(void *v1, void *v2, enum kcmp_type type)
0051 {
0052     long t1, t2;
0053 
0054     t1 = kptr_obfuscate((long)v1, type);
0055     t2 = kptr_obfuscate((long)v2, type);
0056 
0057     return (t1 < t2) | ((t1 > t2) << 1);
0058 }
0059 
0060 /* The caller must have pinned the task */
0061 static struct file *
0062 get_file_raw_ptr(struct task_struct *task, unsigned int idx)
0063 {
0064     struct file *file;
0065 
0066     rcu_read_lock();
0067     file = task_lookup_fd_rcu(task, idx);
0068     rcu_read_unlock();
0069 
0070     return file;
0071 }
0072 
0073 static void kcmp_unlock(struct rw_semaphore *l1, struct rw_semaphore *l2)
0074 {
0075     if (likely(l2 != l1))
0076         up_read(l2);
0077     up_read(l1);
0078 }
0079 
0080 static int kcmp_lock(struct rw_semaphore *l1, struct rw_semaphore *l2)
0081 {
0082     int err;
0083 
0084     if (l2 > l1)
0085         swap(l1, l2);
0086 
0087     err = down_read_killable(l1);
0088     if (!err && likely(l1 != l2)) {
0089         err = down_read_killable_nested(l2, SINGLE_DEPTH_NESTING);
0090         if (err)
0091             up_read(l1);
0092     }
0093 
0094     return err;
0095 }
0096 
0097 #ifdef CONFIG_EPOLL
0098 static int kcmp_epoll_target(struct task_struct *task1,
0099                  struct task_struct *task2,
0100                  unsigned long idx1,
0101                  struct kcmp_epoll_slot __user *uslot)
0102 {
0103     struct file *filp, *filp_epoll, *filp_tgt;
0104     struct kcmp_epoll_slot slot;
0105 
0106     if (copy_from_user(&slot, uslot, sizeof(slot)))
0107         return -EFAULT;
0108 
0109     filp = get_file_raw_ptr(task1, idx1);
0110     if (!filp)
0111         return -EBADF;
0112 
0113     filp_epoll = fget_task(task2, slot.efd);
0114     if (!filp_epoll)
0115         return -EBADF;
0116 
0117     filp_tgt = get_epoll_tfile_raw_ptr(filp_epoll, slot.tfd, slot.toff);
0118     fput(filp_epoll);
0119 
0120     if (IS_ERR(filp_tgt))
0121         return PTR_ERR(filp_tgt);
0122 
0123     return kcmp_ptr(filp, filp_tgt, KCMP_FILE);
0124 }
0125 #else
0126 static int kcmp_epoll_target(struct task_struct *task1,
0127                  struct task_struct *task2,
0128                  unsigned long idx1,
0129                  struct kcmp_epoll_slot __user *uslot)
0130 {
0131     return -EOPNOTSUPP;
0132 }
0133 #endif
0134 
0135 SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type,
0136         unsigned long, idx1, unsigned long, idx2)
0137 {
0138     struct task_struct *task1, *task2;
0139     int ret;
0140 
0141     rcu_read_lock();
0142 
0143     /*
0144      * Tasks are looked up in caller's PID namespace only.
0145      */
0146     task1 = find_task_by_vpid(pid1);
0147     task2 = find_task_by_vpid(pid2);
0148     if (!task1 || !task2)
0149         goto err_no_task;
0150 
0151     get_task_struct(task1);
0152     get_task_struct(task2);
0153 
0154     rcu_read_unlock();
0155 
0156     /*
0157      * One should have enough rights to inspect task details.
0158      */
0159     ret = kcmp_lock(&task1->signal->exec_update_lock,
0160             &task2->signal->exec_update_lock);
0161     if (ret)
0162         goto err;
0163     if (!ptrace_may_access(task1, PTRACE_MODE_READ_REALCREDS) ||
0164         !ptrace_may_access(task2, PTRACE_MODE_READ_REALCREDS)) {
0165         ret = -EPERM;
0166         goto err_unlock;
0167     }
0168 
0169     switch (type) {
0170     case KCMP_FILE: {
0171         struct file *filp1, *filp2;
0172 
0173         filp1 = get_file_raw_ptr(task1, idx1);
0174         filp2 = get_file_raw_ptr(task2, idx2);
0175 
0176         if (filp1 && filp2)
0177             ret = kcmp_ptr(filp1, filp2, KCMP_FILE);
0178         else
0179             ret = -EBADF;
0180         break;
0181     }
0182     case KCMP_VM:
0183         ret = kcmp_ptr(task1->mm, task2->mm, KCMP_VM);
0184         break;
0185     case KCMP_FILES:
0186         ret = kcmp_ptr(task1->files, task2->files, KCMP_FILES);
0187         break;
0188     case KCMP_FS:
0189         ret = kcmp_ptr(task1->fs, task2->fs, KCMP_FS);
0190         break;
0191     case KCMP_SIGHAND:
0192         ret = kcmp_ptr(task1->sighand, task2->sighand, KCMP_SIGHAND);
0193         break;
0194     case KCMP_IO:
0195         ret = kcmp_ptr(task1->io_context, task2->io_context, KCMP_IO);
0196         break;
0197     case KCMP_SYSVSEM:
0198 #ifdef CONFIG_SYSVIPC
0199         ret = kcmp_ptr(task1->sysvsem.undo_list,
0200                    task2->sysvsem.undo_list,
0201                    KCMP_SYSVSEM);
0202 #else
0203         ret = -EOPNOTSUPP;
0204 #endif
0205         break;
0206     case KCMP_EPOLL_TFD:
0207         ret = kcmp_epoll_target(task1, task2, idx1, (void *)idx2);
0208         break;
0209     default:
0210         ret = -EINVAL;
0211         break;
0212     }
0213 
0214 err_unlock:
0215     kcmp_unlock(&task1->signal->exec_update_lock,
0216             &task2->signal->exec_update_lock);
0217 err:
0218     put_task_struct(task1);
0219     put_task_struct(task2);
0220 
0221     return ret;
0222 
0223 err_no_task:
0224     rcu_read_unlock();
0225     return -ESRCH;
0226 }
0227 
0228 static __init int kcmp_cookies_init(void)
0229 {
0230     int i;
0231 
0232     get_random_bytes(cookies, sizeof(cookies));
0233 
0234     for (i = 0; i < KCMP_TYPES; i++)
0235         cookies[i][1] |= (~(~0UL >>  1) | 1);
0236 
0237     return 0;
0238 }
0239 arch_initcall(kcmp_cookies_init);