Re: [PATCH 2/2] ipc: Fix ipc data structures inconsistency

2017-12-02 Thread Davidlohr Bueso

On Sat, 02 Dec 2017, Philippe Mikoyan wrote:


On Fri, 1 Dec 2017 09:20:07 -0800
Davidlohr Bueso  wrote:



Hmm yeah that's pretty fishy, also shm_atime = 0, no?



Yeah, definitely, other data structure fields can also be
inconsistent, and applying not only to shmem, but also to
other ipc mechanisms.


Right.



Thank you for noting the typo, 'll send fixed version in next
message(without another patch, see below).


Ok, I had yet to look at that patch.


Re: [PATCH 2/2] ipc: Fix ipc data structures inconsistency

2017-12-02 Thread Philippe Mikoyan
On Fri, 1 Dec 2017 09:20:07 -0800
Davidlohr Bueso  wrote:

> 
> Hmm yeah that's pretty fishy, also shm_atime = 0, no?
> 

Yeah, definitely, other data structure fields can also be
inconsistent, and applying not only to shmem, but also to 
other ipc mechanisms.

Thank you for noting the typo, 'll send fixed version in next
message(without another patch, see below).

On Sat, 2 Dec 2017 07:03:30 +0100
Manfred Spraul  wrote:

> Especially: I don't know the shm code good enough to immediately
> check the change you make to nattach.

It seems that I didn't know the shm code good enough too: I've
recently discovered that 
[PATCH 1/2] ipc/shm: Fix shm_nattch incorrect value
is, frankly speaking, clearly total crap as it 
1) doesn't handle that shmem segment can be already RMID-ed
when entering shm_mmap, when called from 'remap_file_pages'
2) doesn't support (broken) logic of detaching remapped via
'remap_file_pages' shmem segment.

Regardless of handling (deprecated) 'remap_file_pages' call, patch
shall be OK. However, it has to be made over.

Sorry about that, hope I will find at least halfway elegant 
solution and send it ASAP.

On Sat, 2 Dec 2017 07:03:30 +0100
Manfred Spraul  wrote:

> 
> And, perhaps as a side information:
> There appears to be a use-after-free in shm, I now got a 2nd mail
> from syzbot:
> http://lkml.iu.edu/hypermail/linux/kernel/1702.3/02480.html
> 

Will dig into.


Thanks,
Phil


Re: [PATCH 2/2] ipc: Fix ipc data structures inconsistency

2017-12-01 Thread Manfred Spraul

Hi,

On 12/01/2017 06:20 PM, Davidlohr Bueso wrote:

On Thu, 30 Nov 2017, Philippe Mikoyan wrote:


As described in the title, this patch fixes id_ds inconsistency
when ctl_stat runs concurrently with some ds-changing function,
e.g. shmat, msgsnd or whatever.

For instance, if shmctl(IPC_STAT) is running concurrently with shmat,
following data structure can be returned:
{... shm_lpid = 0, shm_nattch = 1, ...}


The patch appears to be good. I'll try to perform some tests, but I'm 
not sure when I will be able to.
Especially: I don't know the shm code good enough to immediately check 
the change you make to nattach.


And, perhaps as a side information:
There appears to be a use-after-free in shm, I now got a 2nd mail from 
syzbot:

http://lkml.iu.edu/hypermail/linux/kernel/1702.3/02480.html



Hmm yeah that's pretty fishy, also shm_atime = 0, no?

So I think this patch is fine as we can obviously race at a user level.
This is another justification for converting the ipc lock to rwlock;
performance wise they are the pretty much the same (being queued)...
but that's irrelevant to this patch. I like that you manage to do
security and such checks still only under rcu, like all ipc calls
work; *_stat() is no longer special.

I don't like rwlock, they add complexity without reducing the cache line 
pressure.


What I would like to try is to create a mutex_lock_rcu() function, and 
then convert everything to a mutex.


As pseudocode::
    rcu_lock();
    idr_lookup();
    mutex_trylock();
    if (failed) {
        getref();
        rcu_unlock();
        mutex_lock();
        putref();
    } else {
        rcu_unlock();
    }

Obviously, the getref then within the mutex framework, i.e. only if 
mutex_lock() really sleeps.
If the code in ipc gets significantly simpler, then perhaps convert it 
to an rw mutex.


Re: [PATCH 2/2] ipc: Fix ipc data structures inconsistency

2017-12-01 Thread Davidlohr Bueso

On Thu, 30 Nov 2017, Philippe Mikoyan wrote:


As described in the title, this patch fixes id_ds inconsistency
when ctl_stat runs concurrently with some ds-changing function,
e.g. shmat, msgsnd or whatever.

For instance, if shmctl(IPC_STAT) is running concurrently with shmat,
following data structure can be returned:
{... shm_lpid = 0, shm_nattch = 1, ...}


Hmm yeah that's pretty fishy, also shm_atime = 0, no?

So I think this patch is fine as we can obviously race at a user level.
This is another justification for converting the ipc lock to rwlock;
performance wise they are the pretty much the same (being queued)...
but that's irrelevant to this patch. I like that you manage to do
security and such checks still only under rcu, like all ipc calls
work; *_stat() is no longer special.

With a nit below:

Reviewed-by: Davidlohr Bueso 


diff --git a/ipc/util.c b/ipc/util.c
index 78755873cc5b..8d3c3946c825 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -22,9 +22,12 @@
 *  tree.
 *  - perform initial checks (capabilities, auditing and permission,
 *etc).
- * - perform read-only operations, such as STAT, INFO commands.
+ * - perform read-only operations, such as INFO command, that
+ *   do not demand atomicity
 *acquire the ipc lock (kern_ipc_perm.lock) through
 *ipc_lock_object()
+ * - perform read-only operatoins that demand atomicity,

 ^^ typo

+ *   such as STAT command.
 *  - perform data updates, such as SET, RMID commands and
 *mechanism-specific operations (semop/semtimedop,
 *msgsnd/msgrcv, shmat/shmdt).


Thanks,
Davidlohr


[PATCH 2/2] ipc: Fix ipc data structures inconsistency

2017-11-29 Thread Philippe Mikoyan
As described in the title, this patch fixes id_ds inconsistency
when ctl_stat runs concurrently with some ds-changing function,
e.g. shmat, msgsnd or whatever.

For instance, if shmctl(IPC_STAT) is running concurrently with shmat,
following data structure can be returned:
{... shm_lpid = 0, shm_nattch = 1, ...}

Signed-off-by: Philippe Mikoyan 
---
 ipc/msg.c  | 20 ++--
 ipc/sem.c  | 10 ++
 ipc/shm.c  | 19 ++-
 ipc/util.c |  5 -
 4 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/ipc/msg.c b/ipc/msg.c
index 06be5a9adfa4..047579b42de4 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -475,9 +475,9 @@ static int msgctl_info(struct ipc_namespace *ns, int msqid,
 static int msgctl_stat(struct ipc_namespace *ns, int msqid,
 int cmd, struct msqid64_ds *p)
 {
-   int err;
struct msg_queue *msq;
-   int success_return;
+   int id = 0;
+   int err;

memset(p, 0, sizeof(*p));

@@ -488,14 +488,13 @@ static int msgctl_stat(struct ipc_namespace *ns, int 
msqid,
err = PTR_ERR(msq);
goto out_unlock;
}
-   success_return = msq->q_perm.id;
+   id = msq->q_perm.id;
} else {
msq = msq_obtain_object_check(ns, msqid);
if (IS_ERR(msq)) {
err = PTR_ERR(msq);
goto out_unlock;
}
-   success_return = 0;
}

err = -EACCES;
@@ -506,6 +505,14 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
if (err)
goto out_unlock;

+   ipc_lock_object(&msq->q_perm);
+
+   if (!ipc_valid_object(&msq->q_perm)) {
+   ipc_unlock_object(&msq->q_perm);
+   err = -EIDRM;
+   goto out_unlock;
+   }
+
kernel_to_ipc64_perm(&msq->q_perm, &p->msg_perm);
p->msg_stime  = msq->q_stime;
p->msg_rtime  = msq->q_rtime;
@@ -515,9 +522,10 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
p->msg_qbytes = msq->q_qbytes;
p->msg_lspid  = msq->q_lspid;
p->msg_lrpid  = msq->q_lrpid;
-   rcu_read_unlock();

-   return success_return;
+   ipc_unlock_object(&msq->q_perm);
+   rcu_read_unlock();
+   return id;

 out_unlock:
rcu_read_unlock();
diff --git a/ipc/sem.c b/ipc/sem.c
index f7385bce5fd3..9b6f80d1b3f1 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1211,10 +1211,20 @@ static int semctl_stat(struct ipc_namespace *ns, int 
semid,
if (err)
goto out_unlock;

+   ipc_lock_object(&sma->sem_perm);
+
+   if (!ipc_valid_object(&sma->sem_perm)) {
+   ipc_unlock_object(&sma->sem_perm);
+   err = -EIDRM;
+   goto out_unlock;
+   }
+
kernel_to_ipc64_perm(&sma->sem_perm, &semid64->sem_perm);
semid64->sem_otime = get_semotime(sma);
semid64->sem_ctime = sma->sem_ctime;
semid64->sem_nsems = sma->sem_nsems;
+
+   ipc_unlock_object(&sma->sem_perm);
rcu_read_unlock();
return id;

diff --git a/ipc/shm.c b/ipc/shm.c
index 565f17925128..8f58faba7429 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -896,9 +896,11 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
int cmd, struct shmid64_ds *tbuf)
 {
struct shmid_kernel *shp;
-   int result;
+   int id = 0;
int err;

+   memset(tbuf, 0, sizeof(*tbuf));
+
rcu_read_lock();
if (cmd == SHM_STAT) {
shp = shm_obtain_object(ns, shmid);
@@ -906,14 +908,13 @@ static int shmctl_stat(struct ipc_namespace *ns, int 
shmid,
err = PTR_ERR(shp);
goto out_unlock;
}
-   result = shp->shm_perm.id;
+   id = shp->shm_perm.id;
} else {
shp = shm_obtain_object_check(ns, shmid);
if (IS_ERR(shp)) {
err = PTR_ERR(shp);
goto out_unlock;
}
-   result = 0;
}

err = -EACCES;
@@ -924,7 +925,14 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
if (err)
goto out_unlock;

-   memset(tbuf, 0, sizeof(*tbuf));
+   ipc_lock_object(&shp->shm_perm);
+
+   if (!ipc_valid_object(&shp->shm_perm)) {
+   ipc_unlock_object(&shp->shm_perm);
+   err = -EIDRM;
+   goto out_unlock;
+   }
+
kernel_to_ipc64_perm(&shp->shm_perm, &tbuf->shm_perm);
tbuf->shm_segsz = shp->shm_segsz;
tbuf->shm_atime = shp->shm_atim;
@@ -934,8 +942,9 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
tbuf->shm_lpid  = shp->shm_lprid;
tbuf->shm_nattch = shp->shm_nattch;

+   ipc_unlock_object(&shp->shm_perm);
rcu_read_unlock();
-   return result;
+   re