2009-09-29 14:48:17

by Philipp Reisner

[permalink] [raw]
Subject: [PATCH] connector: Allow permission checking in the receiver callbacks

Various users of the connector should actually check if the
sender's capabilities of a netlink/connector packet are
actually sufficient for the operation they trigger. Up to
now the connector framework did not allow the kernel side
receiver to do so.

This patch set does the groundwork.

Philipp Reisner (4):
connector: Keep the skb in cn_callback_data
connector: Provide the sender's credentials to the callback
connector/dm: Fixed a compilation warning
connector: Removed the destruct_data callback since it is always
kfree_skb()

Documentation/connector/cn_test.c | 2 +-
Documentation/connector/connector.txt | 8 ++++----
drivers/connector/cn_queue.c | 12 +++++++-----
drivers/connector/connector.c | 22 ++++++++--------------
drivers/md/dm-log-userspace-transfer.c | 3 +--
drivers/staging/dst/dcore.c | 2 +-
drivers/staging/pohmelfs/config.c | 2 +-
drivers/video/uvesafb.c | 2 +-
drivers/w1/w1_netlink.c | 2 +-
include/linux/connector.h | 11 ++++-------
10 files changed, 29 insertions(+), 37 deletions(-)


2009-09-29 14:48:18

by Philipp Reisner

[permalink] [raw]
Subject: [PATCH] connector: Keep the skb in cn_callback_data

Signed-off-by: Philipp Reisner <[email protected]>
Acked-by: Lars Ellenberg <[email protected]>
---
drivers/connector/cn_queue.c | 3 ++-
drivers/connector/connector.c | 11 +++++------
include/linux/connector.h | 4 ++--
3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 4a1dfe1..b4cfac9 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -78,8 +78,9 @@ void cn_queue_wrapper(struct work_struct *work)
struct cn_callback_entry *cbq =
container_of(work, struct cn_callback_entry, work);
struct cn_callback_data *d = &cbq->data;
+ struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb));

- d->callback(d->callback_priv);
+ d->callback(msg);

d->destruct_data(d->ddata);
d->ddata = NULL;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 74f52af..fc9887f 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -129,10 +129,11 @@ EXPORT_SYMBOL_GPL(cn_netlink_send);
/*
* Callback helper - queues work and setup destructor for given data.
*/
-static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data)
+static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *), void *data)
{
struct cn_callback_entry *__cbq, *__new_cbq;
struct cn_dev *dev = &cdev;
+ struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb));
int err = -ENODEV;

spin_lock_bh(&dev->cbdev->queue_lock);
@@ -140,7 +141,7 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
if (cn_cb_equal(&__cbq->id.id, &msg->id)) {
if (likely(!work_pending(&__cbq->work) &&
__cbq->data.ddata == NULL)) {
- __cbq->data.callback_priv = msg;
+ __cbq->data.skb = skb;

__cbq->data.ddata = data;
__cbq->data.destruct_data = destruct_data;
@@ -156,7 +157,7 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
__new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC);
if (__new_cbq) {
d = &__new_cbq->data;
- d->callback_priv = msg;
+ d->skb = skb;
d->callback = __cbq->data.callback;
d->ddata = data;
d->destruct_data = destruct_data;
@@ -191,7 +192,6 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
*/
static void cn_rx_skb(struct sk_buff *__skb)
{
- struct cn_msg *msg;
struct nlmsghdr *nlh;
int err;
struct sk_buff *skb;
@@ -208,8 +208,7 @@ static void cn_rx_skb(struct sk_buff *__skb)
return;
}

- msg = NLMSG_DATA(nlh);
- err = cn_call_callback(msg, (void (*)(void *))kfree_skb, skb);
+ err = cn_call_callback(skb, (void (*)(void *))kfree_skb, skb);
if (err < 0)
kfree_skb(skb);
}
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 47ebf41..05a7a14 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -134,8 +134,8 @@ struct cn_callback_id {
struct cn_callback_data {
void (*destruct_data) (void *);
void *ddata;
-
- void *callback_priv;
+
+ struct sk_buff *skb;
void (*callback) (struct cn_msg *);

void *free;
--
1.6.0.4

2009-09-29 14:48:51

by Philipp Reisner

[permalink] [raw]
Subject: [PATCH] connector: Provide the sender's credentials to the callback

Signed-off-by: Philipp Reisner <[email protected]>
Acked-by: Lars Ellenberg <[email protected]>
---
Documentation/connector/cn_test.c | 2 +-
Documentation/connector/connector.txt | 8 ++++----
drivers/connector/cn_queue.c | 7 ++++---
drivers/connector/connector.c | 4 ++--
drivers/md/dm-log-userspace-transfer.c | 2 +-
drivers/staging/dst/dcore.c | 2 +-
drivers/staging/pohmelfs/config.c | 2 +-
drivers/video/uvesafb.c | 2 +-
drivers/w1/w1_netlink.c | 2 +-
include/linux/connector.h | 6 +++---
10 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
index 1711adc..b07add3 100644
--- a/Documentation/connector/cn_test.c
+++ b/Documentation/connector/cn_test.c
@@ -34,7 +34,7 @@ static char cn_test_name[] = "cn_test";
static struct sock *nls;
static struct timer_list cn_test_timer;

-static void cn_test_callback(struct cn_msg *msg)
+static void cn_test_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
pr_info("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
__func__, jiffies, msg->id.idx, msg->id.val,
diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt
index 81e6bf6..78c9466 100644
--- a/Documentation/connector/connector.txt
+++ b/Documentation/connector/connector.txt
@@ -23,7 +23,7 @@ handling, etc... The Connector driver allows any kernelspace agents to use
netlink based networking for inter-process communication in a significantly
easier way:

-int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct cn_msg *, struct netlink_skb_parms *));
void cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask);

struct cb_id
@@ -53,15 +53,15 @@ struct cn_msg
Connector interfaces.
/*****************************************/

-int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct cn_msg *, struct netlink_skb_parms *));

Registers new callback with connector core.

struct cb_id *id - unique connector's user identifier.
It must be registered in connector.h for legal in-kernel users.
char *name - connector's callback symbolic name.
- void (*callback) (void *) - connector's callback.
- Argument must be dereferenced to struct cn_msg *.
+ void (*callback) (struct cn..) - connector's callback.
+ cn_msg and the sender's credentials


void cn_del_callback(struct cb_id *id);
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index b4cfac9..163c3e3 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -79,8 +79,9 @@ void cn_queue_wrapper(struct work_struct *work)
container_of(work, struct cn_callback_entry, work);
struct cn_callback_data *d = &cbq->data;
struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb));
+ struct netlink_skb_parms *nsp = &NETLINK_CB(d->skb);

- d->callback(msg);
+ d->callback(msg, nsp);

d->destruct_data(d->ddata);
d->ddata = NULL;
@@ -90,7 +91,7 @@ void cn_queue_wrapper(struct work_struct *work)

static struct cn_callback_entry *
cn_queue_alloc_callback_entry(char *name, struct cb_id *id,
- void (*callback)(struct cn_msg *))
+ void (*callback)(struct cn_msg *, struct netlink_skb_parms *))
{
struct cn_callback_entry *cbq;

@@ -124,7 +125,7 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
}

int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id,
- void (*callback)(struct cn_msg *))
+ void (*callback)(struct cn_msg *, struct netlink_skb_parms *))
{
struct cn_callback_entry *cbq, *__cbq;
int found = 0;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index fc9887f..e59f0ab 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -269,7 +269,7 @@ static void cn_notify(struct cb_id *id, u32 notify_event)
* May sleep.
*/
int cn_add_callback(struct cb_id *id, char *name,
- void (*callback)(struct cn_msg *))
+ void (*callback)(struct cn_msg *, struct netlink_skb_parms *))
{
int err;
struct cn_dev *dev = &cdev;
@@ -351,7 +351,7 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
*
* Used for notification of a request's processing.
*/
-static void cn_callback(struct cn_msg *msg)
+static void cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
struct cn_ctl_msg *ctl;
struct cn_ctl_entry *ent;
diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
index ba0edad..556131f 100644
--- a/drivers/md/dm-log-userspace-transfer.c
+++ b/drivers/md/dm-log-userspace-transfer.c
@@ -129,7 +129,7 @@ static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr)
* This is the connector callback that delivers data
* that was sent from userspace.
*/
-static void cn_ulog_callback(void *data)
+static void cn_ulog_callback(void *data, struct netlink_skb_parms *nsp)
{
struct cn_msg *msg = (struct cn_msg *)data;
struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);
diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c
index ac85773..3943c91 100644
--- a/drivers/staging/dst/dcore.c
+++ b/drivers/staging/dst/dcore.c
@@ -847,7 +847,7 @@ static dst_command_func dst_commands[] = {
/*
* Configuration parser.
*/
-static void cn_dst_callback(struct cn_msg *msg)
+static void cn_dst_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
struct dst_ctl *ctl;
int err;
diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c
index 90f962e..c9162b3 100644
--- a/drivers/staging/pohmelfs/config.c
+++ b/drivers/staging/pohmelfs/config.c
@@ -527,7 +527,7 @@ out_unlock:
return err;
}

-static void pohmelfs_cn_callback(struct cn_msg *msg)
+static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
int err;

diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index e98baf6..aa7cd95 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -67,7 +67,7 @@ static DEFINE_MUTEX(uvfb_lock);
* find the kernel part of the task struct, copy the registers and
* the buffer contents and then complete the task.
*/
-static void uvesafb_cn_callback(struct cn_msg *msg)
+static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
struct uvesafb_task *utask;
struct uvesafb_ktask *task;
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index 52ccb3d..45c126f 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -306,7 +306,7 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm
return error;
}

-static void w1_cn_callback(struct cn_msg *msg)
+static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1);
struct w1_netlink_cmd *cmd;
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 05a7a14..545728e 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -136,7 +136,7 @@ struct cn_callback_data {
void *ddata;

struct sk_buff *skb;
- void (*callback) (struct cn_msg *);
+ void (*callback) (struct cn_msg *, struct netlink_skb_parms *);

void *free;
};
@@ -167,11 +167,11 @@ struct cn_dev {
struct cn_queue_dev *cbdev;
};

-int cn_add_callback(struct cb_id *, char *, void (*callback) (struct cn_msg *));
+int cn_add_callback(struct cb_id *, char *, void (*callback) (struct cn_msg *, struct netlink_skb_parms *));
void cn_del_callback(struct cb_id *);
int cn_netlink_send(struct cn_msg *, u32, gfp_t);

-int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *));
+int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *, struct netlink_skb_parms *));
void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);

int queue_cn_work(struct cn_callback_entry *cbq, struct work_struct *work);
--
1.6.0.4

2009-09-29 14:48:17

by Philipp Reisner

[permalink] [raw]
Subject: [PATCH] connector/dm: Fixed a compilation warning

Signed-off-by: Philipp Reisner <[email protected]>
Acked-by: Lars Ellenberg <[email protected]>
---
drivers/md/dm-log-userspace-transfer.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
index 556131f..1327e1a 100644
--- a/drivers/md/dm-log-userspace-transfer.c
+++ b/drivers/md/dm-log-userspace-transfer.c
@@ -129,9 +129,8 @@ static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr)
* This is the connector callback that delivers data
* that was sent from userspace.
*/
-static void cn_ulog_callback(void *data, struct netlink_skb_parms *nsp)
+static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
- struct cn_msg *msg = (struct cn_msg *)data;
struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);

spin_lock(&receiving_list_lock);
--
1.6.0.4

2009-09-29 14:48:13

by Philipp Reisner

[permalink] [raw]
Subject: [PATCH] connector: Removed the destruct_data callback since it is always kfree_skb()

Signed-off-by: Philipp Reisner <[email protected]>
Acked-by: Lars Ellenberg <[email protected]>
---
drivers/connector/cn_queue.c | 4 ++--
drivers/connector/connector.c | 11 +++--------
include/linux/connector.h | 3 ---
3 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 163c3e3..210338e 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -83,8 +83,8 @@ void cn_queue_wrapper(struct work_struct *work)

d->callback(msg, nsp);

- d->destruct_data(d->ddata);
- d->ddata = NULL;
+ kfree_skb(d->skb);
+ d->skb = NULL;

kfree(d->free);
}
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index e59f0ab..f060246 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -129,7 +129,7 @@ EXPORT_SYMBOL_GPL(cn_netlink_send);
/*
* Callback helper - queues work and setup destructor for given data.
*/
-static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *), void *data)
+static int cn_call_callback(struct sk_buff *skb)
{
struct cn_callback_entry *__cbq, *__new_cbq;
struct cn_dev *dev = &cdev;
@@ -140,12 +140,9 @@ static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *),
list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) {
if (cn_cb_equal(&__cbq->id.id, &msg->id)) {
if (likely(!work_pending(&__cbq->work) &&
- __cbq->data.ddata == NULL)) {
+ __cbq->data.skb == NULL)) {
__cbq->data.skb = skb;

- __cbq->data.ddata = data;
- __cbq->data.destruct_data = destruct_data;
-
if (queue_cn_work(__cbq, &__cbq->work))
err = 0;
else
@@ -159,8 +156,6 @@ static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *),
d = &__new_cbq->data;
d->skb = skb;
d->callback = __cbq->data.callback;
- d->ddata = data;
- d->destruct_data = destruct_data;
d->free = __new_cbq;

__new_cbq->pdev = __cbq->pdev;
@@ -208,7 +203,7 @@ static void cn_rx_skb(struct sk_buff *__skb)
return;
}

- err = cn_call_callback(skb, (void (*)(void *))kfree_skb, skb);
+ err = cn_call_callback(skb);
if (err < 0)
kfree_skb(skb);
}
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 545728e..3a14615 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -132,9 +132,6 @@ struct cn_callback_id {
};

struct cn_callback_data {
- void (*destruct_data) (void *);
- void *ddata;
-
struct sk_buff *skb;
void (*callback) (struct cn_msg *, struct netlink_skb_parms *);

--
1.6.0.4

2009-09-30 11:20:56

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [PATCH] connector: Allow permission checking in the receiver callbacks

Hi Philipp.

On Tue, Sep 29, 2009 at 04:48:07PM +0200, Philipp Reisner ([email protected]) wrote:
> Various users of the connector should actually check if the
> sender's capabilities of a netlink/connector packet are
> actually sufficient for the operation they trigger. Up to
> now the connector framework did not allow the kernel side
> receiver to do so.
>
> This patch set does the groundwork.
>
> Philipp Reisner (4):
> connector: Keep the skb in cn_callback_data
> connector: Provide the sender's credentials to the callback
> connector/dm: Fixed a compilation warning
> connector: Removed the destruct_data callback since it is always
> kfree_skb()

Patches look good to me.
Andrew please apply to the appropriate tree. I do not know whether it is
acceptible now, since it is not a bugfix, but merely a simple cleanup.
Feel free to add my signed off or ack, thank you.

> Documentation/connector/cn_test.c | 2 +-
> Documentation/connector/connector.txt | 8 ++++----
> drivers/connector/cn_queue.c | 12 +++++++-----
> drivers/connector/connector.c | 22 ++++++++--------------
> drivers/md/dm-log-userspace-transfer.c | 3 +--
> drivers/staging/dst/dcore.c | 2 +-
> drivers/staging/pohmelfs/config.c | 2 +-
> drivers/video/uvesafb.c | 2 +-
> drivers/w1/w1_netlink.c | 2 +-
> include/linux/connector.h | 11 ++++-------
> 10 files changed, 29 insertions(+), 37 deletions(-)

--
Evgeniy Polyakov

2009-09-30 13:20:33

by Lars Ellenberg

[permalink] [raw]
Subject: Re: [PATCH] connector: Allow permission checking in the receiver callbacks

On Wed, Sep 30, 2009 at 03:20:57PM +0400, Evgeniy Polyakov wrote:
> Hi Philipp.
>
> On Tue, Sep 29, 2009 at 04:48:07PM +0200, Philipp Reisner ([email protected]) wrote:
> > Various users of the connector should actually check if the
> > sender's capabilities of a netlink/connector packet are
> > actually sufficient for the operation they trigger. Up to
> > now the connector framework did not allow the kernel side
> > receiver to do so.
> >
> > This patch set does the groundwork.
> >
> > Philipp Reisner (4):
> > connector: Keep the skb in cn_callback_data
> > connector: Provide the sender's credentials to the callback
> > connector/dm: Fixed a compilation warning
> > connector: Removed the destruct_data callback since it is always
> > kfree_skb()
>
> Patches look good to me.
> Andrew please apply to the appropriate tree. I do not know whether it is
> acceptible now, since it is not a bugfix, but merely a simple cleanup.
> Feel free to add my signed off or ack, thank you.

Thanks.

Actually it is the basis for follow-up security fixes.

Without this, unprivileged user space is able to send arbitrary
connector requests to kernel subsystems, which have no way to verify the
privileges of the sender anymore, because that information, even though
available at the netlink layer, has been dropped by the connector.

Once this is applied, the various in-kernel receiving connector
callbacks can (and need to) add cap_raised(nsb->eff_cap, cap) where
appropriate. For example, you don't want some guest user to be able to
trigger a dst_del_node callback by sending a crafted netlink message,
right?

So it _is_ a (design-) bug fix.
Or am I missing something?

Lars

2009-09-30 19:29:27

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [PATCH] connector: Allow permission checking in the receiver callbacks

On Wed, Sep 30, 2009 at 03:20:35PM +0200, Lars Ellenberg ([email protected]) wrote:
> Actually it is the basis for follow-up security fixes.
>
> Without this, unprivileged user space is able to send arbitrary
> connector requests to kernel subsystems, which have no way to verify the
> privileges of the sender anymore, because that information, even though
> available at the netlink layer, has been dropped by the connector.

It is not. One can add some checks at receiving time which happens in
process context to get its credentials, but nothing in netlink itself
carry this info. Getting that connector schedules workqueue this ability
is lost.

> Once this is applied, the various in-kernel receiving connector
> callbacks can (and need to) add cap_raised(nsb->eff_cap, cap) where
> appropriate. For example, you don't want some guest user to be able to
> trigger a dst_del_node callback by sending a crafted netlink message,
> right?
>
> So it _is_ a (design-) bug fix.
> Or am I missing something?

This patchset is not a bugfix, just a cleanup, since none in patchset
uses netlink_skb_parms and currently I see no users which are affected
by this behaviour in the mainline branch (not counting staging tree).

But if proposed configuration changes for DM are on the way, then I
agree and they should force this patchset into the tree as a bugfix.

--
Evgeniy Polyakov

2009-10-01 08:01:51

by Lars Ellenberg

[permalink] [raw]
Subject: Re: [PATCH] connector: Allow permission checking in the receiver callbacks

On Wed, Sep 30, 2009 at 11:29:28PM +0400, Evgeniy Polyakov wrote:
> On Wed, Sep 30, 2009 at 03:20:35PM +0200, Lars Ellenberg ([email protected]) wrote:
> > Actually it is the basis for follow-up security fixes.
> >
> > Without this, unprivileged user space is able to send arbitrary
> > connector requests to kernel subsystems, which have no way to verify the
> > privileges of the sender anymore, because that information, even though
> > available at the netlink layer, has been dropped by the connector.
>
> It is not. One can add some checks at receiving time which happens in
> process context to get its credentials, but nothing in netlink itself
> carry this info. Getting that connector schedules workqueue this ability
> is lost.

Please correct me if I'm wrong.

My understanding is, that in netlink_sendmsg, the credentials and
capabilities are copied into skb->cb.
During kernel side receive, these can be checked.

If we pass the skb, instead of just the msg, then even an asynchronously
scheduled receive callback, running in any workqueue or other context,
can check for these credentials.

Passing skb instead of just the msg for use in cn_queue_wrapper
is what the fist patch does.

Second patch changes the semantics of the actual callback
to be passed in the msg _and_ the netlink_skb_parms, both
"reconstructed" from the skb.

Now, in the end-user callback, there is the actual msg,
but also the netlink_skb_parms.
So this enables the end-user callback, running in arbitrary context,
to check capabilities and other credentials of the sending process.


> > Once this is applied, the various in-kernel receiving connector
> > callbacks can (and need to) add cap_raised(nsb->eff_cap, cap) where
> > appropriate. For example, you don't want some guest user to be able to
> > trigger a dst_del_node callback by sending a crafted netlink message,
> > right?
> >
> > So it _is_ a (design-) bug fix.
> > Or am I missing something?
>
> This patchset is not a bugfix, just a cleanup, since none in patchset
> uses netlink_skb_parms

3. and 4. patch are in fact merely cleanups.

> and currently I see no users which are affected
> by this behaviour in the mainline branch (not counting staging tree).
>
> But if proposed configuration changes for DM are on the way, then I
> agree and they should force this patchset into the tree as a bugfix.
>
> --
> Evgeniy Polyakov
>

--
: Lars Ellenberg
: LINBIT | Your Way to High Availability
: DRBD/HA support and consulting http://www.linbit.com

DRBD? and LINBIT? are registered trademarks of LINBIT, Austria.

2009-10-04 10:23:59

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [PATCH] connector: Allow permission checking in the receiver callbacks

Hi.

On Thu, Oct 01, 2009 at 10:01:52AM +0200, Lars Ellenberg ([email protected]) wrote:
> Please correct me if I'm wrong.

You are right, and I did not argue that patchset is wrong. I just did
not mark it as bugfix, since there were no seriously affected users
(including vesa). But if you push DM changes, which are affected, then
this patchset must be pushed first of course.
Iff DM changes are about to be submitted in the next window, I see no
problems postponing this patchset either.

--
Evgeniy Polyakov

2009-10-04 21:51:48

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] connector: Keep the skb in cn_callback_data

On Tue, 29 Sep 2009 16:48:08 +0200 Philipp Reisner <[email protected]> wrote:

> Signed-off-by: Philipp Reisner <[email protected]>
> Acked-by: Lars Ellenberg <[email protected]>

Please don't send unchangelogged patches.

> diff --git a/include/linux/connector.h b/include/linux/connector.h
> index 47ebf41..05a7a14 100644
> --- a/include/linux/connector.h
> +++ b/include/linux/connector.h
> @@ -134,8 +134,8 @@ struct cn_callback_id {
> struct cn_callback_data {
> void (*destruct_data) (void *);
> void *ddata;
> -
> - void *callback_priv;
> +
> + struct sk_buff *skb;
> void (*callback) (struct cn_msg *);
>
> void *free;

This one replaces the void* private pointer with the skb but you didn't
explain to us why this was done.

Also, the patch does two things. It _adds_ the skb pointer and it also
_removes_ the opaque void* private-data pointer for the callbacks.
What are the implications of removing callback_priv? Why was this done?

2009-10-04 21:54:34

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] connector: Provide the sender's credentials to the callback

On Tue, 29 Sep 2009 16:48:09 +0200 Philipp Reisner <[email protected]> wrote:

> Signed-off-by: Philipp Reisner <[email protected]>
> Acked-by: Lars Ellenberg <[email protected]>

Please don't send unchangelogged patches.

The title tells us what the patch does, but how is the reader supposed
to work out why it does it?

> diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
> index ba0edad..556131f 100644
> --- a/drivers/md/dm-log-userspace-transfer.c
> +++ b/drivers/md/dm-log-userspace-transfer.c
> @@ -129,7 +129,7 @@ static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr)
> * This is the connector callback that delivers data
> * that was sent from userspace.
> */
> -static void cn_ulog_callback(void *data)
> +static void cn_ulog_callback(void *data, struct netlink_skb_parms *nsp)
> {
> struct cn_msg *msg = (struct cn_msg *)data;
> struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);

Your "connector/dm: Fixed a compilation warning" fix is already in
linux-next, so we throw a small and easily-fixed reject here.

2009-10-04 21:58:39

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] connector: Removed the destruct_data callback since it is always kfree_skb()

On Tue, 29 Sep 2009 16:48:11 +0200 Philipp Reisner <[email protected]> wrote:

> Signed-off-by: Philipp Reisner <[email protected]>
> Acked-by: Lars Ellenberg <[email protected]>

Please don't send unchangelogged patches.

> index 163c3e3..210338e 100644
> --- a/drivers/connector/cn_queue.c
> +++ b/drivers/connector/cn_queue.c
> @@ -83,8 +83,8 @@ void cn_queue_wrapper(struct work_struct *work)
>
> d->callback(msg, nsp);
>
> - d->destruct_data(d->ddata);
> - d->ddata = NULL;
> + kfree_skb(d->skb);
> + d->skb = NULL;
>
> kfree(d->free);
> }

So.. why is this a good thing to do? The patchset removes the option
of ever putting anything other than an skb* into the callback data, it
does this without any dicussion or justification and it does it under
the guise of "allowing permission checking in the receiver callbacks".