Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157006623
D47618.id146551.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
D47618.id146551.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D47618: New setcred() system call and associated MAC hooks
Attached
Detach File
Event Timeline
Log In to Comment