Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F98797940
D46923.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D46923.diff
View Options
diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c
--- a/sys/fs/unionfs/union_subr.c
+++ b/sys/fs/unionfs/union_subr.c
@@ -920,11 +920,6 @@
/* Authority change to root */
rootinfo = uifind((uid_t)0);
cred = crdup(cnp->cn_cred);
- /*
- * The calls to chgproccnt() are needed to compensate for change_ruid()
- * calling chgproccnt().
- */
- chgproccnt(cred->cr_ruidinfo, 1, 0);
change_euid(cred, rootinfo);
change_ruid(cred, rootinfo);
change_svuid(cred, (uid_t)0);
@@ -1046,7 +1041,6 @@
unionfs_mkshadowdir_finish:
unionfs_clear_in_progress_flag(vp, UNIONFS_COPY_IN_PROGRESS);
cnp->cn_cred = credbk;
- chgproccnt(cred->cr_ruidinfo, -1, 0);
crfree(cred);
return (error);
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -999,11 +999,6 @@
ruadd(&q->p_stats->p_cru, &q->p_crux, &p->p_ru, &p->p_rux);
PROC_UNLOCK(q);
- /*
- * Decrement the count of procs running with this uid.
- */
- (void)chgproccnt(p->p_ucred->cr_ruidinfo, -1, 0);
-
/*
* Destroy resource accounting information associated with the process.
*/
@@ -1017,9 +1012,10 @@
racct_proc_exit(p);
/*
- * Free credentials, arguments, and sigacts.
+ * Free credentials, arguments, and sigacts, and decrement the count of
+ * processes running with this uid.
*/
- proc_unset_cred(p);
+ proc_unset_cred(p, true);
pargs_drop(p->p_args);
p->p_args = NULL;
sigacts_free(p->p_sigacts);
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1085,7 +1085,7 @@
#endif
racct_proc_exit(newproc);
fail1:
- proc_unset_cred(newproc);
+ proc_unset_cred(newproc, false);
fail2:
if (vm2 != NULL)
vmspace_free(vm2);
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
@@ -568,7 +568,7 @@
#endif
{
/*
- * Set the real uid and transfer proc count to new user.
+ * Set the real uid.
*/
if (uid != oldcred->cr_ruid) {
change_ruid(newcred, uip);
@@ -594,6 +594,9 @@
change_euid(newcred, uip);
setsugid(p);
}
+ /*
+ * This also transfers the proc count to the new user.
+ */
proc_set_cred(p, newcred);
#ifdef RACCT
racct_proc_ucred_changed(p, oldcred, newcred);
@@ -2236,31 +2239,76 @@
/*
* Change process credentials.
+ *
* Callers are responsible for providing the reference for passed credentials
- * and for freeing old ones.
+ * and for freeing old ones. Calls chgproccnt() to correctly account the
+ * current process to the proper real UID, if the latter has changed. Returns
+ * whether the operation was successful. Failure can happen only on
+ * 'enforce_proc_lim' being true and if no new process can be accounted to the
+ * new real UID because of the current limit (see the inner comment for more
+ * details) and the caller does not have privilege (PRIV_PROC_LIMIT) to override
+ * that.
*/
-void
-proc_set_cred(struct proc *p, struct ucred *newcred)
+static bool
+_proc_set_cred(struct proc *p, struct ucred *newcred, bool enforce_proc_lim)
{
- struct ucred *cr;
+ struct ucred *const oldcred = p->p_ucred;
- cr = p->p_ucred;
- MPASS(cr != NULL);
+ MPASS(oldcred != NULL);
PROC_LOCK_ASSERT(p, MA_OWNED);
KASSERT(newcred->cr_users == 0, ("%s: users %d not 0 on cred %p",
__func__, newcred->cr_users, newcred));
- mtx_lock(&cr->cr_mtx);
- KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
- __func__, cr->cr_users, cr));
- cr->cr_users--;
- mtx_unlock(&cr->cr_mtx);
+ KASSERT(newcred->cr_ref == 1, ("%s: ref %ld not 1 on cred %p",
+ __func__, newcred->cr_ref, newcred));
+
+ if (newcred->cr_ruidinfo != oldcred->cr_ruidinfo) {
+ /*
+ * XXXOC: This check is flawed but nonetheless the best we can
+ * currently do as we don't really track limits per UID contrary
+ * to what we pretend in setrlimit(2). Until this is reworked,
+ * we just check here that the number of processes for our new
+ * real UID doesn't exceed this process' process number limit
+ * (which is meant to be associated with the current real UID).
+ */
+ const int proccnt_changed = chgproccnt(newcred->cr_ruidinfo, 1,
+ enforce_proc_lim ? lim_cur_proc(p, RLIMIT_NPROC) : 0);
+
+ if (!proccnt_changed) {
+ if (priv_check_cred(oldcred, PRIV_PROC_LIMIT) != 0)
+ return (false);
+ (void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
+ }
+ }
+
+ mtx_lock(&oldcred->cr_mtx);
+ KASSERT(oldcred->cr_users > 0, ("%s: users %d not > 0 on cred %p",
+ __func__, oldcred->cr_users, oldcred));
+ oldcred->cr_users--;
+ mtx_unlock(&oldcred->cr_mtx);
p->p_ucred = newcred;
newcred->cr_users = 1;
PROC_UPDATE_COW(p);
+ if (newcred->cr_ruidinfo != oldcred->cr_ruidinfo)
+ (void)chgproccnt(oldcred->cr_ruidinfo, -1, 0);
+ return (true);
}
void
-proc_unset_cred(struct proc *p)
+proc_set_cred(struct proc *p, struct ucred *newcred)
+{
+ bool success = _proc_set_cred(p, newcred, false);
+
+ MPASS(success);
+}
+
+bool
+proc_set_cred_enforce_proc_lim(struct proc *p, struct ucred *newcred)
+{
+ return (_proc_set_cred(p, newcred, true));
+}
+
+void
+proc_unset_cred(struct proc *p, bool decrement_proc_count)
{
struct ucred *cr;
@@ -2275,6 +2323,8 @@
KASSERT(cr->cr_ref > 0, ("%s: ref %ld not > 0 on cred %p",
__func__, cr->cr_ref, cr));
mtx_unlock(&cr->cr_mtx);
+ if (decrement_proc_count)
+ (void)chgproccnt(cr->cr_ruidinfo, -1, 0);
crfree(cr);
}
@@ -2574,8 +2624,7 @@
/*-
* Change a process's real uid.
* Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
- * will be updated, and the old and new cr_ruidinfo proc
- * counts will be updated.
+ * will be updated.
* References: newcred must be an exclusive credential reference for the
* duration of the call.
*/
@@ -2583,12 +2632,10 @@
change_ruid(struct ucred *newcred, struct uidinfo *ruip)
{
- (void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
newcred->cr_ruid = ruip->ui_uid;
uihold(ruip);
uifree(newcred->cr_ruidinfo);
newcred->cr_ruidinfo = ruip;
- (void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
}
/*-
diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h
--- a/sys/sys/ucred.h
+++ b/sys/sys/ucred.h
@@ -154,8 +154,9 @@
struct ucred *crcopysafe(struct proc *p, struct ucred *cr);
struct ucred *crdup(struct ucred *cr);
void crextend(struct ucred *cr, int n);
-void proc_set_cred(struct proc *p, struct ucred *cr);
-void proc_unset_cred(struct proc *p);
+void proc_set_cred(struct proc *p, struct ucred *newcred);
+bool proc_set_cred_enforce_proc_lim(struct proc *p, struct ucred *newcred);
+void proc_unset_cred(struct proc *p, bool decrement_proc_count);
void crfree(struct ucred *cr);
struct ucred *crcowsync(void);
struct ucred *crget(void);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Oct 5, 7:21 PM (21 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
13668556
Default Alt Text
D46923.diff (6 KB)
Attached To
Mode
D46923: cred: proc_set_cred(), proc_unset_cred(): Update user's process count
Attached
Detach File
Event Timeline
Log In to Comment