Skip to content

Commit

Permalink
IB/security: Restrict use of the write() interface
Browse files Browse the repository at this point in the history
The drivers/infiniband stack uses write() as a replacement for
bi-directional ioctl().  This is not safe. There are ways to
trigger write calls that result in the return structure that
is normally written to user space being shunted off to user
specified kernel memory instead.

For the immediate repair, detect and deny suspicious accesses to
the write API.

For long term, update the user space libraries and the kernel API
to something that doesn't present the same security vulnerabilities
(likely a structured ioctl() interface).

The impacted uAPI interfaces are generally only available if
hardware from drivers/infiniband is installed in the system.

Reported-by: Jann Horn <jann@thejh.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
[ Expanded check to all known write() entry points ]
Cc: stable@vger.kernel.org
Signed-off-by: Doug Ledford <dledford@redhat.com>
  • Loading branch information
jgunthorpe authored and dledford committed Apr 28, 2016
1 parent 7723d8c commit e6bd18f
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 1 deletion.
4 changes: 4 additions & 0 deletions drivers/infiniband/core/ucm.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

#include <asm/uaccess.h>

#include <rdma/ib.h>
#include <rdma/ib_cm.h>
#include <rdma/ib_user_cm.h>
#include <rdma/ib_marshall.h>
Expand Down Expand Up @@ -1103,6 +1104,9 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf,
struct ib_ucm_cmd_hdr hdr;
ssize_t result;

if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
return -EACCES;

if (len < sizeof(hdr))
return -EINVAL;

Expand Down
3 changes: 3 additions & 0 deletions drivers/infiniband/core/ucma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,9 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf,
struct rdma_ucm_cmd_hdr hdr;
ssize_t ret;

if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
return -EACCES;

if (len < sizeof(hdr))
return -EINVAL;

Expand Down
5 changes: 5 additions & 0 deletions drivers/infiniband/core/uverbs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@

#include <asm/uaccess.h>

#include <rdma/ib.h>

#include "uverbs.h"

MODULE_AUTHOR("Roland Dreier");
Expand Down Expand Up @@ -709,6 +711,9 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
int srcu_key;
ssize_t ret;

if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
return -EACCES;

if (count < sizeof hdr)
return -EINVAL;

Expand Down
5 changes: 5 additions & 0 deletions drivers/infiniband/hw/qib/qib_file_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
#include <linux/export.h>
#include <linux/uio.h>

#include <rdma/ib.h>

#include "qib.h"
#include "qib_common.h"
#include "qib_user_sdma.h"
Expand Down Expand Up @@ -2067,6 +2069,9 @@ static ssize_t qib_write(struct file *fp, const char __user *data,
ssize_t ret = 0;
void *dest;

if (WARN_ON_ONCE(!ib_safe_file_access(fp)))
return -EACCES;

if (count < sizeof(cmd.type)) {
ret = -EINVAL;
goto bail;
Expand Down
2 changes: 1 addition & 1 deletion drivers/staging/rdma/hfi1/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ July, 2015
- Remove unneeded file entries in sysfs
- Remove software processing of IB protocol and place in library for use
by qib, ipath (if still present), hfi1, and eventually soft-roce

- Replace incorrect uAPI
6 changes: 6 additions & 0 deletions drivers/staging/rdma/hfi1/file_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
#include <linux/vmalloc.h>
#include <linux/io.h>

#include <rdma/ib.h>

#include "hfi.h"
#include "pio.h"
#include "device.h"
Expand Down Expand Up @@ -190,6 +192,10 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
int uctxt_required = 1;
int must_be_root = 0;

/* FIXME: This interface cannot continue out of staging */
if (WARN_ON_ONCE(!ib_safe_file_access(fp)))
return -EACCES;

if (count < sizeof(cmd)) {
ret = -EINVAL;
goto bail;
Expand Down
16 changes: 16 additions & 0 deletions include/rdma/ib.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#define _RDMA_IB_H

#include <linux/types.h>
#include <linux/sched.h>

struct ib_addr {
union {
Expand Down Expand Up @@ -86,4 +87,19 @@ struct sockaddr_ib {
__u64 sib_scope_id;
};

/*
* The IB interfaces that use write() as bi-directional ioctl() are
* fundamentally unsafe, since there are lots of ways to trigger "write()"
* calls from various contexts with elevated privileges. That includes the
* traditional suid executable error message writes, but also various kernel
* interfaces that can write to file descriptors.
*
* This function provides protection for the legacy API by restricting the
* calling context.
*/
static inline bool ib_safe_file_access(struct file *filp)
{
return filp->f_cred == current_cred() && segment_eq(get_fs(), USER_DS);
}

#endif /* _RDMA_IB_H */

0 comments on commit e6bd18f

Please sign in to comment.