All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Kirill A. Shutemov" <kirill@shutemov.name>
To: Manfred Spraul <manfred@colorfullife.com>,
	Davidlohr Bueso <dave@stgolabs.net>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	linux-kernel@vger.kernel.org, linux-mm@kvack.org,
	Dmitry Vyukov <dvyukov@google.com>
Subject: Re: [PATCH, RESEND] ipc/shm: handle removed segments gracefully in shm_mmap()
Date: Mon, 4 Jan 2016 16:11:30 +0200	[thread overview]
Message-ID: <20160104141130.GA13515@node.shutemov.name> (raw)
In-Reply-To: <5687B843.2040804@colorfullife.com>

On Sat, Jan 02, 2016 at 12:45:07PM +0100, Manfred Spraul wrote:
> On 11/13/2015 08:23 PM, Davidlohr Bueso wrote:
> >
> >So considering EINVAL, even your approach to bumping up nattach by calling
> >_shm_open earlier isn't enough. Races exposed to user called rmid can
> >still
> >occur between dropping the lock and doing ->mmap(). Ultimately this leads
> >to
> >all ipc_valid_object() checks, as we totally ignore SHM_DEST segments
> >nowadays
> >since we forbid mapping previously removed segments.
> >
> >I think this is the first thing we must decide before going forward with
> >this
> >mess. ipc currently defines invalid objects by merely checking the deleted
> >flag.
> >
> >Manfred, any thoughts?
> >
> With regards to locking: Sorry, shm is too different to msg/sem/mqueue.
> 
> With regards to EIDRM / EINVAL:
> When all kernel memory was released, then the kernel cannot find out if the
> ID was valid at one time or not.
> Thus EIDRM can only be a hint, the OS (kernel/libc) cannot guarantee that
> user space will never see something else.
> (trivial example: user space sleeps just before the syscall)
> 
> So I would not create special code to optimize EIDRM handling for races. If
> we sometimes report EINVAL, it would be probably ok as well.

Guys, here's yet another attempt to fix the issue.

The key idea this time is to use shm_ids(ns).rwsem taken for read in shm_mmap()
to prevent rmid under us.

Any problem with this?

diff --git a/ipc/shm.c b/ipc/shm.c
index ed3027d0f277..b306fb3d9586 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -156,11 +156,12 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
 	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
 
 	/*
-	 * We raced in the idr lookup or with shm_destroy().  Either way, the
-	 * ID is busted.
+	 * Callers of shm_lock() must validate the status of the returned ipc
+	 * object pointer (as returned by ipc_lock()), and error out as
+	 * appropriate.
 	 */
-	WARN_ON(IS_ERR(ipcp));
-
+	if (IS_ERR(ipcp))
+		return (void *)ipcp;
 	return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -194,6 +195,14 @@ static void shm_open(struct vm_area_struct *vma)
 	struct shmid_kernel *shp;
 
 	shp = shm_lock(sfd->ns, sfd->id);
+
+	/*
+	 * We raced in the idr lookup or with shm_destroy().
+	 * Either way, the ID is busted.
+	 */
+	if (WARN_ON(IS_ERR(shp)))
+		return ;
+
 	shp->shm_atim = get_seconds();
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_nattch++;
@@ -386,18 +395,34 @@ static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
 static int shm_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct shm_file_data *sfd = shm_file_data(file);
+	struct shmid_kernel *shp;
 	int ret;
 
+	/* Prevent rmid under us */
+	down_read(&shm_ids(sfd->ns).rwsem);
+
+	/* Check if we can map the segment */
+	shp = shm_lock(sfd->ns, sfd->id);
+	if (IS_ERR(shp)) {
+		ret = PTR_ERR(shp);
+		goto out;
+	}
+	ret = shp->shm_perm.mode & SHM_DEST ? -EINVAL : 0;
+	shm_unlock(shp);
+	if (ret)
+		goto out;
+
 	ret = sfd->file->f_op->mmap(sfd->file, vma);
 	if (ret != 0)
-		return ret;
+		goto out;
 	sfd->vm_ops = vma->vm_ops;
 #ifdef CONFIG_MMU
 	WARN_ON(!sfd->vm_ops->fault);
 #endif
 	vma->vm_ops = &shm_vm_ops;
 	shm_open(vma);
-
+out:
+	up_read(&shm_ids(sfd->ns).rwsem);
 	return ret;
 }
 
-- 
 Kirill A. Shutemov

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

WARNING: multiple messages have this Message-ID (diff)
From: "Kirill A. Shutemov" <kirill@shutemov.name>
To: Manfred Spraul <manfred@colorfullife.com>,
	Davidlohr Bueso <dave@stgolabs.net>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	linux-kernel@vger.kernel.org, linux-mm@kvack.org,
	Dmitry Vyukov <dvyukov@google.com>
Subject: Re: [PATCH, RESEND] ipc/shm: handle removed segments gracefully in shm_mmap()
Date: Mon, 4 Jan 2016 16:11:30 +0200	[thread overview]
Message-ID: <20160104141130.GA13515@node.shutemov.name> (raw)
In-Reply-To: <5687B843.2040804@colorfullife.com>

On Sat, Jan 02, 2016 at 12:45:07PM +0100, Manfred Spraul wrote:
> On 11/13/2015 08:23 PM, Davidlohr Bueso wrote:
> >
> >So considering EINVAL, even your approach to bumping up nattach by calling
> >_shm_open earlier isn't enough. Races exposed to user called rmid can
> >still
> >occur between dropping the lock and doing ->mmap(). Ultimately this leads
> >to
> >all ipc_valid_object() checks, as we totally ignore SHM_DEST segments
> >nowadays
> >since we forbid mapping previously removed segments.
> >
> >I think this is the first thing we must decide before going forward with
> >this
> >mess. ipc currently defines invalid objects by merely checking the deleted
> >flag.
> >
> >Manfred, any thoughts?
> >
> With regards to locking: Sorry, shm is too different to msg/sem/mqueue.
> 
> With regards to EIDRM / EINVAL:
> When all kernel memory was released, then the kernel cannot find out if the
> ID was valid at one time or not.
> Thus EIDRM can only be a hint, the OS (kernel/libc) cannot guarantee that
> user space will never see something else.
> (trivial example: user space sleeps just before the syscall)
> 
> So I would not create special code to optimize EIDRM handling for races. If
> we sometimes report EINVAL, it would be probably ok as well.

Guys, here's yet another attempt to fix the issue.

The key idea this time is to use shm_ids(ns).rwsem taken for read in shm_mmap()
to prevent rmid under us.

Any problem with this?

diff --git a/ipc/shm.c b/ipc/shm.c
index ed3027d0f277..b306fb3d9586 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -156,11 +156,12 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
 	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
 
 	/*
-	 * We raced in the idr lookup or with shm_destroy().  Either way, the
-	 * ID is busted.
+	 * Callers of shm_lock() must validate the status of the returned ipc
+	 * object pointer (as returned by ipc_lock()), and error out as
+	 * appropriate.
 	 */
-	WARN_ON(IS_ERR(ipcp));
-
+	if (IS_ERR(ipcp))
+		return (void *)ipcp;
 	return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -194,6 +195,14 @@ static void shm_open(struct vm_area_struct *vma)
 	struct shmid_kernel *shp;
 
 	shp = shm_lock(sfd->ns, sfd->id);
+
+	/*
+	 * We raced in the idr lookup or with shm_destroy().
+	 * Either way, the ID is busted.
+	 */
+	if (WARN_ON(IS_ERR(shp)))
+		return ;
+
 	shp->shm_atim = get_seconds();
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_nattch++;
@@ -386,18 +395,34 @@ static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
 static int shm_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct shm_file_data *sfd = shm_file_data(file);
+	struct shmid_kernel *shp;
 	int ret;
 
+	/* Prevent rmid under us */
+	down_read(&shm_ids(sfd->ns).rwsem);
+
+	/* Check if we can map the segment */
+	shp = shm_lock(sfd->ns, sfd->id);
+	if (IS_ERR(shp)) {
+		ret = PTR_ERR(shp);
+		goto out;
+	}
+	ret = shp->shm_perm.mode & SHM_DEST ? -EINVAL : 0;
+	shm_unlock(shp);
+	if (ret)
+		goto out;
+
 	ret = sfd->file->f_op->mmap(sfd->file, vma);
 	if (ret != 0)
-		return ret;
+		goto out;
 	sfd->vm_ops = vma->vm_ops;
 #ifdef CONFIG_MMU
 	WARN_ON(!sfd->vm_ops->fault);
 #endif
 	vma->vm_ops = &shm_vm_ops;
 	shm_open(vma);
-
+out:
+	up_read(&shm_ids(sfd->ns).rwsem);
 	return ret;
 }
 
-- 
 Kirill A. Shutemov

  reply	other threads:[~2016-01-04 14:11 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-11  8:57 [PATCH, RESEND] ipc/shm: handle removed segments gracefully in shm_mmap() Kirill A. Shutemov
2015-11-11  8:57 ` Kirill A. Shutemov
2015-11-11 17:03 ` Davidlohr Bueso
2015-11-11 17:03   ` Davidlohr Bueso
2015-11-11 19:50   ` Kirill A. Shutemov
2015-11-11 19:50     ` Kirill A. Shutemov
2015-11-13  5:31     ` Davidlohr Bueso
2015-11-13  5:31       ` Davidlohr Bueso
2015-11-13  9:12       ` Kirill A. Shutemov
2015-11-13  9:12         ` Kirill A. Shutemov
2015-11-13 19:23         ` Davidlohr Bueso
2015-11-13 19:23           ` Davidlohr Bueso
2015-11-13 19:58           ` Davidlohr Bueso
2015-11-13 19:58             ` Davidlohr Bueso
2015-11-16  9:32           ` Kirill A. Shutemov
2015-11-16  9:32             ` Kirill A. Shutemov
2016-01-02 11:45           ` Manfred Spraul
2016-01-02 11:45             ` Manfred Spraul
2016-01-04 14:11             ` Kirill A. Shutemov [this message]
2016-01-04 14:11               ` Kirill A. Shutemov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160104141130.GA13515@node.shutemov.name \
    --to=kirill@shutemov.name \
    --cc=akpm@linux-foundation.org \
    --cc=dave@stgolabs.net \
    --cc=dvyukov@google.com \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=manfred@colorfullife.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.