Пример #1
0
/*
 * setgid() is implemented like SysV w/ SAVED_IDS 
 *
 * SMP: Same implicit races as above.
 */
asmlinkage long sys_setgid(gid_t gid)
{
	int old_egid = current->egid;
	int retval;

	retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
	if (retval)
		return retval;

	if (capable(CAP_SETGID)) {
		if (old_egid != gid) {
			set_dumpable(current->mm, suid_dumpable);
			smp_wmb();
		}
		current->gid = current->egid = current->sgid = current->fsgid = gid;
	} else if ((gid == current->gid) || (gid == current->sgid)) {
		if (old_egid != gid) {
			set_dumpable(current->mm, suid_dumpable);
			smp_wmb();
		}
		current->egid = current->fsgid = gid;
	}
	else
		return -EPERM;

	key_fsgid_changed(current);
	proc_id_connector(current, PROC_EVENT_GID);
	return 0;
}
Пример #2
0
int flush_old_exec_from_task(struct task_struct *task)
{
	int retval;

	retval = de_thread(task);
	if(retval)
		goto out;

	ethread_notify_execve(task);

	task->sas_ss_sp = task->sas_ss_size = 0;

	if (task->cred->euid == task->cred->uid && task->cred->egid == task->cred->gid)
		set_dumpable(current->mm, 1);
	else
		set_dumpable(current->mm, 0);

	task->flags &= ~PF_RANDOMIZE;
	flush_thread_from_task(task);

	/* Set the new mm task size. We have to do that late because it may
	 * depend on TIF_32BIT which is only updated in flush_thread() on
	 * some architectures like powerpc
	 */
	task->mm->task_size = 0x80000000;

	task->self_exec_id++;

	flush_signal_handlers_from_task(task, 0);
	flush_old_files_from_task(task);

	return 0;
out:
	return retval;
}
Пример #3
0
/*
 * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
 * is used for "access()" and for the NFS daemon (letting nfsd stay at
 * whatever uid it wants to). It normally shadows "euid", except when
 * explicitly set by setfsuid() or for access..
 */
asmlinkage long sys_setfsuid(uid_t uid)
{
	int old_fsuid;

	old_fsuid = current->fsuid;
	if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))
		return old_fsuid;

	if (uid == current->uid || uid == current->euid ||
	    uid == current->suid || uid == current->fsuid || 
	    capable(CAP_SETUID)) {
		if (uid != old_fsuid) {
			set_dumpable(current->mm, suid_dumpable);
			smp_wmb();
		}
		current->fsuid = uid;
	}

	key_fsuid_changed(current);
	proc_id_connector(current, PROC_EVENT_UID);

	security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);

	return old_fsuid;
}
Пример #4
0
/*
 * setuid() is implemented like SysV with SAVED_IDS 
 * 
 * Note that SAVED_ID's is deficient in that a setuid root program
 * like sendmail, for example, cannot set its uid to be a normal 
 * user and then switch back, because if you're root, setuid() sets
 * the saved uid too.  If you don't like this, blame the bright people
 * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
 * will allow a root program to temporarily drop privileges and be able to
 * regain them by swapping the real and effective uid.  
 */
asmlinkage long sys_setuid(uid_t uid)
{
	int old_euid = current->euid;
	int old_ruid, old_suid, new_suid;
	int retval;

	retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
	if (retval)
		return retval;

	old_ruid = current->uid;
	old_suid = current->suid;
	new_suid = old_suid;
	
	if (capable(CAP_SETUID)) {
		if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
			return -EAGAIN;
		new_suid = uid;
	} else if ((uid != current->uid) && (uid != new_suid))
		return -EPERM;

	if (old_euid != uid) {
		set_dumpable(current->mm, suid_dumpable);
		smp_wmb();
	}
	current->fsuid = current->euid = uid;
	current->suid = new_suid;

	key_fsuid_changed(current);
	proc_id_connector(current, PROC_EVENT_UID);

	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
}
Пример #5
0
/*
 * Unprivileged users may change the real uid to the effective uid
 * or vice versa.  (BSD-style)
 *
 * If you set the real uid at all, or set the effective uid to a value not
 * equal to the real uid, then the saved uid is set to the new effective uid.
 *
 * This makes it possible for a setuid program to completely drop its
 * privileges, which is often a useful assertion to make when you are doing
 * a security audit over a program.
 *
 * The general idea is that a program which uses just setreuid() will be
 * 100% compatible with BSD.  A program which uses just setuid() will be
 * 100% compatible with POSIX with saved IDs. 
 */
asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
{
	int old_ruid, old_euid, old_suid, new_ruid, new_euid;
	int retval;

	retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
	if (retval)
		return retval;

	new_ruid = old_ruid = current->uid;
	new_euid = old_euid = current->euid;
	old_suid = current->suid;

	if (ruid != (uid_t) -1) {
		new_ruid = ruid;
		if ((old_ruid != ruid) &&
		    (current->euid != ruid) &&
		    !capable(CAP_SETUID))
			return -EPERM;
	}

	if (euid != (uid_t) -1) {
		new_euid = euid;
		if ((old_ruid != euid) &&
		    (current->euid != euid) &&
		    (current->suid != euid) &&
		    !capable(CAP_SETUID))
			return -EPERM;
	}

	if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
		return -EAGAIN;

	if (new_euid != old_euid) {
		set_dumpable(current->mm, suid_dumpable);
		smp_wmb();
	}
	current->fsuid = current->euid = new_euid;
	if (ruid != (uid_t) -1 ||
	    (euid != (uid_t) -1 && euid != old_ruid))
		current->suid = current->euid;
	current->fsuid = current->euid;

	key_fsuid_changed(current);
	proc_id_connector(current, PROC_EVENT_UID);

	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
}
Пример #6
0
static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
	if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
		set_dumpable(current->mm, suid_dumpable);

		if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) && !capable(CAP_SETUID)) {
			bprm->e_uid = current->uid;
			bprm->e_gid = current->gid;
		}
	}

	current->suid = current->euid = current->fsuid = bprm->e_uid;
	current->sgid = current->egid = current->fsgid = bprm->e_gid;

	dummy_capget(current, &current->cap_effective, &current->cap_inheritable, &current->cap_permitted);
}
Пример #7
0
/*
 * Unprivileged users may change the real gid to the effective gid
 * or vice versa.  (BSD-style)
 *
 * If you set the real gid at all, or set the effective gid to a value not
 * equal to the real gid, then the saved gid is set to the new effective gid.
 *
 * This makes it possible for a setgid program to completely drop its
 * privileges, which is often a useful assertion to make when you are doing
 * a security audit over a program.
 *
 * The general idea is that a program which uses just setregid() will be
 * 100% compatible with BSD.  A program which uses just setgid() will be
 * 100% compatible with POSIX with saved IDs. 
 *
 * SMP: There are not races, the GIDs are checked only by filesystem
 *      operations (as far as semantic preservation is concerned).
 */
asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
{
	int old_rgid = current->gid;
	int old_egid = current->egid;
	int new_rgid = old_rgid;
	int new_egid = old_egid;
	int retval;

	retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
	if (retval)
		return retval;

	if (rgid != (gid_t) -1) {
		if ((old_rgid == rgid) ||
		    (current->egid==rgid) ||
		    capable(CAP_SETGID))
			new_rgid = rgid;
		else
			return -EPERM;
	}
	if (egid != (gid_t) -1) {
		if ((old_rgid == egid) ||
		    (current->egid == egid) ||
		    (current->sgid == egid) ||
		    capable(CAP_SETGID))
			new_egid = egid;
		else
			return -EPERM;
	}
	if (new_egid != old_egid) {
		set_dumpable(current->mm, suid_dumpable);
		smp_wmb();
	}
	if (rgid != (gid_t) -1 ||
	    (egid != (gid_t) -1 && egid != old_rgid))
		current->sgid = new_egid;
	current->fsgid = new_egid;
	current->egid = new_egid;
	current->gid = new_rgid;
	key_fsgid_changed(current);
	proc_id_connector(current, PROC_EVENT_GID);
	return 0;
}
Пример #8
0
/*
 * This function implements a generic ability to update ruid, euid,
 * and suid.  This allows you to implement the 4.4 compatible seteuid().
 */
asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
{
	int old_ruid = current->uid;
	int old_euid = current->euid;
	int old_suid = current->suid;
	int retval;

	retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
	if (retval)
		return retval;

	if (!capable(CAP_SETUID)) {
		if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
		    (ruid != current->euid) && (ruid != current->suid))
			return -EPERM;
		if ((euid != (uid_t) -1) && (euid != current->uid) &&
		    (euid != current->euid) && (euid != current->suid))
			return -EPERM;
		if ((suid != (uid_t) -1) && (suid != current->uid) &&
		    (suid != current->euid) && (suid != current->suid))
			return -EPERM;
	}
	if (ruid != (uid_t) -1) {
		if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
			return -EAGAIN;
	}
	if (euid != (uid_t) -1) {
		if (euid != current->euid) {
			set_dumpable(current->mm, suid_dumpable);
			smp_wmb();
		}
		current->euid = euid;
	}
	current->fsuid = current->euid;
	if (suid != (uid_t) -1)
		current->suid = suid;

	key_fsuid_changed(current);
	proc_id_connector(current, PROC_EVENT_UID);

	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
}
Пример #9
0
/*
 * Samma på svenska..
 */
asmlinkage long sys_setfsgid(gid_t gid)
{
	int old_fsgid;

	old_fsgid = current->fsgid;
	if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
		return old_fsgid;

	if (gid == current->gid || gid == current->egid ||
	    gid == current->sgid || gid == current->fsgid || 
	    capable(CAP_SETGID)) {
		if (gid != old_fsgid) {
			set_dumpable(current->mm, suid_dumpable);
			smp_wmb();
		}
		current->fsgid = gid;
		key_fsgid_changed(current);
		proc_id_connector(current, PROC_EVENT_GID);
	}
	return old_fsgid;
}
Пример #10
0
int main(int argc, char** argv)
try
{
	if(!setup(argc, argv))
	{
		usage();
		exit(-2);
	}

	std::cerr << "parsed channels: ";
	std::copy(channel_list.begin(), channel_list.end(),
      std::ostream_iterator<int> (std::cerr, " "));
	std::cerr << std::endl;
	std::cerr << "nflogd starting..." << std::endl;

	PacketHandler ph(pcap_filename);
	NFmain nf(channel_list, [ph = std::ref(ph)](struct nflog_data *nfa){
       ph(nfa);
    });

	// setup signal
	SETSIG(SIGTERM, term_handler, SA_RESTART);
	SETSIG(SIGINT, term_handler, SA_RESTART);
	SETSIG(SIGHUP, hup_handler, SA_RESTART);

	std::cerr << "going into main loop" << std::endl;

	switch_user();
	set_dumpable();
	nf.loop(term_flag);

	std::cerr << "terminating..." << std::endl;
	return 0;
}
catch (const std::exception& e)
{
    std::cerr << e.what() << std::endl;
    return -1;
}
Пример #11
0
/*
 * Same as above, but for rgid, egid, sgid.
 */
asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
{
	int retval;

	retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
	if (retval)
		return retval;

	if (!capable(CAP_SETGID)) {
		if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
		    (rgid != current->egid) && (rgid != current->sgid))
			return -EPERM;
		if ((egid != (gid_t) -1) && (egid != current->gid) &&
		    (egid != current->egid) && (egid != current->sgid))
			return -EPERM;
		if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
		    (sgid != current->egid) && (sgid != current->sgid))
			return -EPERM;
	}
	if (egid != (gid_t) -1) {
		if (egid != current->egid) {
			set_dumpable(current->mm, suid_dumpable);
			smp_wmb();
		}
		current->egid = egid;
	}
	current->fsgid = current->egid;
	if (rgid != (gid_t) -1)
		current->gid = rgid;
	if (sgid != (gid_t) -1)
		current->sgid = sgid;

	key_fsgid_changed(current);
	proc_id_connector(current, PROC_EVENT_GID);
	return 0;
}
Пример #12
0
static int set_user(uid_t new_ruid, int dumpclear)
{
	struct user_struct *new_user;

	new_user = alloc_uid(current->nsproxy->user_ns, new_ruid);
	if (!new_user)
		return -EAGAIN;

	if (atomic_read(&new_user->processes) >=
				current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
			new_user != current->nsproxy->user_ns->root_user) {
		free_uid(new_user);
		return -EAGAIN;
	}

	switch_uid(new_user);

	if (dumpclear) {
		set_dumpable(current->mm, suid_dumpable);
		smp_wmb();
	}
	current->uid = new_ruid;
	return 0;
}
Пример #13
0
int ckpt_restore_cred(ckpt_desc_t desc)
{
    int ret = 0;
    ckpt_cred_t cred;
    gid_t *groups = NULL;
    const struct cred *curr_cred = current->cred;

    log_restore_cred("restoring cred ...");
    if (ckpt_read(desc, &cred, sizeof(ckpt_cred_t)) != sizeof(ckpt_cred_t)) {
        log_err("failed to get cred");
        return -EIO;
    }

    if (cred.ngroups > NGROUPS_MAX) {
        log_err("ngroups (%d) > NGROUPS_MAX", cred.ngroups);
        return -EINVAL;
    }

    if (cred.ngroups > 0) {
        int i;
        size_t size = cred.ngroups * sizeof(gid_t);
        struct group_info *gi = curr_cred->group_info;

        groups = vmalloc(size);
        if (!groups) {
            log_err("no memory");
            return -ENOMEM;
        }

        if (ckpt_read(desc, groups, size) != size) {
            log_err("failed to get groups");
            ret = -EIO;
            goto out;
        }

        for (i = 0; i < cred.ngroups; i++) {
            if (!groups_search(gi, groups[i])) {
                mm_segment_t fs = get_fs();
                set_fs(KERNEL_DS);
                ret = sys_setgroups(cred.ngroups, groups);
                set_fs(fs);
                if (ret < 0) {
                    log_err("failed to set groups");
                    goto out;
                }
                break;
            }
        }
    }

    current->gpid = cred.gpid;
    ret = sys_setresgid(cred.gid, cred.egid, cred.sgid);
    if (ret < 0) {
        log_err("failed to restore gid");
        goto out;
    }

    ret = sys_setresuid(cred.uid, cred.euid, cred.suid);
    if (ret < 0) {
        log_err("failed to restore uid");
        goto out;
    }

    if ((curr_cred->euid == curr_cred->uid) && (curr_cred->egid == curr_cred->gid))
        set_dumpable(current->mm, 1);
    else
        set_dumpable(current->mm, *compat_suid_dumpable);
    log_restore_pos(desc);
out:
    if (groups)
        vfree(groups);
    return ret;
}
Пример #14
0
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
			  unsigned long arg4, unsigned long arg5)
{
	long error = 0;

	if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error))
		return error;

	switch (option) {
		case PR_SET_PDEATHSIG:
			if (!valid_signal(arg2)) {
				error = -EINVAL;
				break;
			}
			current->pdeath_signal = arg2;
			break;
		case PR_GET_PDEATHSIG:
			error = put_user(current->pdeath_signal, (int __user *)arg2);
			break;
		case PR_GET_DUMPABLE:
			error = get_dumpable(current->mm);
			break;
		case PR_SET_DUMPABLE:
			if (arg2 < 0 || arg2 > 1) {
				error = -EINVAL;
				break;
			}
			set_dumpable(current->mm, arg2);
			break;

		case PR_SET_UNALIGN:
			error = SET_UNALIGN_CTL(current, arg2);
			break;
		case PR_GET_UNALIGN:
			error = GET_UNALIGN_CTL(current, arg2);
			break;
		case PR_SET_FPEMU:
			error = SET_FPEMU_CTL(current, arg2);
			break;
		case PR_GET_FPEMU:
			error = GET_FPEMU_CTL(current, arg2);
			break;
		case PR_SET_FPEXC:
			error = SET_FPEXC_CTL(current, arg2);
			break;
		case PR_GET_FPEXC:
			error = GET_FPEXC_CTL(current, arg2);
			break;
		case PR_GET_TIMING:
			error = PR_TIMING_STATISTICAL;
			break;
		case PR_SET_TIMING:
			if (arg2 != PR_TIMING_STATISTICAL)
				error = -EINVAL;
			break;

		case PR_SET_NAME: {
			struct task_struct *me = current;
			unsigned char ncomm[sizeof(me->comm)];

			ncomm[sizeof(me->comm)-1] = 0;
			if (strncpy_from_user(ncomm, (char __user *)arg2,
						sizeof(me->comm)-1) < 0)
				return -EFAULT;
			set_task_comm(me, ncomm);
			return 0;
		}
		case PR_GET_NAME: {
			struct task_struct *me = current;
			unsigned char tcomm[sizeof(me->comm)];

			get_task_comm(tcomm, me);
			if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm)))
				return -EFAULT;
			return 0;
		}
		case PR_GET_ENDIAN:
			error = GET_ENDIAN(current, arg2);
			break;
		case PR_SET_ENDIAN:
			error = SET_ENDIAN(current, arg2);
			break;

		case PR_GET_SECCOMP:
			error = prctl_get_seccomp();
			break;
		case PR_SET_SECCOMP:
			error = prctl_set_seccomp(arg2);
			break;
		case PR_GET_TSC:
			error = GET_TSC_CTL(arg2);
			break;
		case PR_SET_TSC:
			error = SET_TSC_CTL(arg2);
			break;
		default:
			error = -EINVAL;
			break;
	}
	return error;
}