void proc_exec_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE]; const struct cred *cred; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_EXEC; ev->event_data.exec.process_pid = task->pid; ev->event_data.exec.process_tgid = task->tgid; rcu_read_lock(); cred = __task_cred(task); ev->event_data.exec.process_euid = cred->euid; ev->event_data.exec.process_egid = cred->egid; rcu_read_unlock(); proc_get_exe(task, ev->event_data.exec.exe); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
void tasks_test_saved(void) { struct task_struct *p; struct cred *cred =NULL; struct mm_struct *mm; unsigned long vsize = 0, vrss = 0; printk("\nThe following trace is a kernel tasks test and not a bug!\n"); printk("USER\tPID\tVSIZE\tRSS\tSTATE\tNAME\n"); write_lock_irq(&tasklist_lock); for_each_process(p) { cred = (struct cred *)get_cred((struct cred *) __task_cred(p)); vsize = 0; vrss = 0; mm = get_task_mm(p); if (mm) { tasks_mem_get(mm, &vsize, &vrss); } printk("%d\t%d\t%ld\t%ld\t%s\t%s\n", cred->uid, task_pid_nr(p), vsize, vrss, get_task_state(p), p->comm); } write_unlock_irq(&tasklist_lock); }
static int sec_nfc_open(struct inode *inode, struct file *file) { struct sec_nfc_info *info = container_of(file->private_data, struct sec_nfc_info, miscdev); int ret = 0; uid_t uid; // Security dev_dbg(info->dev, "%s: info : %p" , __func__, info); // Check process uid = __task_cred(current)->uid; if (g_secnfc_uid != uid) { dev_err(info->dev, "%s: Un-authorized process. No access to device\n", __func__); return -EPERM; } // End of Security mutex_lock(&info->mutex); if (info->state != SEC_NFC_ST_OFF) { dev_err(info->dev, "sec_nfc is busy\n"); ret = -EBUSY; goto out; } #ifdef CONFIG_SEC_NFC_I2C mutex_lock(&info->read_mutex); info->read_irq = SEC_NFC_NONE; mutex_unlock(&info->read_mutex); ret = sec_nfc_set_state(info, SEC_NFC_ST_NORM); #endif out: mutex_unlock(&info->mutex); return ret; }
int set_task_ioprio(struct task_struct *task, int ioprio) { int err; struct io_context *ioc; const struct cred *cred = current_cred(), *tcred; rcu_read_lock(); tcred = __task_cred(task); if (!uid_eq(tcred->uid, cred->euid) && !uid_eq(tcred->uid, cred->uid) && !capable(CAP_SYS_NICE)) { rcu_read_unlock(); return -EPERM; } rcu_read_unlock(); err = security_task_setioprio(task, ioprio); if (err) return err; ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE); if (ioc) { ioc->ioprio = ioprio; put_io_context(ioc); } return err; }
/** * aa_task_setrlimit - test permission to set an rlimit * @profile - profile confining the task (NOT NULL) * @task - task the resource is being set on * @resource - the resource being set * @new_rlim - the new resource limit (NOT NULL) * * Control raising the processes hard limit. * * Returns: 0 or error code if setting resource failed */ int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, unsigned int resource, struct rlimit *new_rlim) { struct aa_profile *task_profile; int error = 0; rcu_read_lock(); task_profile = aa_get_profile(aa_cred_profile(__task_cred(task))); rcu_read_unlock(); /* TODO: extend resource control to handle other (non current) * profiles. AppArmor rules currently have the implicit assumption * that the task is setting the resource of a task confined with * the same profile or that the task setting the resource of another * task has CAP_SYS_RESOURCE. */ if ((profile != task_profile && aa_capable(profile, CAP_SYS_RESOURCE, 1)) || (profile->rlimits.mask & (1 << resource) && new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) error = -EACCES; aa_put_profile(task_profile); return audit_resource(profile, resource, new_rlim->rlim_max, error); }
asmlinkage long my_open(const char __user *filename, int flags, umode_t mode) { char *fname = 0; struct task_struct *cur = 0; // Get the filename fname = getname(filename); if (!fname) { printk("[ACE - ERROR] - Could not get the name of the file!\n"); return (-ENOENT); } // Get the current task cur = get_current_task(); if (!cur) { printk("[ACE - ERROR] - Could not get the current task!\n"); return (-ENOENT); } printk("[ACE - INFO] Checking file '%s'...\n", fname); if (policy_check(fname, __task_cred(cur)->euid) == 0) return sys_open(filename, flags, mode); else return (-EACCES); }
/* * Assumes either tasklist_lock read locked with appropriate task_lock held, or * tasklist_lock write locked. */ static void task_update_object(struct task_kddm_object *obj) { struct task_struct *tsk = obj->task; const struct cred *cred; if (tsk) { BUG_ON(tsk->task_obj != obj); obj->state = tsk->state; obj->flags = tsk->flags; obj->ptrace = tsk->ptrace; obj->exit_state = tsk->exit_state; obj->exit_code = tsk->exit_code; obj->exit_signal = tsk->exit_signal; obj->self_exec_id = tsk->self_exec_id; BUG_ON(obj->node != kerrighed_node_id && obj->node != KERRIGHED_NODE_ID_NONE); rcu_read_lock(); cred = __task_cred(tsk); obj->uid = cred->uid; obj->euid = cred->euid; obj->egid = cred->egid; rcu_read_unlock(); obj->utime = task_utime(tsk); obj->stime = task_stime(tsk); obj->dumpable = (tsk->mm && get_dumpable(tsk->mm) == 1); obj->thread_group_empty = thread_group_empty(tsk); } }
void gr_handle_crash(struct task_struct *task, const int sig) { struct acl_subject_label *curr; struct acl_subject_label *curr2; struct task_struct *tsk, *tsk2; const struct cred *cred; const struct cred *cred2; if (sig != SIGSEGV && sig != SIGKILL && sig != SIGBUS && sig != SIGILL) return; if (unlikely(!gr_acl_is_enabled())) return; curr = task->acl; if (!(curr->resmask & (1 << GR_CRASH_RES))) return; if (time_before_eq(curr->expires, get_seconds())) { curr->expires = 0; curr->crashes = 0; } curr->crashes++; if (!curr->expires) curr->expires = get_seconds() + curr->res[GR_CRASH_RES].rlim_max; if ((curr->crashes >= curr->res[GR_CRASH_RES].rlim_cur) && time_after(curr->expires, get_seconds())) { rcu_read_lock(); cred = __task_cred(task); if (cred->uid && proc_is_setxid(cred)) { gr_log_crash1(GR_DONT_AUDIT, GR_SEGVSTART_ACL_MSG, task, curr->res[GR_CRASH_RES].rlim_max); spin_lock(&gr_uid_lock); gr_insert_uid(cred->uid, curr->expires); spin_unlock(&gr_uid_lock); curr->expires = 0; curr->crashes = 0; read_lock(&tasklist_lock); do_each_thread(tsk2, tsk) { cred2 = __task_cred(tsk); if (tsk != task && cred2->uid == cred->uid) gr_fake_force_sig(SIGKILL, tsk); } while_each_thread(tsk2, tsk);
static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) { struct files_struct *files; struct task_struct *task; const struct cred *cred; struct inode *inode; int fd; if (flags & LOOKUP_RCU) return -ECHILD; inode = dentry->d_inode; task = get_proc_task(inode); fd = proc_fd(inode); if (task) { files = get_files_struct(task); if (files) { struct file *file; rcu_read_lock(); file = fcheck_files(files, fd); if (file) { unsigned f_mode = file->f_mode; rcu_read_unlock(); put_files_struct(files); if (task_dumpable(task)) { rcu_read_lock(); cred = __task_cred(task); inode->i_uid = cred->euid; inode->i_gid = cred->egid; rcu_read_unlock(); } else { inode->i_uid = GLOBAL_ROOT_UID; inode->i_gid = GLOBAL_ROOT_GID; } if (S_ISLNK(inode->i_mode)) { unsigned i_mode = S_IFLNK; if (f_mode & FMODE_READ) i_mode |= S_IRUSR | S_IXUSR; if (f_mode & FMODE_WRITE) i_mode |= S_IWUSR | S_IXUSR; inode->i_mode = i_mode; } security_task_to_inode(task, inode); put_task_struct(task); return 1; } rcu_read_unlock(); put_files_struct(files); } put_task_struct(task); } return 0; }
static void gr_log_end(int audit, int append_default) { char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; if (append_default) { struct task_struct *task = current; struct task_struct *parent = task->real_parent; const struct cred *cred = __task_cred(task); const struct cred *pcred = __task_cred(parent); unsigned int len = strlen(buf); snprintf(buf + len, PAGE_SIZE - len - 1, DEFAULTSECMSG, gr_task_fullpath(task), task->comm, task_pid_nr(task), GR_GLOBAL_UID(cred->uid), GR_GLOBAL_UID(cred->euid), GR_GLOBAL_GID(cred->gid), GR_GLOBAL_GID(cred->egid), gr_parent_task_fullpath(task), parent->comm, task_pid_nr(task->real_parent), GR_GLOBAL_UID(pcred->uid), GR_GLOBAL_UID(pcred->euid), GR_GLOBAL_GID(pcred->gid), GR_GLOBAL_GID(pcred->egid)); } printk("%s\n", buf); return; }
int set_task_ioprio(struct task_struct *task, int ioprio) { #ifdef CONFIG_IOSCHED_BFQ int err, i; #else int err; #endif struct io_context *ioc; const struct cred *cred = current_cred(), *tcred; rcu_read_lock(); tcred = __task_cred(task); if (tcred->uid != cred->euid && tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) { rcu_read_unlock(); return -EPERM; } rcu_read_unlock(); err = security_task_setioprio(task, ioprio); if (err) return err; task_lock(task); do { ioc = task->io_context; /* see wmb() in current_io_context() */ smp_read_barrier_depends(); if (ioc) break; ioc = alloc_io_context(GFP_ATOMIC, -1); if (!ioc) { err = -ENOMEM; break; } #ifdef CONFIG_IOSCHED_BFQ /* let other ioc users see the new values */ smp_wmb(); #endif task->io_context = ioc; } while (1); if (!err) { ioc->ioprio = ioprio; #ifdef CONFIG_IOSCHED_BFQ /* make sure schedulers see the new ioprio value */ wmb(); for (i = 0; i < IOC_IOPRIO_CHANGED_BITS; i++) set_bit(i, ioc->ioprio_changed); #else ioc->ioprio_changed = 1; #endif } task_unlock(task); return err; }
/* * check the target process has a UID that matches the current process's */ static bool check_same_owner(struct task_struct *p) { const struct cred *cred = current_cred(), *pcred; bool match; rcu_read_lock(); pcred = __task_cred(p); match = (uid_eq(cred->euid, pcred->euid) || uid_eq(cred->euid, pcred->uid)); rcu_read_unlock(); return match; }
/** * cap_ptrace_traceme - Determine whether another process may trace the current * @parent: The task proposed to be the tracer * * Determine whether the nominated task is permitted to trace the current * process, returning 0 if permission is granted, -ve if denied. */ int cap_ptrace_traceme(struct task_struct *parent) { int ret = 0; rcu_read_lock(); if (!cap_issubset(current_cred()->cap_permitted, __task_cred(parent)->cap_permitted) && !has_capability(parent, CAP_SYS_PTRACE)) ret = -EPERM; rcu_read_unlock(); return ret; }
/** * cap_ptrace_access_check - Determine whether the current process may access * another * @child: The process to be accessed * @mode: The mode of attachment. * * Determine whether a process may access another, returning 0 if permission * granted, -ve if denied. */ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) { int ret = 0; rcu_read_lock(); if (!cap_issubset(__task_cred(child)->cap_permitted, current_cred()->cap_permitted) && !capable(CAP_SYS_PTRACE)) ret = -EPERM; rcu_read_unlock(); return ret; }
static inline void task_state(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *p) { struct group_info *group_info; int g; struct fdtable *fdt = NULL; const struct cred *cred; pid_t ppid, tpid; rcu_read_lock(); ppid = pid_alive(p) ? task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; tpid = 0; if (pid_alive(p)) { struct task_struct *tracer = tracehook_tracer_task(p); if (tracer) tpid = task_pid_nr_ns(tracer, ns); } cred = get_cred((struct cred *) __task_cred(p)); seq_printf(m, "State:\t%s\n" "Tgid:\t%d\n" "Pid:\t%d\n" "PPid:\t%d\n" "TracerPid:\t%d\n" "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), task_tgid_nr_ns(p, ns), pid_nr_ns(pid, ns), ppid, tpid, cred->uid, cred->euid, cred->suid, cred->fsuid, cred->gid, cred->egid, cred->sgid, cred->fsgid); task_lock(p); if (p->files) fdt = files_fdtable(p->files); seq_printf(m, "FDSize:\t%d\n" "Groups:\t", fdt ? fdt->max_fds : 0); rcu_read_unlock(); group_info = cred->group_info; task_unlock(p); for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) seq_printf(m, "%d ", GROUP_AT(group_info, g)); put_cred(cred); seq_printf(m, "\n"); }
void gr_handle_brute_attach(struct task_struct *p, unsigned long mm_flags) { #ifdef CONFIG_GRKERNSEC_BRUTE uid_t uid = 0; if (!grsec_enable_brute) return; rcu_read_lock(); read_lock(&tasklist_lock); read_lock(&grsec_exec_file_lock); if (p->real_parent && p->real_parent->exec_file == p->exec_file) p->real_parent->brute = 1; else { const struct cred *cred = __task_cred(p), *cred2; struct task_struct *tsk, *tsk2; if (!__get_dumpable(mm_flags) && cred->uid) { struct user_struct *user; uid = cred->uid; /* this is put upon execution past expiration */ user = find_user(uid); if (user == NULL) goto unlock; user->banned = 1; user->ban_expires = get_seconds() + GR_USER_BAN_TIME; if (user->ban_expires == ~0UL) user->ban_expires--; do_each_thread(tsk2, tsk) { cred2 = __task_cred(tsk); if (tsk != p && cred2->uid == uid) gr_fake_force_sig(SIGKILL, tsk); } while_each_thread(tsk2, tsk); } }
/** * cap_capget - Retrieve a task's capability sets * @target: The task from which to retrieve the capability sets * @effective: The place to record the effective set * @inheritable: The place to record the inheritable set * @permitted: The place to record the permitted set * * This function retrieves the capabilities of the nominated task and returns * them to the caller. */ int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { const struct cred *cred; /* Derived from kernel/capability.c:sys_capget. */ rcu_read_lock(); cred = __task_cred(target); *effective = cred->cap_effective; *inheritable = cred->cap_inheritable; *permitted = cred->cap_permitted; rcu_read_unlock(); return 0; }
static inline int sigio_perm(struct task_struct *p, struct fown_struct *fown, int sig) { const struct cred *cred; int ret; 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)); rcu_read_unlock(); return ret; }
void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) { const struct cred *tcred; struct timespec uptime, ts; u64 ac_etime; BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN); do_posix_clock_monotonic_gettime(&uptime); ts = timespec_sub(uptime, tsk->start_time); ac_etime = timespec_to_ns(&ts); do_div(ac_etime, NSEC_PER_USEC); stats->ac_etime = ac_etime; stats->ac_btime = get_seconds() - ts.tv_sec; if (thread_group_leader(tsk)) { stats->ac_exitcode = tsk->exit_code; if (tsk->flags & PF_FORKNOEXEC) stats->ac_flag |= AFORK; } if (tsk->flags & PF_SUPERPRIV) stats->ac_flag |= ASU; if (tsk->flags & PF_DUMPCORE) stats->ac_flag |= ACORE; if (tsk->flags & PF_SIGNALED) stats->ac_flag |= AXSIG; stats->ac_nice = task_nice(tsk); stats->ac_sched = tsk->policy; stats->ac_pid = tsk->pid; rcu_read_lock(); tcred = __task_cred(tsk); stats->ac_uid = tcred->uid; stats->ac_gid = tcred->gid; stats->ac_ppid = pid_alive(tsk) ? rcu_dereference(tsk->real_parent)->tgid : 0; rcu_read_unlock(); stats->ac_utime = cputime_to_msecs(tsk->utime) * USEC_PER_MSEC; stats->ac_stime = cputime_to_msecs(tsk->stime) * USEC_PER_MSEC; stats->ac_utimescaled = cputime_to_msecs(tsk->utimescaled) * USEC_PER_MSEC; stats->ac_stimescaled = cputime_to_msecs(tsk->stimescaled) * USEC_PER_MSEC; stats->ac_minflt = tsk->min_flt; stats->ac_majflt = tsk->maj_flt; strncpy(stats->ac_comm, tsk->comm, sizeof(stats->ac_comm)); }
asmlinkage long compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, compat_size_t __user *len_ptr) { struct compat_robust_list_head __user *head; unsigned long ret; #ifndef CONFIG_GRKERNSEC_PROC_MEMMAP const struct cred *cred = current_cred(); const struct cred *pcred; #endif if (!futex_cmpxchg_enabled) return -ENOSYS; if (!pid) head = current->compat_robust_list; else { struct task_struct *p; ret = -ESRCH; read_lock(&tasklist_lock); p = find_task_by_vpid(pid); if (!p) goto err_unlock; ret = -EPERM; #ifdef CONFIG_GRKERNSEC_PROC_MEMMAP if (!ptrace_may_access(p, PTRACE_MODE_READ)) goto err_unlock; #else pcred = __task_cred(p); if (cred->euid != pcred->euid && cred->euid != pcred->uid && !capable(CAP_SYS_PTRACE)) goto err_unlock; #endif head = p->compat_robust_list; read_unlock(&tasklist_lock); } if (put_user(sizeof(*head), len_ptr)) return -EFAULT; return put_user(ptr_to_compat(head), head_ptr); err_unlock: read_unlock(&tasklist_lock); return ret; }
int set_task_ioprio(struct task_struct *task, int ioprio) { int err, i; struct io_context *ioc; const struct cred *cred = current_cred(), *tcred; rcu_read_lock(); tcred = __task_cred(task); if (tcred->uid != cred->euid && tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) { rcu_read_unlock(); return -EPERM; } rcu_read_unlock(); err = security_task_setioprio(task, ioprio); if (err) return err; task_lock(task); do { ioc = task->io_context; /* see wmb() in current_io_context() */ smp_read_barrier_depends(); if (ioc) break; ioc = alloc_io_context(GFP_ATOMIC, -1); if (!ioc) { err = -ENOMEM; break; } smp_wmb(); task->io_context = ioc; } while (1); if (!err) { ioc->ioprio = ioprio; wmb(); for (i = 0; i < IOC_IOPRIO_CHANGED_BITS; i++) set_bit(i, ioc->ioprio_changed); } task_unlock(task); return err; }
/* Check whether a task is allowed to use a security operation. */ static int task_has_security(struct task_struct *tsk, u32 perms) { const struct task_security_struct *tsec; u32 sid = 0; rcu_read_lock(); tsec = __task_cred(tsk)->security; if (tsec) sid = tsec->sid; rcu_read_unlock(); if (!tsec) return -EACCES; return avc_has_perm(sid, SECINITSID_SECURITY, SECCLASS_SECURITY, perms, NULL); }
/** * cap_ptrace_traceme - Determine whether another process may trace the current * @parent: The task proposed to be the tracer * * If parent is in the same or an ancestor user_ns and has all current's * capabilities, then ptrace access is allowed. * If parent has the ptrace capability to current's user_ns, then ptrace * access is allowed. * Else denied. * * Determine whether the nominated task is permitted to trace the current * process, returning 0 if permission is granted, -ve if denied. */ int cap_ptrace_traceme(struct task_struct *parent) { int ret = 0; const struct cred *cred, *child_cred; rcu_read_lock(); cred = __task_cred(parent); child_cred = current_cred(); if (cred->user->user_ns == child_cred->user->user_ns && cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) goto out; if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE)) goto out; ret = -EPERM; out: rcu_read_unlock(); return ret; }
/** * cap_ptrace_access_check - Determine whether the current process may access * another * @child: The process to be accessed * @mode: The mode of attachment. * * If we are in the same or an ancestor user_ns and have all the target * task's capabilities, then ptrace access is allowed. * If we have the ptrace capability to the target user_ns, then ptrace * access is allowed. * Else denied. * * Determine whether a process may access another, returning 0 if permission * granted, -ve if denied. */ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) { int ret = 0; const struct cred *cred, *child_cred; rcu_read_lock(); cred = current_cred(); child_cred = __task_cred(child); if (cred->user->user_ns == child_cred->user->user_ns && cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) goto out; if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE)) goto out; ret = -EPERM; out: rcu_read_unlock(); return ret; }
void gr_log_resource(const struct task_struct *task, const int res, const unsigned long wanted, const int gt) { const struct cred *cred; unsigned long rlim; if (!gr_acl_is_enabled() && !grsec_resource_logging) return; // not yet supported resource if (unlikely(!restab_log[res])) return; if (res == RLIMIT_CPU || res == RLIMIT_RTTIME) rlim = task->signal->rlim[res].rlim_max; else rlim = task->signal->rlim[res].rlim_cur; if (likely((rlim == RLIM_INFINITY) || (gt && wanted <= rlim) || (!gt && wanted < rlim))) return; rcu_read_lock(); cred = __task_cred(task); if (res == RLIMIT_NPROC && (cap_raised(cred->cap_effective, CAP_SYS_ADMIN) || cap_raised(cred->cap_effective, CAP_SYS_RESOURCE))) goto out_rcu_unlock; else if (res == RLIMIT_MEMLOCK && cap_raised(cred->cap_effective, CAP_IPC_LOCK)) goto out_rcu_unlock; else if (res == RLIMIT_NICE && cap_raised(cred->cap_effective, CAP_SYS_NICE)) goto out_rcu_unlock; rcu_read_unlock(); gr_log_res_ulong2_str(GR_DONT_AUDIT, GR_RESOURCE_MSG, task, wanted, restab_log[res], rlim); return; out_rcu_unlock: rcu_read_unlock(); return; }
asmlinkage long compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, compat_size_t __user *len_ptr) { struct compat_robust_list_head __user *head; unsigned long ret; const struct cred *cred = current_cred(), *pcred; if (!futex_cmpxchg_enabled) return -ENOSYS; if (!pid) head = current->compat_robust_list; else { struct task_struct *p; ret = -ESRCH; read_lock(&tasklist_lock); p = find_task_by_vpid(pid); if (!p) goto err_unlock; ret = -EPERM; pcred = __task_cred(p); if (cred->euid != pcred->euid && cred->euid != pcred->uid && !capable(CAP_SYS_PTRACE)) goto err_unlock; head = p->compat_robust_list; read_unlock(&tasklist_lock); } if (put_user(sizeof(*head), len_ptr)) return -EFAULT; return put_user(ptr_to_compat(head), head_ptr); err_unlock: read_unlock(&tasklist_lock); return ret; }
int __ptrace_may_access(struct task_struct *task, unsigned int mode) { const struct cred *cred = current_cred(), *tcred; /* 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. */ int dumpable = 0; /* Don't let security modules deny introspection */ if (task == current) return 0; rcu_read_lock(); tcred = __task_cred(task); if (cred->user->user_ns == tcred->user->user_ns && (cred->uid == tcred->euid && cred->uid == tcred->suid && cred->uid == tcred->uid && cred->gid == tcred->egid && cred->gid == tcred->sgid && cred->gid == tcred->gid)) goto ok; if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE)) goto ok; rcu_read_unlock(); return -EPERM; ok: rcu_read_unlock(); smp_rmb(); if (task->mm) dumpable = get_dumpable(task->mm); if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE)) return -EPERM; return security_ptrace_access_check(task, mode); }
void proc_id_connector(struct task_struct *task, int which_id) { struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); struct timespec ts; const struct cred *cred; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = buffer_to_cn_msg(buffer); ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); ev->what = which_id; ev->event_data.id.process_pid = task->pid; ev->event_data.id.process_tgid = task->tgid; rcu_read_lock(); cred = __task_cred(task); if (which_id == PROC_EVENT_UID) { ev->event_data.id.r.ruid = from_kuid_munged(&init_user_ns, cred->uid); ev->event_data.id.e.euid = from_kuid_munged(&init_user_ns, cred->euid); } else if (which_id == PROC_EVENT_GID) { ev->event_data.id.r.rgid = from_kgid_munged(&init_user_ns, cred->gid); ev->event_data.id.e.egid = from_kgid_munged(&init_user_ns, cred->egid); } else { rcu_read_unlock(); return; } rcu_read_unlock(); get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = timespec_to_ns(&ts); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); msg->flags = 0; /* not used */ cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
/* * Calling into a user-controlled filesystem gives the filesystem * daemon ptrace-like capabilities over the requester process. This * means, that the filesystem daemon is able to record the exact * filesystem operations performed, and can also control the behavior * of the requester process in otherwise impossible ways. For example * it can delay the operation for arbitrary length of time allowing * DoS against the requester. * * For this reason only those processes can call into the filesystem, * for which the owner of the mount has ptrace privilege. This * excludes processes started by other users, suid or sgid processes. */ int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) { const struct cred *cred; int ret; if (fc->flags & FUSE_ALLOW_OTHER) return 1; rcu_read_lock(); ret = 0; cred = __task_cred(task); if (cred->euid == fc->user_id && cred->suid == fc->user_id && cred->uid == fc->user_id && cred->egid == fc->group_id && cred->sgid == fc->group_id && cred->gid == fc->group_id) ret = 1; rcu_read_unlock(); return ret; }
/** * cap_ptrace_access_check - Determine whether the current process may access * another * @child: The process to be accessed * @mode: The mode of attachment. * * If we are in the same or an ancestor user_ns and have all the target * task's capabilities, then ptrace access is allowed. * If we have the ptrace capability to the target user_ns, then ptrace * access is allowed. * Else denied. * * Determine whether a process may access another, returning 0 if permission * granted, -ve if denied. */ 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; out: rcu_read_unlock(); return ret; }