|
@@ -1459,6 +1459,23 @@ static int do_execve_common(const char *filename,
|
|
|
struct files_struct *displaced;
|
|
|
bool clear_in_exec;
|
|
|
int retval;
|
|
|
+ const struct cred *cred = current_cred();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We move the actual failure in case of RLIMIT_NPROC excess from
|
|
|
+ * set*uid() to execve() because too many poorly written programs
|
|
|
+ * don't check setuid() return code. Here we additionally recheck
|
|
|
+ * whether NPROC limit is still exceeded.
|
|
|
+ */
|
|
|
+ if ((current->flags & PF_NPROC_EXCEEDED) &&
|
|
|
+ atomic_read(&cred->user->processes) > rlimit(RLIMIT_NPROC)) {
|
|
|
+ retval = -EAGAIN;
|
|
|
+ goto out_ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* We're below the limit (still or again), so we don't want to make
|
|
|
+ * further execve() calls fail. */
|
|
|
+ current->flags &= ~PF_NPROC_EXCEEDED;
|
|
|
|
|
|
retval = unshare_files(&displaced);
|
|
|
if (retval)
|