lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1473244055-25240-3-git-send-email-yauheni.kaliuta@redhat.com>
Date:   Wed,  7 Sep 2016 13:27:35 +0300
From:   Yauheni Kaliuta <yauheni.kaliuta@...hat.com>
To:     linux-kernel@...r.kernel.org
Cc:     aris@...hat.com, jolsa@...hat.com
Subject: [PATCH RFC 2/2] rlimits: report resource limits violations

The patch instrument different places of resource limits checks with
reporting using the infrastructure from the previous patch.

Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@...hat.com>
---
 arch/ia64/kernel/perfmon.c                 |  4 +++-
 arch/powerpc/kvm/book3s_64_vio.c           |  6 ++++--
 arch/powerpc/mm/mmu_context_iommu.c        |  6 ++++--
 drivers/android/binder.c                   |  7 ++++++-
 drivers/infiniband/core/umem.c             |  1 +
 drivers/infiniband/hw/hfi1/user_pages.c    |  5 ++++-
 drivers/infiniband/hw/qib/qib_user_pages.c |  1 +
 drivers/infiniband/hw/usnic/usnic_uiom.c   |  1 +
 drivers/misc/mic/scif/scif_rma.c           |  1 +
 drivers/vfio/vfio_iommu_spapr_tce.c        |  6 ++++--
 drivers/vfio/vfio_iommu_type1.c            |  4 ++++
 fs/attr.c                                  |  4 +++-
 fs/binfmt_aout.c                           |  4 +++-
 fs/binfmt_flat.c                           |  1 +
 fs/coredump.c                              |  4 +++-
 fs/exec.c                                  | 14 ++++++++++----
 fs/file.c                                  | 26 +++++++++++++++++++++-----
 fs/select.c                                |  4 +++-
 include/linux/mm.h                         |  7 ++++++-
 ipc/mqueue.c                               | 10 ++++++++--
 ipc/shm.c                                  |  1 +
 kernel/bpf/syscall.c                       | 15 ++++++++++++---
 kernel/events/core.c                       |  1 +
 kernel/fork.c                              |  9 ++++++---
 kernel/sched/core.c                        | 17 +++++++++++++----
 kernel/signal.c                            |  7 ++++---
 kernel/sys.c                               |  9 ++++++---
 kernel/time/posix-cpu-timers.c             |  8 ++++++++
 mm/mlock.c                                 | 14 +++++++++++++-
 mm/mmap.c                                  | 19 +++++++++++++++----
 mm/mremap.c                                |  4 +++-
 net/unix/af_unix.c                         |  9 ++++++---
 32 files changed, 179 insertions(+), 50 deletions(-)

diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 2436ad5f92c1..c765e94a7089 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2259,8 +2259,10 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
 	 * if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur)
 	 * 	return -ENOMEM;
 	 */
-	if (size > task_rlimit(task, RLIMIT_MEMLOCK))
+	if (size > task_rlimit(task, RLIMIT_MEMLOCK)) {
+		rlimit_exceeded_task(RLIMIT_MEMLOCK, size, task);
 		return -ENOMEM;
+	}
 
 	/*
 	 * We do the easy to undo allocations first.
diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c
index c379ff5a4438..a0477260d398 100644
--- a/arch/powerpc/kvm/book3s_64_vio.c
+++ b/arch/powerpc/kvm/book3s_64_vio.c
@@ -67,10 +67,12 @@ static long kvmppc_account_memlimit(unsigned long stt_pages, bool inc)
 
 		locked = current->mm->locked_vm + stt_pages;
 		lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
+		if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+			rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 			ret = -ENOMEM;
-		else
+		} else {
 			current->mm->locked_vm += stt_pages;
+		}
 	} else {
 		if (WARN_ON_ONCE(stt_pages > current->mm->locked_vm))
 			stt_pages = current->mm->locked_vm;
diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c
index da6a2168ae9e..421890d325df 100644
--- a/arch/powerpc/mm/mmu_context_iommu.c
+++ b/arch/powerpc/mm/mmu_context_iommu.c
@@ -42,10 +42,12 @@ static long mm_iommu_adjust_locked_vm(struct mm_struct *mm,
 	if (incr) {
 		locked = mm->locked_vm + npages;
 		lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
+		if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+			rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 			ret = -ENOMEM;
-		else
+		} else {
 			mm->locked_vm += npages;
+		}
 	} else {
 		if (WARN_ON_ONCE(npages > mm->locked_vm))
 			npages = mm->locked_vm;
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 16288e777ec3..a44021051a02 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -379,6 +379,7 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
 	struct files_struct *files = proc->files;
 	unsigned long rlim_cur;
 	unsigned long irqs;
+	int ret;
 
 	if (files == NULL)
 		return -ESRCH;
@@ -389,7 +390,11 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
 	rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE);
 	unlock_task_sighand(proc->tsk, &irqs);
 
-	return __alloc_fd(files, 0, rlim_cur, flags);
+	ret = __alloc_fd(files, 0, rlim_cur, flags);
+	if (ret == -EMFILE)
+		rlimit_exceeded_task(RLIMIT_NOFILE, (u64)-1, proc->tsk);
+
+	return ret;
 }
 
 /*
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index c68746ce6624..8d7746b3a5c9 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -168,6 +168,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
 	lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
 
 	if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
+		rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 		ret = -ENOMEM;
 		goto out;
 	}
diff --git a/drivers/infiniband/hw/hfi1/user_pages.c b/drivers/infiniband/hw/hfi1/user_pages.c
index 20f4ddcac3b0..1f510a13ed3b 100644
--- a/drivers/infiniband/hw/hfi1/user_pages.c
+++ b/drivers/infiniband/hw/hfi1/user_pages.c
@@ -95,8 +95,11 @@ bool hfi1_can_pin_pages(struct hfi1_devdata *dd, struct mm_struct *mm,
 	up_read(&mm->mmap_sem);
 
 	/* First, check the absolute limit against all pinned pages. */
-	if (pinned + npages >= ulimit && !can_lock)
+	if (pinned + npages >= ulimit && !can_lock) {
+		/* if it's in pages, should be converted to bytes? */
+		rlimit_exceeded(RLIMIT_MEMLOCK, pinned + npages);
 		return false;
+	}
 
 	return ((nlocked + npages) <= size) || can_lock;
 }
diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c
index 2d2b94fd3633..649a0a1317bb 100644
--- a/drivers/infiniband/hw/qib/qib_user_pages.c
+++ b/drivers/infiniband/hw/qib/qib_user_pages.c
@@ -61,6 +61,7 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages,
 	lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
 
 	if (num_pages > lock_limit && !capable(CAP_IPC_LOCK)) {
+		rlimit_exceeded(RLIMIT_MEMLOCK, num_pages << PAGE_SHIFT);
 		ret = -ENOMEM;
 		goto bail;
 	}
diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c
index a0b6ebee4d8a..11367fcc238b 100644
--- a/drivers/infiniband/hw/usnic/usnic_uiom.c
+++ b/drivers/infiniband/hw/usnic/usnic_uiom.c
@@ -129,6 +129,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
 	lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
 
 	if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
+		rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 		ret = -ENOMEM;
 		goto out;
 	}
diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c
index e0203b1a20fd..0e83d14cda06 100644
--- a/drivers/misc/mic/scif/scif_rma.c
+++ b/drivers/misc/mic/scif/scif_rma.c
@@ -303,6 +303,7 @@ static inline int __scif_check_inc_pinned_vm(struct mm_struct *mm,
 		dev_err(scif_info.mdev.this_device,
 			"locked(%lu) > lock_limit(%lu)\n",
 			locked, lock_limit);
+		rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 		return -ENOMEM;
 	}
 	mm->pinned_vm = locked;
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
index 80378ddadc5c..5ff1773b01f4 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -44,10 +44,12 @@ static long try_increment_locked_vm(long npages)
 	down_write(&current->mm->mmap_sem);
 	locked = current->mm->locked_vm + npages;
 	lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-	if (locked > lock_limit && !capable(CAP_IPC_LOCK))
+	if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+		rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 		ret = -ENOMEM;
-	else
+	} else {
 		current->mm->locked_vm += npages;
+	}
 
 	pr_debug("[%d] RLIMIT_MEMLOCK +%ld %ld/%ld%s\n", current->pid,
 			npages << PAGE_SHIFT,
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 2ba19424e4a1..6929c0eaac9d 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -280,6 +280,8 @@ static long vfio_pin_pages(unsigned long vaddr, long npage,
 		put_pfn(*pfn_base, prot);
 		pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__,
 			limit << PAGE_SHIFT);
+		rlimit_exceeded(RLIMIT_MEMLOCK,
+				(current->mm->locked_vm + 1) << PAGE_SHIFT);
 		return -ENOMEM;
 	}
 
@@ -308,6 +310,8 @@ static long vfio_pin_pages(unsigned long vaddr, long npage,
 			put_pfn(pfn, prot);
 			pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
 				__func__, limit << PAGE_SHIFT);
+			rlimit_exceeded(RLIMIT_MEMLOCK,
+					(current->mm->locked_vm + i + 1) << PAGE_SHIFT);
 			break;
 		}
 	}
diff --git a/fs/attr.c b/fs/attr.c
index 42bb42bb3c72..62d3de88ab42 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -102,8 +102,10 @@ int inode_newsize_ok(const struct inode *inode, loff_t offset)
 		unsigned long limit;
 
 		limit = rlimit(RLIMIT_FSIZE);
-		if (limit != RLIM_INFINITY && offset > limit)
+		if (limit != RLIM_INFINITY && offset > limit) {
+			rlimit_exceeded(RLIMIT_FSIZE, offset);
 			goto out_sig;
+		}
 		if (offset > inode->i_sb->s_maxbytes)
 			goto out_big;
 	} else {
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index ae1b5404fced..9041ef2d419a 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -228,8 +228,10 @@ static int load_aout_binary(struct linux_binprm * bprm)
 	rlim = rlimit(RLIMIT_DATA);
 	if (rlim >= RLIM_INFINITY)
 		rlim = ~0;
-	if (ex.a_data + ex.a_bss > rlim)
+	if (ex.a_data + ex.a_bss > rlim) {
+		rlimit_exceeded(RLIMIT_DATA, data_len + bss_len);
 		return -ENOMEM;
+	}
 
 	/* Flush all traces of the currently running executable */
 	retval = flush_old_exec(bprm);
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 9b2917a30294..042864d44dff 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -512,6 +512,7 @@ static int load_flat_file(struct linux_binprm *bprm,
 	if (rlim >= RLIM_INFINITY)
 		rlim = ~0;
 	if (data_len + bss_len > rlim) {
+		rlimit_exceeded(RLIMIT_DATA, data_len + bss_len);
 		ret = -ENOMEM;
 		goto err;
 	}
diff --git a/fs/coredump.c b/fs/coredump.c
index 281b768000e6..8c7b6cadf262 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -784,8 +784,10 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr)
 	struct file *file = cprm->file;
 	loff_t pos = file->f_pos;
 	ssize_t n;
-	if (cprm->written + nr > cprm->limit)
+	if (cprm->written + nr > cprm->limit) {
+		rlimit_exceeded(RLIMIT_CORE, cprm->written + nr);
 		return 0;
+	}
 	while (nr) {
 		if (dump_interrupted())
 			return 0;
diff --git a/fs/exec.c b/fs/exec.c
index 6fcfb3f7b137..6edc0eeeece0 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -230,6 +230,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
 		 */
 		rlim = current->signal->rlim;
 		if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
+			/* should it be reported somehow? */
 			put_page(page);
 			return NULL;
 		}
@@ -1650,10 +1651,15 @@ static int do_execveat_common(int fd, struct filename *filename,
 	 * don't check setuid() return code.  Here we additionally recheck
 	 * whether NPROC limit is still exceeded.
 	 */
-	if ((current->flags & PF_NPROC_EXCEEDED) &&
-	    atomic_read(&current_user()->processes) > rlimit(RLIMIT_NPROC)) {
-		retval = -EAGAIN;
-		goto out_ret;
+	if (current->flags & PF_NPROC_EXCEEDED) {
+		int nproc;
+
+		nproc = atomic_read(&current_user()->processes);
+		if (nproc > rlimit(RLIMIT_NPROC)) {
+			rlimit_exceeded(RLIMIT_NPROC, nproc);
+			retval = -EAGAIN;
+			goto out_ret;
+		}
 	}
 
 	/* We're below the limit (still or again), so we don't want to make
diff --git a/fs/file.c b/fs/file.c
index 6b1acdfe59da..d76fbb15e4ec 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -554,12 +554,22 @@ out:
 
 static int alloc_fd(unsigned start, unsigned flags)
 {
-	return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
+	int ret;
+
+	ret = __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
+	if (ret == -EMFILE)
+		rlimit_exceeded(RLIMIT_NOFILE, (u64)-1);
+	return ret;
 }
 
 int get_unused_fd_flags(unsigned flags)
 {
-	return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
+	int ret;
+
+	ret = __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
+	if (ret == -EMFILE)
+		rlimit_exceeded(RLIMIT_NOFILE, (u64)-1);
+	return ret;
 }
 EXPORT_SYMBOL(get_unused_fd_flags);
 
@@ -872,8 +882,10 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
 	if (!file)
 		return __close_fd(files, fd);
 
-	if (fd >= rlimit(RLIMIT_NOFILE))
+	if (fd >= rlimit(RLIMIT_NOFILE)) {
+		rlimit_exceeded(RLIMIT_NOFILE, fd);
 		return -EBADF;
+	}
 
 	spin_lock(&files->file_lock);
 	err = expand_files(files, fd);
@@ -898,8 +910,10 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
 	if (unlikely(oldfd == newfd))
 		return -EINVAL;
 
-	if (newfd >= rlimit(RLIMIT_NOFILE))
+	if (newfd >= rlimit(RLIMIT_NOFILE)) {
+		rlimit_exceeded(RLIMIT_NOFILE, newfd);
 		return -EBADF;
+	}
 
 	spin_lock(&files->file_lock);
 	err = expand_files(files, newfd);
@@ -953,8 +967,10 @@ SYSCALL_DEFINE1(dup, unsigned int, fildes)
 int f_dupfd(unsigned int from, struct file *file, unsigned flags)
 {
 	int err;
-	if (from >= rlimit(RLIMIT_NOFILE))
+	if (from >= rlimit(RLIMIT_NOFILE)) {
+		rlimit_exceeded(RLIMIT_NOFILE, from);
 		return -EINVAL;
+	}
 	err = alloc_fd(from, flags);
 	if (err >= 0) {
 		get_file(file);
diff --git a/fs/select.c b/fs/select.c
index 8ed9da50896a..adb057ce7897 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -886,8 +886,10 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
  	struct poll_list *walk = head;
  	unsigned long todo = nfds;
 
-	if (nfds > rlimit(RLIMIT_NOFILE))
+	if (nfds > rlimit(RLIMIT_NOFILE)) {
+		rlimit_exceeded(RLIMIT_NOFILE, nfds);
 		return -EINVAL;
+	}
 
 	len = min_t(unsigned int, nfds, N_STACK_PPS);
 	for (;;) {
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ef815b9cd426..1ef5ed878895 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2002,8 +2002,13 @@ static inline int check_data_rlimit(unsigned long rlim,
 				    unsigned long start_data)
 {
 	if (rlim < RLIM_INFINITY) {
-		if (((new - start) + (end_data - start_data)) > rlim)
+		unsigned long data_size;
+
+		data_size = (new - start) + (end_data - start_data);
+		if (data_size > rlim) {
+			rlimit_exceeded(RLIMIT_DATA, data_size);
 			return -ENOSPC;
+		}
 	}
 
 	return 0;
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 0b13ace266f2..85ac1b643522 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -275,13 +275,19 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
 					  info->attr.mq_msgsize);
 
 		spin_lock(&mq_lock);
-		if (u->mq_bytes + mq_bytes < u->mq_bytes ||
-		    u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) {
+		if (u->mq_bytes + mq_bytes < u->mq_bytes) {
 			spin_unlock(&mq_lock);
 			/* mqueue_evict_inode() releases info->messages */
 			ret = -EMFILE;
 			goto out_inode;
 		}
+		if (u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) {
+			spin_unlock(&mq_lock);
+			rlimit_exceeded(RLIMIT_MSGQUEUE, u->mq_bytes + mq_bytes);
+			/* mqueue_evict_inode() releases info->messages */
+			ret = -EMFILE;
+			goto out_inode;
+		}
 		u->mq_bytes += mq_bytes;
 		spin_unlock(&mq_lock);
 
diff --git a/ipc/shm.c b/ipc/shm.c
index dbac8860c721..640f17ae6094 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1034,6 +1034,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
 				goto out_unlock0;
 			}
 			if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) {
+				rlimit_exceeded(RLIMIT_MEMLOCK, (u64)-1);
 				err = -EPERM;
 				goto out_unlock0;
 			}
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 228f962447a5..8494c1fe921e 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -56,8 +56,11 @@ int bpf_map_precharge_memlock(u32 pages)
 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
 	cur = atomic_long_read(&user->locked_vm);
 	free_uid(user);
-	if (cur + pages > memlock_limit)
+	if (cur + pages > memlock_limit) {
+		rlimit_exceeded(RLIMIT_MEMLOCK,
+				(cur + pages) << PAGE_SHIFT);
 		return -EPERM;
+	}
 	return 0;
 }
 
@@ -65,14 +68,17 @@ static int bpf_map_charge_memlock(struct bpf_map *map)
 {
 	struct user_struct *user = get_current_user();
 	unsigned long memlock_limit;
+	int npages;
 
 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
 
 	atomic_long_add(map->pages, &user->locked_vm);
 
-	if (atomic_long_read(&user->locked_vm) > memlock_limit) {
+	npages = atomic_long_read(&user->locked_vm);
+	if (npages > memlock_limit) {
 		atomic_long_sub(map->pages, &user->locked_vm);
 		free_uid(user);
+		rlimit_exceeded(RLIMIT_MEMLOCK, npages << PAGE_SHIFT);
 		return -EPERM;
 	}
 	map->user = user;
@@ -603,13 +609,16 @@ static int bpf_prog_charge_memlock(struct bpf_prog *prog)
 {
 	struct user_struct *user = get_current_user();
 	unsigned long memlock_limit;
+	int npages;
 
 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
 
 	atomic_long_add(prog->pages, &user->locked_vm);
-	if (atomic_long_read(&user->locked_vm) > memlock_limit) {
+	npages = atomic_long_read(&user->locked_vm);
+	if (npages > memlock_limit) {
 		atomic_long_sub(prog->pages, &user->locked_vm);
 		free_uid(user);
+		rlimit_exceeded(RLIMIT_MEMLOCK, npages << PAGE_SHIFT);
 		return -EPERM;
 	}
 	prog->aux->user = user;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 3cfabdf7b942..b74bf90d1fd4 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5166,6 +5166,7 @@ accounting:
 
 	if ((locked > lock_limit) && perf_paranoid_tracepoint_raw() &&
 		!capable(CAP_IPC_LOCK)) {
+		rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 		ret = -EPERM;
 		goto unlock;
 	}
diff --git a/kernel/fork.c b/kernel/fork.c
index beb31725f7e2..a80f2e11788d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1307,6 +1307,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 {
 	int retval;
 	struct task_struct *p;
+	int nproc;
 
 	if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
 		return ERR_PTR(-EINVAL);
@@ -1368,11 +1369,13 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
 #endif
 	retval = -EAGAIN;
-	if (atomic_read(&p->real_cred->user->processes) >=
-			task_rlimit(p, RLIMIT_NPROC)) {
+	nproc = atomic_read(&p->real_cred->user->processes);
+	if (nproc >= task_rlimit(p, RLIMIT_NPROC)) {
 		if (p->real_cred->user != INIT_USER &&
-		    !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
+		    !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
+			rlimit_exceeded_task(RLIMIT_NPROC, nproc, p);
 			goto bad_fork_free;
+		}
 	}
 	current->flags &= ~PF_NPROC_EXCEEDED;
 
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 2a906f20fba7..1c66b3088684 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3736,9 +3736,13 @@ int can_nice(const struct task_struct *p, const int nice)
 {
 	/* convert nice value [19,-20] to rlimit style value [1,40] */
 	int nice_rlim = nice_to_rlimit(nice);
+	int ret;
 
-	return (nice_rlim <= task_rlimit(p, RLIMIT_NICE) ||
-		capable(CAP_SYS_NICE));
+	ret = (nice_rlim <= task_rlimit(p, RLIMIT_NICE) ||
+	       capable(CAP_SYS_NICE));
+	if (!ret)
+		rlimit_exceeded(RLIMIT_NICE, nice_rlim);
+	return ret;
 }
 
 #ifdef __ARCH_WANT_SYS_NICE
@@ -4070,13 +4074,18 @@ recheck:
 					task_rlimit(p, RLIMIT_RTPRIO);
 
 			/* can't set/change the rt policy */
-			if (policy != p->policy && !rlim_rtprio)
+			if (policy != p->policy && !rlim_rtprio) {
+				rlimit_exceeded(RLIMIT_RTPRIO, (u64)-1);
 				return -EPERM;
+			}
 
 			/* can't increase priority */
 			if (attr->sched_priority > p->rt_priority &&
-			    attr->sched_priority > rlim_rtprio)
+			    attr->sched_priority > rlim_rtprio) {
+				rlimit_exceeded(RLIMIT_RTPRIO,
+						attr->sched_priority);
 				return -EPERM;
+			}
 		}
 
 		 /*
diff --git a/kernel/signal.c b/kernel/signal.c
index af21afc00d08..1c03ca7484f7 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -362,6 +362,7 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi
 {
 	struct sigqueue *q = NULL;
 	struct user_struct *user;
+	int nsigs;
 
 	/*
 	 * Protect access to @t credentials. This can go away when all
@@ -372,11 +373,11 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi
 	atomic_inc(&user->sigpending);
 	rcu_read_unlock();
 
-	if (override_rlimit ||
-	    atomic_read(&user->sigpending) <=
-			task_rlimit(t, RLIMIT_SIGPENDING)) {
+	nsigs = atomic_read(&user->sigpending);
+	if (override_rlimit || nsigs <= task_rlimit(t, RLIMIT_SIGPENDING)) {
 		q = kmem_cache_alloc(sigqueue_cachep, flags);
 	} else {
+		rlimit_exceeded_task(RLIMIT_SIGPENDING, nsigs, t);
 		print_dropped_signal(sig);
 	}
 
diff --git a/kernel/sys.c b/kernel/sys.c
index 89d5be418157..28b718ac1fb1 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -421,6 +421,7 @@ error:
 static int set_user(struct cred *new)
 {
 	struct user_struct *new_user;
+	int nproc;
 
 	new_user = alloc_uid(new->uid);
 	if (!new_user)
@@ -433,11 +434,13 @@ static int set_user(struct cred *new)
 	 * for programs doing set*uid()+execve() by harmlessly deferring the
 	 * failure to the execve() stage.
 	 */
-	if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
-			new_user != INIT_USER)
+	nproc = atomic_read(&new_user->processes);
+	if (nproc >= rlimit(RLIMIT_NPROC) && new_user != INIT_USER) {
+		rlimit_exceeded(RLIMIT_NPROC, nproc);
 		current->flags |= PF_NPROC_EXCEEDED;
-	else
+	} else {
 		current->flags &= ~PF_NPROC_EXCEEDED;
+	}
 
 	free_uid(new->user);
 	new->user = new_user;
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 39008d78927a..ce50f2166776 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -860,6 +860,9 @@ static void check_thread_timers(struct task_struct *tsk,
 
 		if (hard != RLIM_INFINITY &&
 		    tsk->rt.timeout > DIV_ROUND_UP(hard, USEC_PER_SEC/HZ)) {
+			rlimit_hard_exceeded_task(RLIMIT_RTTIME,
+						  tsk->rt.timeout,
+						  tsk);
 			/*
 			 * At the hard limit, we just die.
 			 * No need to calculate anything else now.
@@ -875,6 +878,9 @@ static void check_thread_timers(struct task_struct *tsk,
 				soft += USEC_PER_SEC;
 				sig->rlim[RLIMIT_RTTIME].rlim_cur = soft;
 			}
+			rlimit_exceeded_task(RLIMIT_RTTIME,
+					     tsk->rt.timeout,
+					     tsk);
 			printk(KERN_INFO
 				"RT Watchdog Timeout: %s[%d]\n",
 				tsk->comm, task_pid_nr(tsk));
@@ -980,6 +986,7 @@ static void check_process_timers(struct task_struct *tsk,
 			READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_max);
 		cputime_t x;
 		if (psecs >= hard) {
+			rlimit_hard_exceeded(RLIMIT_CPU, psecs);
 			/*
 			 * At the hard limit, we just die.
 			 * No need to calculate anything else now.
@@ -988,6 +995,7 @@ static void check_process_timers(struct task_struct *tsk,
 			return;
 		}
 		if (psecs >= soft) {
+			rlimit_exceeded(RLIMIT_CPU, psecs);
 			/*
 			 * At the soft limit, send a SIGXCPU every second.
 			 */
diff --git a/mm/mlock.c b/mm/mlock.c
index 14645be06e30..016c7089db04 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -28,6 +28,9 @@ bool can_do_mlock(void)
 {
 	if (rlimit(RLIMIT_MEMLOCK) != 0)
 		return true;
+	else
+		rlimit_exceeded(RLIMIT_MEMLOCK, (u64)-1);
+
 	if (capable(CAP_IPC_LOCK))
 		return true;
 	return false;
@@ -643,6 +646,8 @@ static __must_check int do_mlock(unsigned long start, size_t len, vm_flags_t fla
 	/* check against resource limits */
 	if ((locked <= lock_limit) || capable(CAP_IPC_LOCK))
 		error = apply_vma_lock_flags(start, len, flags);
+	else
+		rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 
 	up_write(&current->mm->mmap_sem);
 	if (error)
@@ -757,6 +762,10 @@ SYSCALL_DEFINE1(mlockall, int, flags)
 	if (!(flags & MCL_CURRENT) || (current->mm->total_vm <= lock_limit) ||
 	    capable(CAP_IPC_LOCK))
 		ret = apply_mlockall_flags(flags);
+	else
+		rlimit_exceeded(RLIMIT_MEMLOCK,
+				current->mm->total_vm << PAGE_SHIFT);
+
 	up_write(&current->mm->mmap_sem);
 	if (!ret && (flags & MCL_CURRENT))
 		mm_populate(0, TASK_SIZE);
@@ -793,8 +802,11 @@ int user_shm_lock(size_t size, struct user_struct *user)
 	lock_limit >>= PAGE_SHIFT;
 	spin_lock(&shmlock_user_lock);
 	if (!allowed &&
-	    locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK))
+	    locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK)) {
+		rlimit_exceeded(RLIMIT_MEMLOCK,
+				(locked + user->locked_shm) << PAGE_SHIFT);
 		goto out;
+	}
 	get_uid(user);
 	user->locked_shm += locked;
 	allowed = 1;
diff --git a/mm/mmap.c b/mm/mmap.c
index ca9d91bca0d6..500a247f1759 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1139,8 +1139,10 @@ static inline int mlock_future_check(struct mm_struct *mm,
 		locked += mm->locked_vm;
 		lock_limit = rlimit(RLIMIT_MEMLOCK);
 		lock_limit >>= PAGE_SHIFT;
-		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
+		if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+			rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 			return -EAGAIN;
+		}
 	}
 	return 0;
 }
@@ -2012,8 +2014,10 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
 	actual_size = size;
 	if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN)))
 		actual_size -= PAGE_SIZE;
-	if (actual_size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur))
+	if (actual_size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur)) {
+		rlimit_exceeded(RLIMIT_STACK, actual_size);
 		return -ENOMEM;
+	}
 
 	/* mlock limit tests */
 	if (vma->vm_flags & VM_LOCKED) {
@@ -2022,8 +2026,10 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
 		locked = mm->locked_vm + grow;
 		limit = READ_ONCE(rlim[RLIMIT_MEMLOCK].rlim_cur);
 		limit >>= PAGE_SHIFT;
-		if (locked > limit && !capable(CAP_IPC_LOCK))
+		if (locked > limit && !capable(CAP_IPC_LOCK)) {
+			rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 			return -ENOMEM;
+		}
 	}
 
 	/* Check to ensure the stack will not grow into a hugetlb-only region */
@@ -2925,8 +2931,11 @@ out:
  */
 bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags, unsigned long npages)
 {
-	if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT)
+	if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT) {
+		rlimit_exceeded(RLIMIT_AS,
+				(mm->total_vm + npages) << PAGE_SHIFT);
 		return false;
+	}
 
 	if (is_data_mapping(flags) &&
 	    mm->data_vm + npages > rlimit(RLIMIT_DATA) >> PAGE_SHIFT) {
@@ -2935,6 +2944,8 @@ bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags, unsigned long npages)
 		    mm->data_vm + npages <= rlimit_max(RLIMIT_DATA) >> PAGE_SHIFT)
 			return true;
 		if (!ignore_rlimit_data) {
+			rlimit_exceeded(RLIMIT_DATA,
+					(mm->data_vm + npages) << PAGE_SHIFT);
 			pr_warn_once("%s (%d): VmData %lu exceed data ulimit %lu. Update limits or use boot option ignore_rlimit_data.\n",
 				     current->comm, current->pid,
 				     (mm->data_vm + npages) << PAGE_SHIFT,
diff --git a/mm/mremap.c b/mm/mremap.c
index da22ad2a5678..8755433ec79c 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -378,8 +378,10 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,
 		locked = mm->locked_vm << PAGE_SHIFT;
 		lock_limit = rlimit(RLIMIT_MEMLOCK);
 		locked += new_len - old_len;
-		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
+		if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+			rlimit_exceeded(RLIMIT_MEMLOCK, locked << PAGE_SHIFT);
 			return ERR_PTR(-EAGAIN);
+		}
 	}
 
 	if (!may_expand_vm(mm, vma->vm_flags,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f1dffe84f0d5..c365e5ab9ace 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1523,10 +1523,13 @@ static void unix_destruct_scm(struct sk_buff *skb)
 static inline bool too_many_unix_fds(struct task_struct *p)
 {
 	struct user_struct *user = current_user();
+	bool ret = false;
 
-	if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
-		return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
-	return false;
+	if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE))) {
+		rlimit_exceeded_task(RLIMIT_NOFILE, user->unix_inflight, p);
+		ret = !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
+	}
+	return ret;
 }
 
 #define MAX_RECURSION_LEVEL 4
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ