Page MenuHomeFreeBSD

D47618.id146551.diff
No OneTemporary

D47618.id146551.diff

diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map
--- a/lib/libsys/Symbol.sys.map
+++ b/lib/libsys/Symbol.sys.map
@@ -380,6 +380,7 @@
FBSD_1.8 {
getrlimitusage;
kcmp;
+ setcred;
};
FBSDprivate_1.0 {
diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h
--- a/lib/libsys/_libsys.h
+++ b/lib/libsys/_libsys.h
@@ -463,6 +463,7 @@
typedef int (__sys_timerfd_settime_t)(int, int, const struct itimerspec *, struct itimerspec *);
typedef int (__sys_kcmp_t)(pid_t, pid_t, int, uintptr_t, uintptr_t);
typedef int (__sys_getrlimitusage_t)(u_int, int, rlim_t *);
+typedef int (__sys_setcred_t)(u_int, const void *, size_t);
void __sys_exit(int rval);
int __sys_fork(void);
@@ -863,6 +864,7 @@
int __sys_timerfd_settime(int fd, int flags, const struct itimerspec * new_value, struct itimerspec * old_value);
int __sys_kcmp(pid_t pid1, pid_t pid2, int type, uintptr_t idx1, uintptr_t idx2);
int __sys_getrlimitusage(u_int which, int flags, rlim_t * res);
+int __sys_setcred(u_int flags, const void * wcred, size_t size);
__END_DECLS
#endif /* __LIBSYS_H_ */
diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map
--- a/lib/libsys/syscalls.map
+++ b/lib/libsys/syscalls.map
@@ -805,4 +805,6 @@
__sys_kcmp;
_getrlimitusage;
__sys_getrlimitusage;
+ _setcred;
+ __sys_setcred;
};
diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h
--- a/sys/bsm/audit_kevents.h
+++ b/sys/bsm/audit_kevents.h
@@ -662,6 +662,7 @@
#define AUE_AIO_READV 43268 /* FreeBSD-specific. */
#define AUE_FSPACECTL 43269 /* FreeBSD-specific. */
#define AUE_TIMERFD 43270 /* FreeBSD/Linux. */
+#define AUE_SETCRED 43271 /* FreeBSD-specific. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -508,4 +508,5 @@
#define FREEBSD32_SYS_freebsd32_timerfd_settime 587
#define FREEBSD32_SYS_kcmp 588
#define FREEBSD32_SYS_getrlimitusage 589
-#define FREEBSD32_SYS_MAXSYSCALL 590
+#define FREEBSD32_SYS_setcred 590
+#define FREEBSD32_SYS_MAXSYSCALL 591
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -595,4 +595,5 @@
"freebsd32_timerfd_settime", /* 587 = freebsd32_timerfd_settime */
"kcmp", /* 588 = kcmp */
"getrlimitusage", /* 589 = getrlimitusage */
+ "setcred", /* 590 = setcred */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -657,4 +657,5 @@
{ .sy_narg = AS(freebsd32_timerfd_settime_args), .sy_call = (sy_call_t *)freebsd32_timerfd_settime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 587 = freebsd32_timerfd_settime */
{ .sy_narg = AS(kcmp_args), .sy_call = (sy_call_t *)sys_kcmp, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 588 = kcmp */
{ .sy_narg = AS(getrlimitusage_args), .sy_call = (sy_call_t *)sys_getrlimitusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimitusage */
+ { .sy_narg = AS(setcred_args), .sy_call = (sy_call_t *)sys_setcred, .sy_auevent = AUE_SETCRED, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 590 = setcred */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3378,6 +3378,15 @@
*n_args = 3;
break;
}
+ /* setcred */
+ case 590: {
+ struct setcred_args *p = params;
+ uarg[a++] = p->flags; /* u_int */
+ uarg[a++] = (intptr_t)p->wcred; /* const void * */
+ uarg[a++] = p->size; /* size_t */
+ *n_args = 3;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9126,6 +9135,22 @@
break;
};
break;
+ /* setcred */
+ case 590:
+ switch (ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11014,6 +11039,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* setcred */
+ case 590:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -656,4 +656,5 @@
{ .sy_narg = AS(timerfd_settime_args), .sy_call = (sy_call_t *)sys_timerfd_settime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 587 = timerfd_settime */
{ .sy_narg = AS(kcmp_args), .sy_call = (sy_call_t *)sys_kcmp, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 588 = kcmp */
{ .sy_narg = AS(getrlimitusage_args), .sy_call = (sy_call_t *)sys_getrlimitusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimitusage */
+ { .sy_narg = AS(setcred_args), .sy_call = (sy_call_t *)sys_setcred, .sy_auevent = AUE_SETCRED, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 590 = setcred */
};
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -3956,6 +3956,7 @@
* Allow jailed processes to manipulate process UNIX
* credentials in any way they see fit.
*/
+ case PRIV_CRED_SETCRED:
case PRIV_CRED_SETUID:
case PRIV_CRED_SETEUID:
case PRIV_CRED_SETGID:
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -73,6 +73,10 @@
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
+#ifdef MAC
+#include <security/mac/mac_syscalls.h>
+#endif
+
#include <vm/uma.h>
#ifdef REGRESSION
@@ -484,6 +488,303 @@
return (error);
}
+static int
+gidp_cmp(const void *p1, const void *p2)
+{
+ const gid_t g1 = *(const gid_t *)p1;
+ const gid_t g2 = *(const gid_t *)p2;
+
+ return ((g1 > g2) - (g1 < g2));
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct setcred_args {
+ u_int flags; /* Flags, including version. */
+ const void *wcred; /* Some setcred_vX structure. */
+ size_t size; /* Length of setcred_vX structure. */
+};
+#endif
+int
+sys_setcred(struct thread *td, struct setcred_args *uap)
+{
+ const u_int flags = uap->flags;
+ const void *const uwcred = uap->wcred;
+ const size_t size = uap->size;
+ struct setcred_v0 wcred;
+#ifdef MAC
+ struct mac mac;
+#endif
+ gid_t smallgroups[CRED_SMALLGROUPS_NB];
+ gid_t *groups = NULL;
+ int error;
+
+ /*
+ * As the only point of this wrapper function is to copyin() from
+ * userland, we only interpret the data pieces we need to perform this
+ * operation and defer further sanity checks to kern_setcred_vX().
+ */
+
+ /* There is only one version for now. */
+ if (SETCREDF_TO_VERSION(flags) != 0 || size != sizeof(wcred))
+ return (EINVAL);
+
+ error = copyin(uwcred, &wcred, sizeof(wcred));
+ if (error != 0)
+ return (error);
+
+ if (flags & SETCREDF_SUPP_GROUPS) {
+ /*
+ * Check for the limit of number of groups right now in order to
+ * limit the amount of bytes to copy.
+ */
+ if (wcred.sc_supp_groups_nb > ngroups_max)
+ return (EINVAL);
+
+ /*
+ * Since we are going to be copying the supplementary groups
+ * from userland, make room also for the effective GID right
+ * now, to avoid having to allocate and copy again the
+ * supplementary groups.
+ */
+ groups = wcred.sc_supp_groups_nb < CRED_SMALLGROUPS_NB ?
+ smallgroups : malloc((wcred.sc_supp_groups_nb + 1) *
+ sizeof(*groups), M_TEMP, M_WAITOK);
+
+ error = copyin(wcred.sc_supp_groups, groups + 1,
+ wcred.sc_supp_groups_nb * sizeof(*groups));
+ if (error != 0)
+ goto finish;
+ wcred.sc_supp_groups = groups + 1;
+ } else {
+ wcred.sc_supp_groups_nb = 0;
+ wcred.sc_supp_groups = NULL;
+ }
+
+#ifdef MAC
+ if (flags & SETCREDF_MAC_LABEL) {
+ error = mac_label_copyin(wcred.sc_label, &mac, NULL);
+ if (error != 0) {
+ wcred.sc_label = NULL;
+ goto finish;
+ }
+ wcred.sc_label = &mac;
+ } else
+ wcred.sc_label = NULL;
+#endif
+
+ error = kern_setcred_v0(td, flags, &wcred, groups);
+
+finish:
+ if (groups != NULL && groups != smallgroups)
+ free(groups, M_TEMP);
+#ifdef MAC
+ if (wcred.sc_label != NULL)
+ free_copied_label(wcred.sc_label);
+#endif
+ return (error);
+}
+
+/*
+ * CAUTION: This function normalizes groups in 'wcred'.
+ *
+ * If 'preallocated_groups' is non-NULL, it must be an already allocated array
+ * of size 'wcred->sc_supp_groups_nb + 1', with the supplementary groups
+ * starting at index 1, and 'wcred->sc_supp_groups' then must point to the first
+ * supplementary group.
+ */
+int
+kern_setcred_v0(struct thread *const td, const u_int flags,
+ struct setcred_v0 *const wcred, gid_t *preallocated_groups)
+{
+ struct proc *const p = td->td_proc;
+ struct ucred *new_cred, *old_cred, *to_free_cred;
+ struct uidinfo *uip = NULL, *ruip = NULL;
+#ifdef MAC
+ void *mac_set_proc_data = NULL;
+ bool proc_label_set = false;
+#endif
+ gid_t *groups = NULL;
+ gid_t smallgroups[CRED_SMALLGROUPS_NB];
+ int error;
+ bool cred_set;
+
+ MPASS(SETCREDF_TO_VERSION(flags) == 0);
+ /* Bail out on unrecognized flags. */
+ if (flags & ~SETCREDF_MASK)
+ return (EINVAL);
+
+ /*
+ * Part 1: We allocate and perform preparatory operations with no locks.
+ */
+
+ if (flags & SETCREDF_SUPP_GROUPS) {
+ if (wcred->sc_supp_groups_nb > ngroups_max)
+ return (EINVAL);
+ if (preallocated_groups != NULL) {
+ groups = preallocated_groups;
+ MPASS(preallocated_groups + 1 == wcred->sc_supp_groups);
+ } else {
+ groups = wcred->sc_supp_groups_nb < CRED_SMALLGROUPS_NB ?
+ smallgroups :
+ malloc((wcred->sc_supp_groups_nb + 1) *
+ sizeof(*groups), M_TEMP, M_WAITOK);
+ memcpy(groups + 1, wcred->sc_supp_groups,
+ wcred->sc_supp_groups_nb * sizeof(*groups));
+ }
+ }
+
+ if (flags & SETCREDF_MAC_LABEL) {
+#ifdef MAC
+ error = mac_set_proc_prepare(td, wcred->sc_label,
+ &mac_set_proc_data);
+ if (error != 0)
+ goto free_groups;
+#else
+ error = ENOTSUP;
+ goto free_groups;
+#endif
+ }
+
+ if (flags & SETCREDF_UID) {
+ AUDIT_ARG_EUID(wcred->sc_uid);
+ uip = uifind(wcred->sc_uid);
+ }
+ if (flags & SETCREDF_RUID) {
+ AUDIT_ARG_RUID(wcred->sc_ruid);
+ ruip = uifind(wcred->sc_ruid);
+ }
+ if (flags & SETCREDF_SVUID)
+ AUDIT_ARG_SUID(wcred->sc_svuid);
+
+ if (flags & SETCREDF_GID)
+ AUDIT_ARG_EGID(wcred->sc_gid);
+ if (flags & SETCREDF_RGID)
+ AUDIT_ARG_RGID(wcred->sc_rgid);
+ if (flags & SETCREDF_SVGID)
+ AUDIT_ARG_SGID(wcred->sc_svgid);
+ if (flags & SETCREDF_SUPP_GROUPS) {
+ int ngrp = wcred->sc_supp_groups_nb;
+
+ /*
+ * Output the raw supplementary groups array for better
+ * traceability.
+ */
+ AUDIT_ARG_GROUPSET(groups + 1, ngrp);
+ ++ngrp;
+ groups_normalize(&ngrp, groups);
+ wcred->sc_supp_groups_nb = ngrp - 1;
+ }
+
+ /*
+ * We first completely build the new credentials and only then pass them
+ * to MAC along with the old ones so that modules can check whether the
+ * requested transition is allowed.
+ */
+ new_cred = crget();
+ to_free_cred = new_cred;
+ if (flags & SETCREDF_SUPP_GROUPS)
+ crextend(new_cred, wcred->sc_supp_groups_nb + 1);
+
+#ifdef MAC
+ mac_cred_setcred_enter();
+#endif
+
+ /*
+ * Part 2: We grab the process lock as to have a stable view of its
+ * current credentials, and prepare a copy of them with the requested
+ * changes applied under that lock.
+ */
+
+ PROC_LOCK(p);
+ old_cred = crcopysafe(p, new_cred);
+
+ /*
+ * Change user IDs.
+ */
+ if (flags & SETCREDF_UID)
+ change_euid(new_cred, uip);
+ if (flags & SETCREDF_RUID)
+ change_ruid(new_cred, ruip);
+ if (flags & SETCREDF_SVUID)
+ change_svuid(new_cred, wcred->sc_svuid);
+
+ /*
+ * Change groups.
+ *
+ * crsetgroups_internal() changes both the effective and supplementary
+ * ones.
+ */
+ if (flags & SETCREDF_SUPP_GROUPS) {
+ groups[0] = flags & SETCREDF_GID ? wcred->sc_gid :
+ new_cred->cr_gid;
+ crsetgroups_internal(new_cred, wcred->sc_supp_groups_nb + 1,
+ groups);
+ } else if (flags & SETCREDF_GID)
+ change_egid(new_cred, wcred->sc_gid);
+ if (flags & SETCREDF_RGID)
+ change_rgid(new_cred, wcred->sc_rgid);
+ if (flags & SETCREDF_SVGID)
+ change_svgid(new_cred, wcred->sc_svgid);
+
+#ifdef MAC
+ /*
+ * Change the MAC label.
+ */
+ if (flags & SETCREDF_MAC_LABEL) {
+ error = mac_set_proc_core(td, new_cred, mac_set_proc_data);
+ if (error != 0)
+ goto unlock_finish;
+ proc_label_set = true;
+ }
+
+ /*
+ * MAC security modules checks.
+ */
+ error = mac_cred_check_setcred(flags, old_cred, new_cred);
+ if (error != 0)
+ goto unlock_finish;
+#endif
+ /*
+ * Privilege check.
+ */
+ error = priv_check_cred(old_cred, PRIV_CRED_SETCRED);
+ if (error != 0)
+ goto unlock_finish;
+
+ /*
+ * Set the new credentials, noting that they have changed.
+ */
+ cred_set = proc_set_cred_enforce_proc_lim(p, new_cred);
+ if (cred_set) {
+ setsugid(p);
+ to_free_cred = old_cred;
+ MPASS(error == 0);
+ } else
+ error = EAGAIN;
+
+unlock_finish:
+ PROC_UNLOCK(p);
+ /*
+ * Part 3: After releasing the process lock, we perform cleanups and
+ * finishing operations.
+ */
+
+#ifdef MAC
+ if (mac_set_proc_data != NULL)
+ mac_set_proc_finish(td, proc_label_set, mac_set_proc_data);
+ mac_cred_setcred_exit();
+#endif
+ crfree(to_free_cred);
+ if (uip != NULL)
+ uifree(uip);
+ if (ruip != NULL)
+ uifree(ruip);
+free_groups:
+ if (groups != preallocated_groups && groups != smallgroups)
+ free(groups, M_TEMP); /* Deals with 'groups' being NULL. */
+ return (error);
+}
+
/*
* Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
* compatible. It says that setting the uid/gid to euid/egid is a special
@@ -859,15 +1160,6 @@
return (error);
}
-static int
-gidp_cmp(const void *p1, const void *p2)
-{
- const gid_t g1 = *(const gid_t *)p1;
- const gid_t g2 = *(const gid_t *)p2;
-
- return ((g1 > g2) - (g1 < g2));
-}
-
/*
* CAUTION: This function normalizes 'groups', possibly also changing the value
* of '*ngrpp' as a consequence.
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -595,4 +595,5 @@
"timerfd_settime", /* 587 = timerfd_settime */
"kcmp", /* 588 = kcmp */
"getrlimitusage", /* 589 = getrlimitusage */
+ "setcred", /* 590 = setcred */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3341,5 +3341,12 @@
_Out_ rlim_t *res
);
}
+590 AUE_SETCRED STD|CAPENABLED {
+ int setcred(
+ u_int flags,
+ _In_reads_bytes_(size) const void *wcred,
+ size_t size
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3465,6 +3465,15 @@
*n_args = 3;
break;
}
+ /* setcred */
+ case 590: {
+ struct setcred_args *p = params;
+ uarg[a++] = p->flags; /* u_int */
+ uarg[a++] = (intptr_t)p->wcred; /* const void * */
+ uarg[a++] = p->size; /* size_t */
+ *n_args = 3;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9271,6 +9280,22 @@
break;
};
break;
+ /* setcred */
+ case 590:
+ switch (ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11249,6 +11274,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* setcred */
+ case 590:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/security/mac/mac_cred.c b/sys/security/mac/mac_cred.c
--- a/sys/security/mac/mac_cred.c
+++ b/sys/security/mac/mac_cred.c
@@ -209,6 +209,55 @@
return (error);
}
+/*
+ * Entry hook for setcred().
+ *
+ * Called with no lock held by setcred() so that MAC modules may allocate memory
+ * in preparation for checking privileges. A call to this hook is always
+ * followed by a matching call to mac_cred_setcred_exit(). Between these two,
+ * setcred() may or may not call mac_cred_check_setcred().
+ */
+void
+mac_cred_setcred_enter(void)
+{
+
+ MAC_POLICY_PERFORM_NOSLEEP(cred_setcred_enter);
+}
+
+MAC_CHECK_PROBE_DEFINE3(cred_check_setcred, "unsigned int", "struct ucred *",
+ "struct ucred *");
+
+/*
+ * Check hook for setcred().
+ *
+ * When called, the current process' lock is held. It thus cannot perform
+ * memory allocations, which must be done in advance in
+ * mac_cred_setcred_enter(). It *MUST NOT* tamper with the process' lock.
+ */
+int
+mac_cred_check_setcred(u_int flags, const struct ucred *old_cred,
+ struct ucred *new_cred)
+{
+ int error;
+
+ MAC_POLICY_CHECK_NOSLEEP(cred_check_setcred, flags, old_cred, new_cred);
+ MAC_CHECK_PROBE3(cred_check_setcred, error, flags, old_cred, new_cred);
+
+ return (error);
+}
+
+/*
+ * Exit hook for setcred().
+ *
+ * Called with no lock held, exactly once per call to mac_cred_setcred_enter().
+ */
+void
+mac_cred_setcred_exit(void)
+{
+
+ MAC_POLICY_PERFORM_NOSLEEP(cred_setcred_exit);
+}
+
MAC_CHECK_PROBE_DEFINE2(cred_check_setuid, "struct ucred *", "uid_t");
int
diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h
--- a/sys/security/mac/mac_framework.h
+++ b/sys/security/mac/mac_framework.h
@@ -72,6 +72,7 @@
struct mount;
struct msg;
struct msqid_kernel;
+struct pipepair;
struct proc;
struct semid_kernel;
struct shmfd;
@@ -80,7 +81,6 @@
struct socket;
struct sysctl_oid;
struct sysctl_req;
-struct pipepair;
struct thread;
struct timespec;
struct ucred;
@@ -115,6 +115,10 @@
int mac_cred_check_setaudit_addr(struct ucred *cred,
struct auditinfo_addr *aia);
int mac_cred_check_setauid(struct ucred *cred, uid_t auid);
+void mac_cred_setcred_enter(void);
+int mac_cred_check_setcred(u_int flags, const struct ucred *old_cred,
+ struct ucred *new_cred);
+void mac_cred_setcred_exit(void);
int mac_cred_check_setegid(struct ucred *cred, gid_t egid);
int mac_cred_check_seteuid(struct ucred *cred, uid_t euid);
int mac_cred_check_setgid(struct ucred *cred, gid_t gid);
diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h
--- a/sys/security/mac/mac_policy.h
+++ b/sys/security/mac/mac_policy.h
@@ -144,6 +144,10 @@
typedef int (*mpo_cred_check_setaudit_addr_t)(struct ucred *cred,
struct auditinfo_addr *aia);
typedef int (*mpo_cred_check_setauid_t)(struct ucred *cred, uid_t auid);
+typedef void (*mpo_cred_setcred_enter_t)(void);
+typedef int (*mpo_cred_check_setcred_t)(u_int flags,
+ const struct ucred *old_cred, struct ucred *new_cred);
+typedef void (*mpo_cred_setcred_exit_t)(void);
typedef int (*mpo_cred_check_setegid_t)(struct ucred *cred, gid_t egid);
typedef int (*mpo_cred_check_seteuid_t)(struct ucred *cred, uid_t euid);
typedef int (*mpo_cred_check_setgid_t)(struct ucred *cred, gid_t gid);
@@ -720,6 +724,9 @@
mpo_cred_check_setaudit_t mpo_cred_check_setaudit;
mpo_cred_check_setaudit_addr_t mpo_cred_check_setaudit_addr;
mpo_cred_check_setauid_t mpo_cred_check_setauid;
+ mpo_cred_setcred_enter_t mpo_cred_setcred_enter;
+ mpo_cred_check_setcred_t mpo_cred_check_setcred;
+ mpo_cred_setcred_exit_t mpo_cred_setcred_exit;
mpo_cred_check_setuid_t mpo_cred_check_setuid;
mpo_cred_check_seteuid_t mpo_cred_check_seteuid;
mpo_cred_check_setgid_t mpo_cred_check_setgid;
@@ -1033,8 +1040,9 @@
* 3 7.x
* 4 8.x
* 5 14.x
+ * 6 15.x
*/
-#define MAC_VERSION 5
+#define MAC_VERSION 6
#define MAC_POLICY_SET(mpops, mpname, mpfullname, mpflags, privdata_wanted) \
static struct mac_policy_conf mpname##_mac_policy_conf = { \
diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c
--- a/sys/security/mac_stub/mac_stub.c
+++ b/sys/security/mac_stub/mac_stub.c
@@ -222,6 +222,26 @@
return (0);
}
+static void
+stub_cred_setcred_enter(void)
+{
+
+}
+
+static int
+stub_cred_check_setcred(u_int flags, const struct ucred *old_cred,
+ struct ucred *new_cred)
+{
+
+ return (0);
+}
+
+static void
+stub_cred_setcred_exit(void)
+{
+
+}
+
static int
stub_cred_check_setegid(struct ucred *cred, gid_t egid)
{
@@ -1688,6 +1708,9 @@
.mpo_cred_check_setaudit = stub_cred_check_setaudit,
.mpo_cred_check_setaudit_addr = stub_cred_check_setaudit_addr,
.mpo_cred_check_setauid = stub_cred_check_setauid,
+ .mpo_cred_setcred_enter = stub_cred_setcred_enter,
+ .mpo_cred_check_setcred = stub_cred_check_setcred,
+ .mpo_cred_setcred_exit = stub_cred_setcred_exit,
.mpo_cred_check_setegid = stub_cred_check_setegid,
.mpo_cred_check_seteuid = stub_cred_check_seteuid,
.mpo_cred_check_setgid = stub_cred_check_setgid,
diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c
--- a/sys/security/mac_test/mac_test.c
+++ b/sys/security/mac_test/mac_test.c
@@ -257,6 +257,35 @@
return (0);
}
+COUNTER_DECL(cred_setcred_enter);
+static void
+test_cred_setcred_enter(void)
+{
+
+ COUNTER_INC(cred_setcred_enter);
+}
+
+COUNTER_DECL(cred_check_setcred);
+static int
+test_cred_check_setcred(u_int flags, const struct ucred *old_cred,
+ struct ucred *new_cred)
+{
+
+ LABEL_CHECK(old_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(new_cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(cred_check_setcred);
+
+ return (0);
+}
+
+COUNTER_DECL(cred_setcred_exit);
+static void
+test_cred_setcred_exit(void)
+{
+
+ COUNTER_INC(cred_setcred_exit);
+}
+
COUNTER_DECL(cred_check_setegid);
static int
test_cred_check_setegid(struct ucred *cred, gid_t egid)
@@ -3033,6 +3062,9 @@
.mpo_cred_check_setaudit = test_cred_check_setaudit,
.mpo_cred_check_setaudit_addr = test_cred_check_setaudit_addr,
.mpo_cred_check_setauid = test_cred_check_setauid,
+ .mpo_cred_setcred_enter = test_cred_setcred_enter,
+ .mpo_cred_check_setcred = test_cred_check_setcred,
+ .mpo_cred_setcred_exit = test_cred_setcred_exit,
.mpo_cred_check_seteuid = test_cred_check_seteuid,
.mpo_cred_check_setegid = test_cred_check_setegid,
.mpo_cred_check_setgid = test_cred_check_setgid,
diff --git a/sys/sys/priv.h b/sys/sys/priv.h
--- a/sys/sys/priv.h
+++ b/sys/sys/priv.h
@@ -105,7 +105,8 @@
#define PRIV_CRED_SETRESGID 58 /* setresgid. */
#define PRIV_SEEOTHERGIDS 59 /* Exempt bsd.seeothergids. */
#define PRIV_SEEOTHERUIDS 60 /* Exempt bsd.seeotheruids. */
-#define PRIV_SEEJAILPROC 61 /* Exempt from bsd.see_jail_proc. */
+#define PRIV_SEEJAILPROC 61 /* Exempt from bsd.see_jail_proc. */
+#define PRIV_CRED_SETCRED 62 /* setcred. */
/*
* Debugging privileges.
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -526,4 +526,5 @@
#define SYS_timerfd_settime 587
#define SYS_kcmp 588
#define SYS_getrlimitusage 589
-#define SYS_MAXSYSCALL 590
+#define SYS_setcred 590
+#define SYS_MAXSYSCALL 591
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -432,4 +432,5 @@
timerfd_gettime.o \
timerfd_settime.o \
kcmp.o \
- getrlimitusage.o
+ getrlimitusage.o \
+ setcred.o
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -320,6 +320,8 @@
fd_set *fd_ex, struct timeval *tvp, int abi_nfdbits);
int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
struct mbuf *control, enum uio_seg segflg);
+int kern_setcred_v0(struct thread *const td, const u_int flags,
+ struct setcred_v0 *const wcred, gid_t *preallocated_groups);
int kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups);
int kern_setitimer(struct thread *, u_int, struct itimerval *,
struct itimerval *);
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1882,6 +1882,11 @@
char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
char res_l_[PADL_(rlim_t *)]; rlim_t * res; char res_r_[PADR_(rlim_t *)];
};
+struct setcred_args {
+ char flags_l_[PADL_(u_int)]; u_int flags; char flags_r_[PADR_(u_int)];
+ char wcred_l_[PADL_(const void *)]; const void * wcred; char wcred_r_[PADR_(const void *)];
+ char size_l_[PADL_(size_t)]; size_t size; char size_r_[PADR_(size_t)];
+};
int sys_exit(struct thread *, struct exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2282,6 +2287,7 @@
int sys_timerfd_settime(struct thread *, struct timerfd_settime_args *);
int sys_kcmp(struct thread *, struct kcmp_args *);
int sys_getrlimitusage(struct thread *, struct getrlimitusage_args *);
+int sys_setcred(struct thread *, struct setcred_args *);
#ifdef COMPAT_43
@@ -3262,6 +3268,7 @@
#define SYS_AUE_timerfd_settime AUE_TIMERFD
#define SYS_AUE_kcmp AUE_NULL
#define SYS_AUE_getrlimitusage AUE_NULL
+#define SYS_AUE_setcred AUE_SETCRED
#undef PAD_
#undef PADL_
diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h
--- a/sys/sys/ucred.h
+++ b/sys/sys/ucred.h
@@ -32,6 +32,7 @@
#ifndef _SYS_UCRED_H_
#define _SYS_UCRED_H_
+#include <sys/types.h>
#if defined(_KERNEL) || defined(_WANT_UCRED)
#include <sys/_lock.h>
#include <sys/_mutex.h>
@@ -39,8 +40,6 @@
#include <bsm/audit.h>
#if defined(_KERNEL) || defined(_WANT_UCRED)
-struct loginclass;
-
/*
* Flags for cr_flags.
*/
@@ -53,6 +52,11 @@
*/
#define CRED_SMALLGROUPS_NB 16
+struct label;
+struct loginclass;
+struct prison;
+struct uidinfo;
+
/*
* Credentials.
*
@@ -119,7 +123,50 @@
/* This can be used for both ucred and xucred structures. */
#define cr_gid cr_groups[0]
+struct mac;
+/*
+ * Structure to pass as an argument to the setcred() system call.
+ */
+struct setcred_v0 {
+ uid_t sc_uid; /* effective user id */
+ uid_t sc_ruid; /* real user id */
+ uid_t sc_svuid; /* saved user id */
+ gid_t sc_gid; /* effective group id */
+ gid_t sc_rgid; /* real group id */
+ gid_t sc_svgid; /* saved group id */
+ int sc_supp_groups_nb; /* number of supplementary groups */
+ gid_t *sc_supp_groups; /* supplementary groups */
+ struct mac *sc_label; /* MAC label */
+};
+
+/*
+ * Flags to setcred().
+ *
+ * Descending order to leave room for more version bits (if ever needed).
+ */
+#define SETCREDF_UID (1u << 31)
+#define SETCREDF_RUID (1u << 30)
+#define SETCREDF_SVUID (1u << 29)
+#define SETCREDF_GID (1u << 28)
+#define SETCREDF_RGID (1u << 27)
+#define SETCREDF_SVGID (1u << 26)
+#define SETCREDF_SUPP_GROUPS (1u << 25)
+#define SETCREDF_MAC_LABEL (1u << 24)
+
+#define SETCREDF_FROM_VERSION(version) (((u_int)version) & 0xFF)
+#define SETCREDF_TO_VERSION(flags) ((flags) & 0xFF)
+
#ifdef _KERNEL
+/*
+ * Masks of the currently valid flags to setcred() (v0). As new versions are
+ * added, they may or may not use the same flags.
+ */
+#define SETCREDF_VERSION_BITS (0xFF)
+#define SETCREDF_SET_MASK (SETCREDF_UID | SETCREDF_RUID | SETCREDF_SVUID | \
+ SETCREDF_GID | SETCREDF_RGID | SETCREDF_SVGID | SETCREDF_SUPP_GROUPS | \
+ SETCREDF_MAC_LABEL)
+#define SETCREDF_MASK (SETCREDF_SET_MASK | SETCREDF_VERSION_BITS)
+
struct proc;
struct thread;
@@ -183,6 +230,13 @@
bool group_is_supplementary(const gid_t gid, const struct ucred *const cred);
bool groupmember(gid_t gid, const struct ucred *cred);
bool realgroupmember(gid_t gid, const struct ucred *cred);
+
+#else /* !_KERNEL */
+
+__BEGIN_DECLS
+int setcred(u_int flags, const void *wcred, size_t size);
+__END_DECLS
+
#endif /* _KERNEL */
#endif /* !_SYS_UCRED_H_ */

File Metadata

Mime Type
text/plain
Expires
Mon, May 18, 10:22 PM (18 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33271995
Default Alt Text
D47618.id146551.diff (27 KB)

Event Timeline