LKML Archive on lore.kernel.org
 help / color / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
						download: 
* [PATCH 2.6.20] reiserfs: Use ARRAY_SIZE macro when appropriate
  @ 2007-02-06 16:08 99% ` Ahmed S. Darwish
  2007-02-06 16:09 99% ` [PATCH 2.6.20] toshiba-acpi: " Ahmed S. Darwish
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-02-06 16:08 UTC (permalink / raw)
  To: reiserfs-dev; +Cc: linux-kernel, reiserfs-list

Hi all,

A patch to use ARRAY_SIZE macro already defined in kernel.h

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
index fba304e..f85c5cf 100644
--- a/fs/reiserfs/do_balan.c
+++ b/fs/reiserfs/do_balan.c
@@ -19,6 +19,7 @@
 #include <linux/time.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/buffer_head.h>
+#include <linux/kernel.h>
 
 #ifdef CONFIG_REISERFS_CHECK
 
@@ -1756,7 +1757,7 @@ static void store_thrown(struct tree_balance *tb, struct buffer_head *bh)
 	if (buffer_dirty(bh))
 		reiserfs_warning(tb->tb_sb,
 				 "store_thrown deals with dirty buffer");
-	for (i = 0; i < sizeof(tb->thrown) / sizeof(tb->thrown[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(tb->thrown); i++)
 		if (!tb->thrown[i]) {
 			tb->thrown[i] = bh;
 			get_bh(bh);	/* free_thrown puts this */
@@ -1769,7 +1770,7 @@ static void free_thrown(struct tree_balance *tb)
 {
 	int i;
 	b_blocknr_t blocknr;
-	for (i = 0; i < sizeof(tb->thrown) / sizeof(tb->thrown[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(tb->thrown); i++) {
 		if (tb->thrown[i]) {
 			blocknr = tb->thrown[i]->b_blocknr;
 			if (buffer_dirty(tb->thrown[i]))


-- 
Ahmed S. Darwish
http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH 2.6.20] toshiba-acpi: Use ARRAY_SIZE macro when appropriate
    2007-02-06 16:08 99% ` [PATCH 2.6.20] reiserfs: Use ARRAY_SIZE macro when appropriate Ahmed S. Darwish
@ 2007-02-06 16:09 99% ` Ahmed S. Darwish
  2007-02-06 16:09 99% ` [PATCH 2.6.20] w1: " Ahmed S. Darwish
  2007-02-06 16:10 99% ` [PATCH 2.6.20] drm: " Ahmed S. Darwish
  3 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-02-06 16:09 UTC (permalink / raw)
  To: toshiba_acpi; +Cc: linux-kernel

Hi all,

A patch to use ARRAY_SIZE macro already defined in kernel.h

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index d9b651f..0208d3a 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -125,7 +125,7 @@ static int write_acpi_int(const char *methodName, int val)
 	union acpi_object in_objs[1];
 	acpi_status status;
 
-	params.count = sizeof(in_objs) / sizeof(in_objs[0]);
+	params.count = ARRAY_SIZE(in_objs);
 	params.pointer = in_objs;
 	in_objs[0].type = ACPI_TYPE_INTEGER;
 	in_objs[0].integer.value = val;

-- 
Ahmed S. Darwish
http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH 2.6.20] w1: Use ARRAY_SIZE macro when appropriate
    2007-02-06 16:08 99% ` [PATCH 2.6.20] reiserfs: Use ARRAY_SIZE macro when appropriate Ahmed S. Darwish
  2007-02-06 16:09 99% ` [PATCH 2.6.20] toshiba-acpi: " Ahmed S. Darwish
@ 2007-02-06 16:09 99% ` Ahmed S. Darwish
  2007-02-06 16:10 99% ` [PATCH 2.6.20] drm: " Ahmed S. Darwish
  3 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-02-06 16:09 UTC (permalink / raw)
  To: johnpol; +Cc: linux-kernel

Hi all,

A patch to use ARRAY_SIZE macro already defined in kernel.h

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index b022fff..732db47 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -141,7 +141,7 @@ static inline int w1_convert_temp(u8 rom[9], u8 fid)
 {
 	int i;
 
-	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
+	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
 		if (w1_therm_families[i].f->fid == fid)
 			return w1_therm_families[i].convert(rom);
 
@@ -238,7 +238,7 @@ static int __init w1_therm_init(void)
 {
 	int err, i;
 
-	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) {
+	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
 		err = w1_register_family(w1_therm_families[i].f);
 		if (err)
 			w1_therm_families[i].broken = 1;
@@ -251,7 +251,7 @@ static void __exit w1_therm_fini(void)
 {
 	int i;
 
-	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
+	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
 		if (!w1_therm_families[i].broken)
 			w1_unregister_family(w1_therm_families[i].f);
 }


-- 
Ahmed S. Darwish
http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH 2.6.20] drm: Use ARRAY_SIZE macro when appropriate
                     ` (2 preceding siblings ...)
  2007-02-06 16:09 99% ` [PATCH 2.6.20] w1: " Ahmed S. Darwish
@ 2007-02-06 16:10 99% ` Ahmed S. Darwish
  3 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-02-06 16:10 UTC (permalink / raw)
  To: airlied; +Cc: linux-kernel, dri-devel

Hi all,

A patch to use ARRAY_SIZE macro already defined in kernel.h

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 62d5fe1..8943ad1 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -72,7 +72,7 @@ static struct drm_proc_list {
 #endif
 };
 
-#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
+#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list)
 
 /**
  * Initialize the DRI proc filesystem for a device.


-- 
Ahmed S. Darwish
http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH 2.6.20] isdn-capi: Use ARRAY_SIZE macro when appropriate
  @ 2007-02-06 20:41 95%   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-02-06 20:41 UTC (permalink / raw)
  To: Joe Perches; +Cc: kkeil, kai.germaschewski, linux-kernel, isdn4linux

On Tue, Feb 06, 2007 at 09:52:17AM -0800, Joe Perches wrote:
> On Tue, 2007-02-06 at 18:04 +0200, Ahmed S. Darwish wrote:
> > A patch to use ARRAY_SIZE macro already defined in kernel.h
> > Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
[...]
> > -    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
> > +    int nelem = ARRAY_SIZE(procfsentries);
> >      int i;
> >  
> >      for (i=0; i < nelem; i++) {
> 
> For these patches, perhaps you can eliminate the temporary
> variable and change the loop to the more common form of
> 
> 	for (i = 0; i < ARRAY_SIZE(array); i++) {

Thanks, I think it's better too. Here's the modified patch.

A patch to use ARRAY_SIZE macro when appropriate.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index d22c022..87fe89c 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1456,10 +1456,9 @@ static struct procfsentries {
 
 static void __init proc_init(void)
 {
-    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
     int i;
 
-    for (i=0; i < nelem; i++) {
+    for (i = 0; i < ARRAY_SIZE(procfsentries); i++) {
         struct procfsentries *p = procfsentries + i;
 	p->procent = create_proc_entry(p->name, p->mode, NULL);
 	if (p->procent) p->procent->read_proc = p->read_proc;
@@ -1468,10 +1467,9 @@ static void __init proc_init(void)
 
 static void __exit proc_exit(void)
 {
-    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
     int i;
 
-    for (i=nelem-1; i >= 0; i--) {
+    for (i = ARRAY_SIZE(procfsentries) - 1; i >= 0; i--) {
         struct procfsentries *p = procfsentries + i;
 	if (p->procent) {
 	   remove_proc_entry(p->name, NULL);
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index c4d438c..cff5d1e 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -2218,10 +2218,9 @@ static struct procfsentries {
 
 static void __init proc_init(void)
 {
-    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
     int i;
 
-    for (i=0; i < nelem; i++) {
+    for (i = 0; i < ARRAY_SIZE(procfsentries); i++) {
         struct procfsentries *p = procfsentries + i;
 	p->procent = create_proc_entry(p->name, p->mode, NULL);
 	if (p->procent) p->procent->read_proc = p->read_proc;
@@ -2230,10 +2229,9 @@ static void __init proc_init(void)
 
 static void __exit proc_exit(void)
 {
-    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
     int i;
 
-    for (i=nelem-1; i >= 0; i--) {
+    for (i = ARRAY_SIZE(procfsentries) - 1; i >= 0; i--) {
         struct procfsentries *p = procfsentries + i;
 	if (p->procent) {
 	   remove_proc_entry(p->name, NULL);


-- 
Ahmed S. Darwish
http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 95%]

* Re: [PATCH 2.6.20] isdn-capi: Use ARRAY_SIZE macro when appropriate
  @ 2007-02-07 19:41 99%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-02-07 19:41 UTC (permalink / raw)
  To: Philippe De Muyter
  Cc: Joe Perches, kkeil, kai.germaschewski, linux-kernel, isdn4linux

On Tue, Feb 06, 2007 at 10:18:14PM +0100, Philippe De Muyter wrote:
> On Tue, Feb 06, 2007 at 10:41:30PM +0200, Ahmed S. Darwish wrote:
> >  
> > -    for (i=nelem-1; i >= 0; i--) {
> > +    for (i = ARRAY_SIZE(procfsentries) - 1; i >= 0; i--) {
> 
> I would write such decrementing loops as :
> 
>        for (i = ARRAY_SIZE(procfsentries); --i >= 0; ) {
> 
> Long time ago, that produced better code.  I did not check recently though.
[...]
> > -    for (i=nelem-1; i >= 0; i--) {
> > +    for (i = ARRAY_SIZE(procfsentries) - 1; i >= 0; i--) {
> 
> Same here

Hi Philippe,

Won't this hurt readability ?. I'm not a gcc guru anyway to have an
opinion on such stuff :).

-- 
Ahmed S. Darwish
http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [patch 1/2] natsemi: Add support for using MII port with no PHY
  @ 2007-02-14 13:28 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-02-14 13:28 UTC (permalink / raw)
  To: Mark Brown; +Cc: Tim Hockin, Jeff Garzik, netdev, linux-kernel

On Wed, Feb 14, 2007 at 10:02:04AM +0000, Mark Brown wrote:

> Signed-Off-By: Mark Brown <broonie@sirena.org.uk>
> 
[...]
> -		if (np->phy_addr_external == PHY_ADDR_NONE) {
> +		/* If we're ignoring the PHY it doesn't matter if we can't
> +		 * find one. */
> +		if (!np->ignore_phy && np->phy_addr_external == PHY_ADDR_NONE) {
[...]
> +	if (!np->ignore_phy) {
> +		/* The link status field is latched: it remains low
> +		 * after a temporary link failure until it's read. We
> +		 * need the current link status, thus read twice.
> +		 */
> +		mdio_read(dev, MII_BMSR);
> +		bmsr = mdio_read(dev, MII_BMSR);
[...]
>  	/*
> +	 * If we're ignoring the PHY then autoneg and the internal
> +	 * transciever are really not going to work so don't let the
> +	 * user select them.
> +	 */
> +	if (np->ignore_phy && (ecmd->autoneg == AUTONEG_ENABLE ||

A trivial comment actually, Is there a point to write multi-line comments 
in two different formats ?

Thanks,

-- 
Ahmed S. Darwish
http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Video GL rendering worked only between 2.6.20 and 2.6.21-rc1
@ 2007-02-23 18:07 99% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-02-23 18:07 UTC (permalink / raw)
  To: linux-kernel

Hi list,

Aiglx/Beryl effects (transparency and other stuff) on windows that display 
video worked magically for the first time in a pull point between 2.6.20 and 
2.6.21-rc1. Unfortunately It doesn't work again now in 2.6.21-rc1 and even in 
2.6.20-mm{1,2}.

I'm not able to find the good commit again :(. Could someone please tell
me the files that is most probably responsible for video GL rendering 
so I can track their changes and find the good commit.

The machine is a Centrino laptop with an i810 card. So I guess those are 
the responsible files:
    
    drivers/char/drm/i810_*.c
    drivers/video/i810/*

Any more probably responsible files? 

Thanks,

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH] drivers/media/video/videocodec.c: check kmalloc() return value.
  @ 2007-03-12 10:45 99% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-12 10:45 UTC (permalink / raw)
  To: Amit Choudhary; +Cc: Linux Kernel

Hi Amit,

On Thu, Mar 08, 2007 at 11:14:01PM -0800, Amit Choudhary wrote:
> Description: Check the return value of kmalloc() in function 
> videocodec_build_table(), in file drivers/media/video/videocodec.c.

No need for `Description:'. This line is automatically put in the logs 
as a patch description if the patch got accepted. 

It's better not to use very large lines. 

Also there's no need to specify the exact function in the log, it's already
displayed in the patch.

> 
> Signed-off-by: Amit Choudhary <amit2030@gmail.com>
> 

As said in Documentation/SubmittingPatches put a "---" line after
Signed-off-by signature.

Thanks,

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* [PATCH 2.6.21-rc4] kernel/exit: Fix a comment and code contradiction
@ 2007-03-17  6:21 99% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-03-17  6:21 UTC (permalink / raw)
  To: kernel-janitors, linux-kernel; +Cc: trivial

Hi list,

Comment in release_task() claims that group leader's parent process 
is signalled only if it desires so, which is not true.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

To save your time, here's the contradictory code which don't appear in 
the patch (appears after its last line):

      leader = p->group_leader;
      if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) {
		BUG_ON(leader->exit_signal == -1);
		do_notify_parent(leader, leader->exit_signal);


diff --git a/kernel/exit.c b/kernel/exit.c
index f132349..4a0a35f 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -152,7 +152,7 @@ repeat:
 	/*
 	 * If we are the last non-leader member of the thread
 	 * group, and the leader is zombie, then notify the
-	 * group leader's parent process. (if it wants notification.)
+	 * group leader's parent process.
 	 */
 	zap_leader = 0;
 	leader = p->group_leader;

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH 2.6.21-rc4] kernel/exit: Fix a comment and code contradiction
  @ 2007-03-17 15:00 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-17 15:00 UTC (permalink / raw)
  To: hannes-kernel; +Cc: kernel-janitors, linux-kernel, trivial

[Johannes please use replay-to-all to notify all readers]

On 2007-03-17 9:45:36 Johannes Weiner wrote:
> On Sat, Mar 17, 2007 at 08:21:32AM +0200, Ahmed S. Darwish wrote:
> > Comment in release_task() claims that group leader's parent process 
> > is signalled only if it desires so, which is not true.
>
> AFAIS, `if it wants notification' means, it does not ignore its children
> via SIG_IGN als handler for SIGCHLD.
>

AFAIK, exit_signal = -1 means that the parent don't want to be signalled,
like what happenes when using CLONE_THREAD. 

But it's even signalled in that case (after issuing a BUG):
   BUG_ON(leader->exit_signal == -1);
   do_notify_parent(leader, leader->exit_signal);

> do_notify_parent() checks if the parent wants to get informed about the
> child states.
>

Yes it does the check but it notifies the given task_struct anyway:

	BUG_ON(sig == -1);
	[ Continue parent notification normally ]
-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* i386: Why putting __USER_DS in kernel threads stack initialization?
@ 2007-03-18 22:58 99% Ahmed S. Darwish
  2007-03-18 23:15 99% ` Ahmed S. Darwish
    0 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-18 22:58 UTC (permalink / raw)
  To: linux-kernel

Hi list,

Reading the kernel threads initialization code I see:

int kernel_thread(...) {

	struct pt_regs regs;
	memset(&regs, 0, sizeof(regs));
	[...]
**	regs.xds = __USER_DS;
**	regs.xes = __USER_DS;
	[...]
	/* Ok, create the new process.. */
	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, \
	       	       0, NULL, NULL);

Continuing with the code, the threads stack (beginning from %esp) is
initialized with the passed *regs from do_fork:

int copy_thread(..., struct task_struct *p, struct pt_regs *regs) {

	struct pt_regs * childregs;
	struct task_struct *tsk;
 	childregs = task_pt_regs(p);
**	*childregs = *regs;
	[...]
** 	p->thread.esp = (unsigned long) childregs;


So the question is what will a _kernel_ thread do with the Usermode Segment
address ?

Thanks,

P.S. I've tried commenting out both lines which led to a non functional init,
Also setting them to __USER_DS made init start but stopped issuing the error:
`Panic: Segment violation at 0x8049798 - Sleeping for 30 seconds'

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: i386: Why putting __USER_DS in kernel threads stack initialization?
  2007-03-18 22:58 99% i386: Why putting __USER_DS in kernel threads stack initialization? Ahmed S. Darwish
@ 2007-03-18 23:15 99% ` Ahmed S. Darwish
    1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-18 23:15 UTC (permalink / raw)
  To: linux-kernel

On Mon, Mar 19, 2007 at 12:58:31AM +0200, ahmed wrote:
> 
> P.S. I've tried commenting out both lines which led to a non functional init,
> Also setting them to __USER_DS made init start but stopped issuing the error:
> `Panic: Segment violation at 0x8049798 - Sleeping for 30 seconds'
> 

Sorry, I meant setting them to __KERNEL_DS.

Thanks,

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: i386: Why putting __USER_DS in kernel threads stack initialization?
  @ 2007-03-21 19:25 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-21 19:25 UTC (permalink / raw)
  To: linux-os (Dick Johnson); +Cc: Linux kernel

On Mon, Mar 19, 2007 at 07:23:25AM -0400, linux-os (Dick Johnson) wrote:
> 
> On Sun, 18 Mar 2007, Ahmed S. Darwish wrote:
> 
> > Hi list,
> >
> > Reading the kernel threads initialization code I see:
> >
> > int kernel_thread(...) {
> >
> > 	struct pt_regs regs;
> > 	memset(&regs, 0, sizeof(regs));
> > 	[...]
> > **	regs.xds = __USER_DS;
> > **	regs.xes = __USER_DS;
> > 	[...]
> > 	/* Ok, create the new process.. */
> > 	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, \
> > 	       	       0, NULL, NULL);
> >
> > Continuing with the code, the threads stack (beginning from %esp) is
> > initialized with the passed *regs from do_fork:
> >
> > int copy_thread(..., struct task_struct *p, struct pt_regs *regs) {
> >
> > 	struct pt_regs * childregs;
> > 	struct task_struct *tsk;
> > 	childregs = task_pt_regs(p);
> > **	*childregs = *regs;
> > 	[...]
> > ** 	p->thread.esp = (unsigned long) childregs;
> >
> >
> > So the question is what will a _kernel_ thread do with the Usermode Segment
> > address ?
> >
> > Thanks,
> >
> > P.S. I've tried commenting out both lines which led to a non functional init,
> > Also setting them to __USER_DS made init start but stopped issuing the error:
> > `Panic: Segment violation at 0x8049798 - Sleeping for 30 seconds'
> >

Sorry, I meant "setting them to __KERNEL_DS" here.

> 
> You might be confusing two routines. The kernel thread routine sets
> DS and ES to the kernel data segment, __KERNEL_DS, not the user data
> segment. 

And that's what's _not_ happening in the code as I mentioned in original post.

> This is so the kernel thread can access the kernel data. Note
> that this is done by putting the values in the pt_regs structure so
> it doesn't happen 'now', but after the fork.

I've searched the code for such case (setting xds to __KERNEL_DS _After_ 
copy_thread()) with no success. As I understand, the kernel thread 
executes the passed function immediately (when given control by scheduler):

i386/kernel/process::kernel_thread():
**	regs.ebx = (unsigned long) fn;
	regs.edx = (unsigned long) arg;
	regs.xds = __USER_DS;
	regs.xes = __USER_DS;
	regs.xfs = __KERNEL_PDA;
	regs.orig_eax = -1;
**	regs.eip = (unsigned long) kernel_thread_helper;
	do_fork(...)

entry.S::kernel_thread_helper (removing CFI_* pseudo ops):

   ENTRY(kernel_thread_helper)
	pushl $0		
	movl %edx,%eax
	push %edx
**	call *%ebx
	push %eax
	call do_exit
	
Am I interpreting the forking process completely wrong?. I'm just curious why 
the __USER_DS is playing a vital rule in kernel threads regs/stack ?

Thanks alot,

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: PATCH: tun/tap driver hw address handling
  @ 2007-03-24 17:04 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-24 17:04 UTC (permalink / raw)
  To: Brian Braunstein; +Cc: Max Krasnyansky, torvalds, linux-kernel, rajesh_mish

Hi Brian,

On Sat, Mar 24, 2007 at 01:56:50AM -0700, Brian Braunstein wrote:
> 
> Linus,
> 
>  According to Documentation/SubmittingPatches "bug fixes" or "obvious" 
> changes
>  should CCed to you, so this is why I have done this.
>

IMHO these days patches got reviewed on LKML, then tested enough on the
unstable -mm tree then it got added to mainline kernel. Subsystem maintaners
can also add patches directly to mainline if they're trivial enough.
 
> Note: This entire email can be found at
> http://bristyle.com/share/patch-tuntap-hw_addr_handling.txt
> 

I think No need for such two lines. everyone uses his favourite LKML archive.

>  Summary:
>    Fix tun/tap driver's handling of hw addresses.  Specifically, ensure 
> that
>    when the tun.dev_addr field is set, the net_device.dev_addr field gets
>    set to the same value.
> 
>  Background:
>    The device hw address is stored in 2 places, in the tun.dev_addr field,
>    and of course the net_device struct's dev_addr field.  It really 
> seems to
>    me that the tun.dev_addr field is redundant, and that anywhere it is 
> used

Editor/mailer wrapping your lines badly ?

> 
> --- linux-2.6.20.4-ORIG/drivers/net/tun.c       2007-03-23 
> 12:52:51.000000000 -0700
> +++ linux-2.6.20.4/drivers/net/tun.c    2007-03-24 01:36:59.000000000 -0700
> @@ -18,6 +18,11 @@

Please reread SubmittingPatches to know the canonical patch format (missing
Signed-off-by and others).

> /*
>  *  Changes:
>  *
> + *  Brian Braunstein <linuxkernel@bristyle.com> 2007/03/23
> + *    Fixed hw address handling.  Now net_device.dev_addr is kept 
> consistent
[Remaing patch]

Patch can't be applied or even read cause your mailer has mistakenly wrapped
its lines.

Regards,

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* [PATCH] IRQ: Check for PERCPU flag only when adding first irqaction.
@ 2007-03-26 19:14 99% Ahmed S. Darwish
  2007-03-27  8:54 99% ` Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-03-26 19:14 UTC (permalink / raw)
  To: linux-kernel

Hi,

An irqaction structure won't be added to the IRQ line irqaction list if they
don't agree wrt the IRQF_PERCPU flag. Only check and set this flag in IRQ
descriptor `status' field when the first irqaction is added to the line list.


Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

Patch over 2.6.21-rc5.

diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 5597c15..ea82a54 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -317,10 +317,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 	}
 
 	*p = new;
-#if defined(CONFIG_IRQ_PER_CPU)
-	if (new->flags & IRQF_PERCPU)
-		desc->status |= IRQ_PER_CPU;
-#endif
+
 	/* Exclude IRQ from balancing */
 	if (new->flags & IRQF_NOBALANCING)
 		desc->status |= IRQ_NO_BALANCING;
@@ -328,6 +325,11 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 	if (!shared) {
 		irq_chip_set_defaults(desc->chip);
 
+#if defined(CONFIG_IRQ_PER_CPU)
+		if (new->flags & IRQF_PERCPU)
+			desc->status |= IRQ_PER_CPU;
+#endif
+		
 		/* Setup the type (level, edge polarity) if configured: */
 		if (new->flags & IRQF_TRIGGER_MASK) {
 			if (desc->chip && desc->chip->set_type)

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] net: tun/tap: fixed hw address handling
  @ 2007-03-26 20:55 99% ` Ahmed S. Darwish
  2007-03-26 21:05 99%   ` Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-03-26 20:55 UTC (permalink / raw)
  To: Brian Braunstein
  Cc: Max Krasnyansky, vtun, akpm, jgarzik, netdev, linux-kernel

On Sun, Mar 25, 2007 at 01:29:29AM -0700, Brian Braunstein wrote:
> 
> From: Brian Braunstein <linuxkernel@bristyle.com>
> 

No need for this line. This line is used when you _forward_ another patch
from others. Signed-off-by is enough

> 
> Signed-off-by: Brian Braunstein <linuxkernel@bristyle.com>
> 
> ---
> 
> Kernel Version: 2.6.20.4
> 

It's always better to generate the patch against the latest -rc kernel.

> --- linux-2.6.20.4-ORIG/drivers/net/tun.c	2007-03-23 
> 12:52:51.000000000 -0700
> +++ linux-2.6.20.4/drivers/net/tun.c	2007-03-25 00:44:20.000000000 -0700
> @@ -18,6 +18,10 @@
> /*
>  *  Changes:
>  *
> + *  Brian Braunstein <linuxkernel@bristyle.com> 2007/03/23
> + *    Fixed hw address handling.  Now net_device.dev_addr is kept 
> consistent

Your mailer still wrap the long lines mistakenly as it did in the first
version of the patch.

Regards,

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH] net: tun/tap: fixed hw address handling
  2007-03-26 20:55 99% ` Ahmed S. Darwish
@ 2007-03-26 21:05 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-26 21:05 UTC (permalink / raw)
  To: Brian Braunstein
  Cc: Max Krasnyansky, vtun, akpm, jgarzik, netdev, linux-kernel

On Mon, Mar 26, 2007 at 10:55:11PM +0200, ahmed wrote:
> On Sun, Mar 25, 2007 at 01:29:29AM -0700, Brian Braunstein wrote:
> > --- linux-2.6.20.4-ORIG/drivers/net/tun.c	2007-03-23 
> > 12:52:51.000000000 -0700
> > +++ linux-2.6.20.4/drivers/net/tun.c	2007-03-25 00:44:20.000000000 -0700
> > @@ -18,6 +18,10 @@
> > /*
> >  *  Changes:
> >  *
> > + *  Brian Braunstein <linuxkernel@bristyle.com> 2007/03/23
> > + *    Fixed hw address handling.  Now net_device.dev_addr is kept 
> > consistent
> 
> Your mailer still wrap the long lines mistakenly as it did in the first
> version of the patch.
> 

It seems a bug in my mutt mail reader (not a feature, it displays other 
mails long lines without wrapping), sorry.

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH] IRQ: Check for PERCPU flag only when adding first irqaction.
  2007-03-26 19:14 99% [PATCH] IRQ: Check for PERCPU flag only when adding first irqaction Ahmed S. Darwish
@ 2007-03-27  8:54 99% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-27  8:54 UTC (permalink / raw)
  To: linux-kernel

On Mon, Mar 26, 2007 at 09:14:55PM +0200, ahmed wrote:
> Hi,
> 
> An irqaction structure won't be added to the IRQ line irqaction list if they
> don't agree wrt the IRQF_PERCPU flag. Only check and set this flag in IRQ
> descriptor `status' field when the first irqaction is added to the line list.
> 
> 
> Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
> ---
> Patch over 2.6.21-rc5.

Maybe just a better description (with the same patch below):

An irqaction structure won't be added to an IRQ descriptor irqaction list
if it don't agree with other irqactions on the IRQF_PERCPU flag. Don't 
check for this flag to change IRQ descriptor `status' for every irqaction
added to the list, Doing the check only for the first irqaction added is
enough.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 5597c15..ea82a54 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -317,10 +317,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 	}
 
 	*p = new;
-#if defined(CONFIG_IRQ_PER_CPU)
-	if (new->flags & IRQF_PERCPU)
-		desc->status |= IRQ_PER_CPU;
-#endif
+
 	/* Exclude IRQ from balancing */
 	if (new->flags & IRQF_NOBALANCING)
 		desc->status |= IRQ_NO_BALANCING;
@@ -328,6 +325,11 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 	if (!shared) {
 		irq_chip_set_defaults(desc->chip);
 
+#if defined(CONFIG_IRQ_PER_CPU)
+		if (new->flags & IRQF_PERCPU)
+			desc->status |= IRQ_PER_CPU;
+#endif
+		
 		/* Setup the type (level, edge polarity) if configured: */
 		if (new->flags & IRQF_TRIGGER_MASK) {
 			if (desc->chip && desc->chip->set_type)


-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: Student Project Ideas
    @ 2007-03-29 20:44 99% ` Ahmed S. Darwish
  1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-29 20:44 UTC (permalink / raw)
  To: Russ Meyerriecks; +Cc: linux-kernel

On Thu, Mar 29, 2007 at 05:04:08AM -0500, Russ Meyerriecks wrote:
> Hi all,
>  I've been hacking on the Linux kernel all semester for my OS:
> Internals class. We are given full autonomy in picking our final
> programming project and I would love for mine to be /useful/ for the
> Linux kernel and not just a theoretical exorcise. If anybody has any
> bug fixes or features maybe they never got around to, and would be
> suitable for this situation, I would love to hear about them.
> 

I'm a college student too and I wished a wish like that in the past. After 
watching the development process for a while, I realized that somehow
a college final project won't fit with the linux kernel project.
Everything here is done by _evolution_ not a revolution, you'll even see the 
highest matured programmers in this project send little patches day by day. 

And the problem that you can't meet your PH.D and tell him/her: hey, I have
a patch or two, they simply don't understand that ;).

Second, I think it's very hard to make a considerable project in the kernel
without doing some little patches here and there at first. Google for kernel
newbies and kernel janitors.

Regards,

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: Student Project Ideas
  @ 2007-03-29 20:59 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-03-29 20:59 UTC (permalink / raw)
  To: Cong WANG; +Cc: Russ Meyerriecks, linux-kernel, Andrew Morton

On Thu, Mar 29, 2007 at 06:32:21PM +0800, Cong WANG wrote:
> 2007/3/29, Russ Meyerriecks <datachomper@gmail.com>:
> >Hi all,
> >  I've been hacking on the Linux kernel all semester for my OS:
> >Internals class. We are given full autonomy in picking our final
> >programming project and I would love for mine to be /useful/ for the
> >Linux kernel and not just a theoretical exorcise. If anybody has any
> >bug fixes or features maybe they never got around to, and would be
> >suitable for this situation, I would love to hear about them.
> >
> 
> First, I think you can read the book named "Kernel Projects for
> Linux". It's a good book although it's outdated.
> 
> Second, in fact, I am also a college student and also want to find a
> suitable and real task in linux kernel for me to work on. KJ doesn't
> help much. ;-p
> 

No, it really helps alot, just be _patient_. For me, I sent a series of dumb
patches at first to use ARRAY_SIZE macro instead of manual computation. Though
the patches were completely braindead, I learnt alot of stuff about how
everything works here. 

Beside sending this KJ patches, I keep reading from Understanding Linux kernel v3
and reading lots of code everyday. Yesterday my first semi-real patch was
accepted in -mm. I'm sure that day by day my patches will be more real and fix
serious issues. 

All of that wouldn't have smoothly happened without the first step, the KJ step ;).

It seems that being a developer in the kernel community is going exactly like how
code goes, _evolution_ not a revolution. You can't be responsible for a good
project directly, just take your way from a janitor to a subsystem maintaner :).
Ofcourse, unless you have an old experience in other OSs (espcifically Unix ones).

Regards,

-- 
Ahmed S. Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 99%]

* Re: Fork Bombing Attack
  @ 2007-05-18 13:19 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-05-18 13:19 UTC (permalink / raw)
  To: Anand Jahagirdar; +Cc: Valdis.Kletnieks, linux-kernel

On 5/18/07, Anand Jahagirdar <anandjigar@gmail.com> wrote:
> Hello All
>            I tried to execute a program which creates 8152 process.(
> i=0; while( i<14) i++ fork(); )  with ulimit 8200. This program
> created 8152 processes and then stopped and came back to command
> prompt. this proves that my machine do have sufficient resources to
> create 8000 processes.
>
>            I found one more interesting thing on the same machine
> having FC6 distribution and Linux Kernel 2.6.18. i have set "ulimit -u
> 100". after setting this limit i tried to execute fork bombing program
> with guest account. after executing it
>
> expected result:-  guest uesr should not able to fork another single
> process when it reaches to 100 processes count.
>
> actual result :-  kernel allow me to create another processes without
> giving error. due to this i tried to execute same fork bombing program
> on another terminal with guest account and this fork bombing attack
> killed the box completely and machine needed reboot.
>

I think if you want resource limiting per _UID_ (and not per _process_
as you did), you should use PAM module pam_limits.so. You can edit
those limits using the file /etc/security/limits.conf

Regards,
-- 
Ahmed S. Darwish
http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [i386] Questions regarding provisional page tables initialization
@ 2007-07-01 20:38 96% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-07-01 20:38 UTC (permalink / raw)
  To: linux-kernel

Hi list,

AFAIK, in the initializaion phase, kernel builds pages tables with two
mappings, identity and PAGE_OFFSET + C mapping. The provisional _global
directory_ is contained in swapper_pg_dir variable. while the provisional 
_page tables_ are stored starting from pg0, right after _end.

There're some stuff that confused me for a full day about the code (head.S)
that  accomplishes the above words:

	movl $(pg0 - __PAGE_OFFSET), %edi
	movl $(swapper_pg_dir - __PAGE_OFFSET), %edx	
	movl $0x007, %eax			/* 0x007 = PRESENT+RW+USER */
10:
	leal $0x007(%edi),%ecx			/* Create PDE entry */

What does the address of 7 bytes displacement after %edi - the physical address
of pg0 - represent ?. Why not just putting the address of %edi (the address of
pagetable cell to be mapped by swapper_pg_dir) in %ecx without displacement?

        page_pde_offset = (__PAGE_OFFSET >> 20)
	movl %ecx,(%edx)			/* Store identity PDE entry */
	movl %ecx,page_pde_offset(%edx)		/* Store kernel PDE entry */

Why the pde_offset is PAGE_OFFSET >> 20 instead of PAGE_OFFSET >> 22 ?
* 22 to right shift the whole page_shift (12) and pgdir_shift (10) bits.

        [...]
	/* Initialize the 1024 _page table_ cells with %eax (0x007) */
	movl $1024, %ecx
11:
	stosl
	addl $0x1000,%eax
	loop 11b

The page table entries beginning from pg0 (pointed by %edi) and following pages 
are initialized with  the series 7 + 8 + 8 + ... for each cell. This series has
the property of setting the PRESENT+RW+USER bits in the whole entries to 1 but it
sets lots of the entries BASE address to 0 too. Why is this done ?

Thanks,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 96%]

* Re: [i386] Questions regarding provisional page tables initialization
  @ 2007-07-02  1:13 99%   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-07-02  1:13 UTC (permalink / raw)
  To: Jeremy Fitzhardinge; +Cc: linux-kernel

Hi Jeremy,

On Sun, Jul 01, 2007 at 03:19:30PM -0700, Jeremy Fitzhardinge wrote:
> Ahmed S. Darwish wrote:
> >Hi list,
> >
> >AFAIK, in the initializaion phase, kernel builds pages tables with two
> >mappings, identity and PAGE_OFFSET + C mapping. The provisional _global
> >directory_ is contained in swapper_pg_dir variable. while the provisional 
> >_page tables_ are stored starting from pg0, right after _end.
> >
> >There're some stuff that confused me for a full day about the code (head.S)
> >that  accomplishes the above words:
> >
> >	movl $(pg0 - __PAGE_OFFSET), %edi
> >	movl $(swapper_pg_dir - __PAGE_OFFSET), %edx	
> >	movl $0x007, %eax			/* 0x007 = PRESENT+RW+USER */
> >10:
> >	leal $0x007(%edi),%ecx			/* Create PDE entry */
> >
> >What does the address of 7 bytes displacement after %edi - the physical 
> >address
> >of pg0 - represent ?. Why not just putting the address of %edi (the 
> >address of
> >pagetable cell to be mapped by swapper_pg_dir) in %ecx without 
> >displacement?
> >  
> 
> The pte format contains the pfn in the top 20 bits, and flags in the 
> lower 12 bits.  As the comment says "0x007 = PRESENT+RW+USER".
> 

yes, but isn't the displacement here (0x007) a _bytes_ displacement ?. so
effectively, %ecx now contains physical address of pg0 + 7bytes. Is it A 
meaningful place/address ?.

> >        page_pde_offset = (__PAGE_OFFSET >> 20)
> >	movl %ecx,(%edx)			/* Store identity PDE entry 
> >	*/
> >	movl %ecx,page_pde_offset(%edx)		/* Store kernel PDE entry */
> >
> >Why the pde_offset is PAGE_OFFSET >> 20 instead of PAGE_OFFSET >> 22 ?
> >* 22 to right shift the whole page_shift (12) and pgdir_shift (10) bits.
> >  
> 
> As Andreas said, its (PAGE_OFFSET >> 22) << 2.
> 

Great!, Thanks a lot.

> >        [...]
> >	/* Initialize the 1024 _page table_ cells with %eax (0x007) */
> >	movl $1024, %ecx
> >11:
> >	stosl
> >	addl $0x1000,%eax
> >	loop 11b
> >
> >The page table entries beginning from pg0 (pointed by %edi) and following 
> >pages are initialized with  the series 7 + 8 + 8 + ... for each cell. This 
> >series has
> >the property of setting the PRESENT+RW+USER bits in the whole entries to 1 
> >but it
> >sets lots of the entries BASE address to 0 too. Why is this done ?
> >  
> 
> I don't follow you.  Are you overlooking the 'L' on stosl?
> 

Sorry for not making the question clear. my question was that the first entry in
the page table pointed by (%edi) is initialize with %eax = 0x007, a reasonable
value (setting the 3 pte flags). Beginning from entry 2, they got initialized
with a value = "new %eax = old %eax + 8", generating a table of entries
initialized with 7, 15, 31, .. . While this scheme makes the 3 PRESENT, RW 
and USER flags set, it makes alot of "pte"s with equivalent "pfn"s. Here comes 
my wonder, why initializing pg0 that way ?.

Thanks,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [i386] Questions regarding provisional page tables initialization
  @ 2007-07-02 10:23 99%       ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-07-02 10:23 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Jeremy Fitzhardinge, linux-kernel

Hi Andreas,

On Mon, Jul 02, 2007 at 11:18:08AM +0200, Andreas Schwab wrote:
> "Ahmed S. Darwish" <darwish.07@gmail.com> writes:
> 
> > yes, but isn't the displacement here (0x007) a _bytes_ displacement ?. so
> > effectively, %ecx now contains physical address of pg0 + 7bytes. Is it A 
> > meaningful place/address ?.
> 
> It's not pg0 + 7bytes, it is pg0 plus 3 flag bits.  Since a page address
> is always page aligned, the low bits are reused for flags.
> 

I'm sure there's a problem in _my_ understanding, but isn't the displacement
- as specified by AT&T syntax - represented in bytes ?. I've wrote a small
assembly function to be sure:

.data
integer:
	.string "%d\n"

.text
test_func:
	push	%ebp
	mov	%esp, %ebp
	push	0x008(%ebp)   ## 8 bytes displacement (the first arg), right ?
	push	$integer
	call 	printf
	mov	%ebp, %esp
	pop	%ebp
	ret

The above method works fine and prints "5" to stdout by the code:

.global	main
main:
	mov	$5, %eax
	push	%eax
	call	test_func

	movl	$1, %eax
	movl	$0, %ebx
	int	$0x80

now back to head.S code:
 	leal    0x007(%edi),%ecx	/* Create PDE entry */

Isn't the above line the same condition (bytes, not bits displacement) ?. 
Thanks for your patience !.

(For other kind replies, don't understand me wrong. I did my homework and
 studied the pte format before asking ;). It's just the bytes/bits issue 
 above that confuses me).

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [i386] Questions regarding provisional page tables initialization
  @ 2007-07-02 15:43 99%           ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-07-02 15:43 UTC (permalink / raw)
  To: Brian Gerst; +Cc: Andreas Schwab, Jeremy Fitzhardinge, linux-kernel

On Mon, Jul 02, 2007 at 07:34:20AM -0400, Brian Gerst wrote:
> Ahmed S. Darwish wrote:
> > now back to head.S code:
> >  	leal    0x007(%edi),%ecx	/* Create PDE entry */
> > 
> > Isn't the above line the same condition (bytes, not bits displacement) ?. 
> > Thanks for your patience !.
> 
> The leal instruction (Load Effective Address) is often used as a way to
> add a constant to one register and store the result in another register
> in a single instruction.
> [...]

At last I got it due to all of everybody's very nice explanations :). 
Here's the provisional page tables intialization scenario:

We want to store pg0 pte addresses to high 20bits swapper_pg_dir entries,
we also want the PRESENT,RW,USER flags be set in those entries. This is 
done by  getting the address of each pg0 entry and adding 7 to it (Brian's
note). Since pg0 entires address are page aligned(Andreas, Jeremy notes),
adding 7 will assure that the first 3 bits are set without affecting the
high 20 bits.

Big Thanks!,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: PROBLEM: System Freeze on Particular workload with kernel 2.6.22.6
  @ 2007-09-19 19:25 99%     ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-09-19 19:25 UTC (permalink / raw)
  To: Low Yucheng; +Cc: Oleg Verych, linux-kernel, linux-mm, Andrew Morton

Hi Low,

On Wed, Sep 19, 2007 at 12:16:39PM -0400, Low Yucheng wrote:
> There are no additional console messages.
> Not sure what this is: * no relevant Cc (memory management added)

Relevant CCs means CCing maintainers or subsystem mailing lists related to your
bug report. i.e, if it's a networking bug, you need to CC the linux kernel
networking mailing list. If it's a kobject bug, you need to CC its maintainer
(Greg) and so on.

Regards,  

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: PROBLEM: System Freeze on Particular workload with kernel 2.6.22.6
  @ 2007-09-20 15:24 99%         ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-09-20 15:24 UTC (permalink / raw)
  To: Jarek Poplawski
  Cc: Low Yucheng, Oleg Verych, linux-kernel, linux-mm, Andrew Morton

On Thu, Sep 20, 2007 at 12:00:31PM +0200, Jarek Poplawski wrote:
> On 19-09-2007 21:25, Ahmed S. Darwish wrote:
> > Hi Low,
> > 
> > On Wed, Sep 19, 2007 at 12:16:39PM -0400, Low Yucheng wrote:
> >> There are no additional console messages.
> >> Not sure what this is: * no relevant Cc (memory management added)
> > 
> > Relevant CCs means CCing maintainers or subsystem mailing lists related to your
> > bug report. i.e, if it's a networking bug, you need to CC the linux kernel
> > networking mailing list. If it's a kobject bug, you need to CC its maintainer
> > (Greg) and so on.
> 
> So, which one do you recommend here?
> 

I'm not really sure, just wanted to solve Jarek's confusion :).

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* i386: Fix null interrupt handler (ignore_int) message ?
@ 2007-09-24 22:08 99% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-09-24 22:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: hpa

Hi all,

I'm getting little confused by some ignore_int (null interrupt handler) code in
head.S. Code notifies the user about the unknown raised interrupt by below
string:

int_msg:
	.asciz "Unknown interrupt or fault at EIP %p %p %p\n"

and prints it using below code path:

ignore_int:
	pushl %eax; pushl %ecx; pushl %edx; pushl %es; pushl %ds
	[...]
	pushl 16(%esp); pushl 24(%esp); 
	pushl 32(%esp); pushl 40(%esp); 
	pushl $int_msg
	[...]
	call printk

** But here's the state of stack before calling printk:

     ???            <-- 40(%esp)             
     ???            <-- 36(%esp)
     --> (Automatically pushed by the processor)
     %eflags        <-- 32(%esp)
     %cs	    <-- 28(%esp)
     %eip	    <-- 24(%esp)
     error-code     <-- 20(%esp)
     --> (Pushed by first lines of ignore_int)
     %eax	    <-- 16(%esp)
     %ecx	    <--	12(%esp)
     %edx	    <-- 8(%esp)
     %es	    <-- 4(%esp)
     %ds	    <-- %esp      

Does 40(%esp) hold a meaningfule value here ?. Also why passing 4 arguments after
the string to prinkt while the string only has 3 conversion specifications (i.e.,
3 * %p) ?.

Best regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH 1/3] Completely remove deprecated IRQ flags (SA_*)
@ 2007-09-26 22:33 98% Ahmed S. Darwish
  2007-09-26 22:35 99% ` [PATCH 2/3] MIPS: Remove " Ahmed S. Darwish
  2007-09-26 22:36 81% ` [PATCH 3/3] NCR53C8XX: " Ahmed S. Darwish
  0 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2007-09-26 22:33 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm

Hi all,

Only very little files use the deprecated SA_* IRQ flags in latest pull. This
minimal patch series removes such macros from the tree and transfrom old code
to the new IRQF_* flags.

Andrew, I've grepped the whole tree to make sure that no more files than the
patched ones use such deprecated macros. I hope this series won't introduce 
build errors.

Patches can be applied cleanly on v2.6.23-rc8.

==>

Get rid of the deprecated SA_* IRQ flags.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 5523f19..00bdebb 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -55,28 +55,6 @@
 #define IRQF_NOBALANCING	0x00000800
 #define IRQF_IRQPOLL		0x00001000
 
-/*
- * Migration helpers. Scheduled for removal in 9/2007
- * Do not use for new code !
- */
-static inline
-unsigned long __deprecated deprecated_irq_flag(unsigned long flag)
-{
-	return flag;
-}
-
-#define SA_INTERRUPT		deprecated_irq_flag(IRQF_DISABLED)
-#define SA_SAMPLE_RANDOM	deprecated_irq_flag(IRQF_SAMPLE_RANDOM)
-#define SA_SHIRQ		deprecated_irq_flag(IRQF_SHARED)
-#define SA_PROBEIRQ		deprecated_irq_flag(IRQF_PROBE_SHARED)
-#define SA_PERCPU		deprecated_irq_flag(IRQF_PERCPU)
-
-#define SA_TRIGGER_LOW		deprecated_irq_flag(IRQF_TRIGGER_LOW)
-#define SA_TRIGGER_HIGH		deprecated_irq_flag(IRQF_TRIGGER_HIGH)
-#define SA_TRIGGER_FALLING	deprecated_irq_flag(IRQF_TRIGGER_FALLING)
-#define SA_TRIGGER_RISING	deprecated_irq_flag(IRQF_TRIGGER_RISING)
-#define SA_TRIGGER_MASK		deprecated_irq_flag(IRQF_TRIGGER_MASK)
-
 typedef irqreturn_t (*irq_handler_t)(int, void *);
 
 struct irqaction {


Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 98%]

* [PATCH 2/3] MIPS: Remove deprecated IRQ flags (SA_*)
  2007-09-26 22:33 98% [PATCH 1/3] Completely remove deprecated IRQ flags (SA_*) Ahmed S. Darwish
@ 2007-09-26 22:35 99% ` Ahmed S. Darwish
  2007-09-26 22:36 81% ` [PATCH 3/3] NCR53C8XX: " Ahmed S. Darwish
  1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-09-26 22:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, ralf

Hi Ralf,

A patch to stop using deprecated IRQ flags. The new IRQF_* macros are used
instead.


Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/arch/mips/pci/ops-pmcmsp.c b/arch/mips/pci/ops-pmcmsp.c
index 09fa007..a86a189 100644
--- a/arch/mips/pci/ops-pmcmsp.c
+++ b/arch/mips/pci/ops-pmcmsp.c
@@ -404,7 +404,7 @@ int msp_pcibios_config_access(unsigned char access_type,
 	if (pciirqflag == 0) {
 		request_irq(MSP_INT_PCI,/* Hardcoded internal MSP7120 wiring */
 				bpci_interrupt,
-				SA_SHIRQ | SA_INTERRUPT,
+				IRQF_SHARED | IRQF_DISABLED,
 				"PMC MSP PCI Host",
 				preg);
 		pciirqflag = ~0;
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
index 6fa8572..ab96a2d 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
@@ -163,7 +163,7 @@ static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
 		CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
 	*CIC_EXT_CFG_REG = cic_ext;
 
-	return request_irq(hirq->irq, hwbutton_handler, SA_INTERRUPT,
+	return request_irq(hirq->irq, hwbutton_handler, IRQF_DISABLED,
 				hirq->name, (void *)hirq);
 }
 

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH 3/3] NCR53C8XX: Remove deprecated IRQ flags (SA_*)
  2007-09-26 22:33 98% [PATCH 1/3] Completely remove deprecated IRQ flags (SA_*) Ahmed S. Darwish
  2007-09-26 22:35 99% ` [PATCH 2/3] MIPS: Remove " Ahmed S. Darwish
@ 2007-09-26 22:36 81% ` Ahmed S. Darwish
  1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-09-26 22:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, matthew, linux-scsi

Hi Matthew,

A patch to stop using deprecated IRQ flags in ncr53c8xx documentaion. The new
IRQF_* macros are used instead.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/Documentation/scsi/ChangeLog.ncr53c8xx b/Documentation/scsi/ChangeLog.ncr53c8xx
index 7d03e9d..a9f721a 100644
--- a/Documentation/scsi/ChangeLog.ncr53c8xx
+++ b/Documentation/scsi/ChangeLog.ncr53c8xx
@@ -195,9 +195,9 @@ Sun Feb  14:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	  Pointed out by Leonard Zubkoff.
 	- Allow to tune request_irq() flags from the boot command line using 
 	  ncr53c8xx=irqm:??, as follows:
-	  a) If bit 0x10 is set in irqm, SA_SHIRQ flag is not used.
-	  b) If bit 0x20 is set in irqm, SA_INTERRUPT flag is not used.
-	  By default the driver uses both SA_SHIRQ and SA_INTERRUPT.
+	  a) If bit 0x10 is set in irqm, IRQF_SHARED flag is not used.
+	  b) If bit 0x20 is set in irqm, IRQF_DISABLED flag is not used.
+	  By default the driver uses both IRQF_SHARED and IRQF_DISABLED.
 	  Option 'ncr53c8xx=irqm:0x20' may be used when an IRQ is shared by 
 	  a 53C8XX adapter and a network board.
 	- Tiny mispelling fixed (ABORT instead of ABRT). Was fortunately 
diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt
index 39d409a..a65cea9 100644
--- a/Documentation/scsi/ncr53c8xx.txt
+++ b/Documentation/scsi/ncr53c8xx.txt
@@ -785,8 +785,8 @@ port address 0x1400.
         irqm:0     always open drain
         irqm:1     same as initial settings (assumed BIOS settings)
         irqm:2     always totem pole
-        irqm:0x10  driver will not use SA_SHIRQ flag when requesting irq
-        irqm:0x20  driver will not use SA_INTERRUPT flag when requesting irq
+        irqm:0x10  driver will not use IRQF_SHARED flag when requesting irq
+        irqm:0x20  driver will not use IRQF_DISABLED flag when requesting irq
 
     (Bits 0x10 and 0x20 can be combined with hardware irq mode option)
 
@@ -1236,15 +1236,15 @@ when the SCSI DATA IN phase is reentered after a phase mismatch.
 When an IRQ is shared by devices that are handled by different drivers, it 
 may happen that one driver complains about the request of the IRQ having 
 failed. Inder Linux-2.0, this may be due to one driver having requested the 
-IRQ using the SA_INTERRUPT flag but some other having requested the same IRQ 
+IRQ using the IRQF_DISABLED flag but some other having requested the same IRQ 
 without this flag. Under both Linux-2.0 and linux-2.2, this may be caused by 
-one driver not having requested the IRQ with the SA_SHIRQ flag.
+one driver not having requested the IRQ with the IRQF_SHARED flag.
 
 By default, the ncr53c8xx and sym53c8xx drivers request IRQs with both the 
-SA_INTERRUPT and the SA_SHIRQ flag under Linux-2.0 and with only the SA_SHIRQ 
+IRQF_DISABLED and the IRQF_SHARED flag under Linux-2.0 and with only the IRQF_SHARED 
 flag under Linux-2.2.
 
-Under Linux-2.0, you can disable use of SA_INTERRUPT flag from the boot 
+Under Linux-2.0, you can disable use of IRQF_DISABLED flag from the boot 
 command line by using the following option:
 
      ncr53c8xx=irqm:0x20   (for the generic ncr53c8xx driver)
@@ -1252,7 +1252,7 @@ command line by using the following option:
 
 If this does not fix the problem, then you may want to check how all other 
 drivers are requesting the IRQ and report the problem. Note that if at least 
-a single driver does not request the IRQ with the SA_SHIRQ flag (share IRQ), 
+a single driver does not request the IRQ with the IRQF_SHARED flag (share IRQ), 
 then the request of the IRQ obviously will not succeed for all the drivers.
 
 15. SCSI problem troubleshooting

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 81%]

* [PATCH RFC 1/2] IRQ: Modularize the setup_irq code (1)
@ 2007-10-05  5:30 83% Ahmed S. Darwish
  2007-10-05  5:36 88% ` [PATCH RFC 2/2] IRQ: Modularize the setup_irq code (2) Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-10-05  5:30 UTC (permalink / raw)
  To: tglx; +Cc: linux-kernel, akpm

Hi Thomas/lkml,

setup_irq() code contains a big chunk of 130 code lines that 
can be divided to several smaller methods. These 2 patches introduce 
those small functions to aid toward setup_irq() code modularity. 
No major code logic changes exist.

Patches can be applied cleanly over v2.6.23-rc9.

Thanks,

==> (Description for Logs)

Introduce can_add_irqaction_on_allocated_irq and warn_about_irqaction_mismatch
methods to support setup_irq() code modularity.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 manage.c |   92 +++++++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 55 insertions(+), 37 deletions(-)

diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 7230d91..6a0d778 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -248,6 +248,50 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc)
 		desc->handle_irq = NULL;
 }
 
+static inline void warn_about_irqaction_mismatch(unsigned int irq,
+						 struct irqaction *new)
+{
+#ifdef CONFIG_DEBUG_SHIRQ
+	const char *name = irq_desc[irq].action->name;
+	/* If device doesn't expect the mismatch */
+	if (!(new->flags & IRQF_PROBE_SHARED)) {
+		printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
+		if (name)
+			printk(KERN_ERR "current handler: %s\n", name);
+		dump_stack();
+	}
+#endif
+}
+
+/*
+ * Test if an irqaction can be added to the passed allocated IRQ line
+ * Must be called with the irq_desc[irq]->lock held.
+ */
+int can_add_irqaction_on_allocated_irq(unsigned int irq, struct irqaction *new)
+{
+	struct irqaction *old = irq_desc[irq].action;
+
+	BUG_ON(!old);
+	/*
+	 * Can't share interrupts unless both agree to and are
+	 * the same type (level, edge, polarity). So both flag
+	 * fields must have IRQF_SHARED set and the bits which
+	 * set the trigger type must match.
+	 */
+	if (!((old->flags & new->flags) & IRQF_SHARED) ||
+	    ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK))
+		return 0;
+
+#if defined(CONFIG_IRQ_PER_CPU)
+	/* All handlers must agree on per-cpuness */
+	if ((old->flags & IRQF_PERCPU) !=
+	    (new->flags & IRQF_PERCPU))
+		return 0;
+#endif
+
+	return 1;
+}
+
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
@@ -256,7 +300,6 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 {
 	struct irq_desc *desc = irq_desc + irq;
 	struct irqaction *old, **p;
-	const char *old_name = NULL;
 	unsigned long flags;
 	int shared = 0;
 
@@ -289,31 +332,18 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 	p = &desc->action;
 	old = *p;
 	if (old) {
-		/*
-		 * Can't share interrupts unless both agree to and are
-		 * the same type (level, edge, polarity). So both flag
-		 * fields must have IRQF_SHARED set and the bits which
-		 * set the trigger type must match.
-		 */
-		if (!((old->flags & new->flags) & IRQF_SHARED) ||
-		    ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
-			old_name = old->name;
-			goto mismatch;
-		}
-
-#if defined(CONFIG_IRQ_PER_CPU)
-		/* All handlers must agree on per-cpuness */
-		if ((old->flags & IRQF_PERCPU) !=
-		    (new->flags & IRQF_PERCPU))
-			goto mismatch;
-#endif
-
-		/* add new interrupt at end of irq queue */
-		do {
-			p = &old->next;
-			old = *p;
-		} while (old);
 		shared = 1;
+		if (can_add_irqaction_on_allocated_irq(irq, new)) {
+			/* add new interrupt at end of irq queue */
+			do {
+				p = &old->next;
+				old = *p;
+			} while (old);
+		} else {
+			warn_about_irqaction_mismatch(irq, new);
+			spin_unlock_irqrestore(&desc->lock, flags);
+			return -EBUSY;
+		}
 	}
 
 	*p = new;
@@ -372,18 +402,6 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 	register_handler_proc(irq, new);
 
 	return 0;
-
-mismatch:
-#ifdef CONFIG_DEBUG_SHIRQ
-	if (!(new->flags & IRQF_PROBE_SHARED)) {
-		printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
-		if (old_name)
-			printk(KERN_ERR "current handler: %s\n", old_name);
-		dump_stack();
-	}
-#endif
-	spin_unlock_irqrestore(&desc->lock, flags);
-	return -EBUSY;
 }
 
 /**


-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 83%]

* [PATCH RFC 2/2] IRQ: Modularize the setup_irq code (2)
  2007-10-05  5:30 83% [PATCH RFC 1/2] IRQ: Modularize the setup_irq code (1) Ahmed S. Darwish
@ 2007-10-05  5:36 88% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-05  5:36 UTC (permalink / raw)
  To: tglx; +Cc: linux-kernel, akpm

Introduce irq_desc_match_fist_irqaction() to support setup_irq() 
code modularity.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

Any ideas for a better method name ?

 manage.c |   89 ++++++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 51 insertions(+), 38 deletions(-)

diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 6a0d778..4e96d56 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -293,6 +293,55 @@ int can_add_irqaction_on_allocated_irq(unsigned int irq, struct irqaction *new)
 }
 
 /*
+ * Configure the passed irq descriptor to satisfy our first newly
+ * added irqaction needs
+ * must be called with the irq_desc[irq]->lock held
+ */
+void irq_desc_match_fist_irqaction(unsigned int irq, struct irqaction *new)
+{
+	struct irq_desc *desc = irq_desc + irq;
+
+	/* We must be the first and the only irqaction */
+	BUG_ON(desc->action != new || new->next);
+
+	irq_chip_set_defaults(desc->chip);
+
+#if defined(CONFIG_IRQ_PER_CPU)
+	if (new->flags & IRQF_PERCPU)
+		desc->status |= IRQ_PER_CPU;
+#endif
+
+	/* Setup the type (level, edge polarity) if configured: */
+	if (new->flags & IRQF_TRIGGER_MASK) {
+		if (desc->chip && desc->chip->set_type)
+			desc->chip->set_type(irq,
+					     new->flags & IRQF_TRIGGER_MASK);
+		else
+			/*
+			 * IRQF_TRIGGER_* but the PIC does not support
+			 * multiple flow-types?
+			 */
+			printk(KERN_WARNING "No IRQF_TRIGGER set_type "
+			       "function for IRQ %d (%s)\n", irq,
+			       desc->chip ? desc->chip->name : "unknown");
+	} else
+		compat_irq_chip_set_default_handler(desc);
+
+	desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
+
+	if (!(desc->status & IRQ_NOAUTOEN)) {
+		desc->depth = 0;
+		desc->status &= ~IRQ_DISABLED;
+		if (desc->chip->startup)
+			desc->chip->startup(irq);
+		else
+			desc->chip->enable(irq);
+	} else
+		/* Undo nested disables: */
+		desc->depth = 1;
+}
+
+/*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
  */
@@ -352,45 +401,9 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 	if (new->flags & IRQF_NOBALANCING)
 		desc->status |= IRQ_NO_BALANCING;
 
-	if (!shared) {
-		irq_chip_set_defaults(desc->chip);
+	if (!shared)
+		irq_desc_match_fist_irqaction(irq, new);
 
-#if defined(CONFIG_IRQ_PER_CPU)
-		if (new->flags & IRQF_PERCPU)
-			desc->status |= IRQ_PER_CPU;
-#endif
-
-		/* Setup the type (level, edge polarity) if configured: */
-		if (new->flags & IRQF_TRIGGER_MASK) {
-			if (desc->chip && desc->chip->set_type)
-				desc->chip->set_type(irq,
-						new->flags & IRQF_TRIGGER_MASK);
-			else
-				/*
-				 * IRQF_TRIGGER_* but the PIC does not support
-				 * multiple flow-types?
-				 */
-				printk(KERN_WARNING "No IRQF_TRIGGER set_type "
-				       "function for IRQ %d (%s)\n", irq,
-				       desc->chip ? desc->chip->name :
-				       "unknown");
-		} else
-			compat_irq_chip_set_default_handler(desc);
-
-		desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
-				  IRQ_INPROGRESS);
-
-		if (!(desc->status & IRQ_NOAUTOEN)) {
-			desc->depth = 0;
-			desc->status &= ~IRQ_DISABLED;
-			if (desc->chip->startup)
-				desc->chip->startup(irq);
-			else
-				desc->chip->enable(irq);
-		} else
-			/* Undo nested disables: */
-			desc->depth = 1;
-	}
 	/* Reset broken irq detection when installing new handler */
 	desc->irq_count = 0;
 	desc->irqs_unhandled = 0;

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 88%]

* [Oops] on 2.6.23-rc9 sysRq Show Tasks (t)
@ 2007-10-06 20:14 70% Ahmed S. Darwish
  2007-10-06 20:52 99% ` Ahmed S. Darwish
    0 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-06 20:14 UTC (permalink / raw)
  To: linux-kernel

Hi all,

Pressing sysRq+T always produce an Oops for every running system task (94 
Oopses, that's a record ;)).
The bug is 100% reproducable. Should I begin bisecting/investigating the 
issue or it's a known problem ?

$ ver_linux
Linux darwish-laptop 2.6.23-rc9 #23 Sat Oct 6 21:48:45 EET 2007 i686 GNU/Linux
 
Gnu C                  4.0.3
Gnu make               3.81beta4
binutils               2.16.91
util-linux             2.12r
mount                  2.12r
module-init-tools      3.2.2
e2fsprogs              1.38
Linux C Library        3.6
Dynamic linker (ldd)   2.3.6
Procps                 3.2.6
Net-tools              1.60
Console-tools          0.2.3
Sh-utils               5.93
udev                   079

[  226.309874] SysRq : Show State
[  226.309948]   task                PC stack   pid father
[  226.310105] init          S c1465b64     0     1      0
[  226.310195]        c1465b54 00000082 00000286 c1465b64 c04255c0 c03c3ec0 00000000 00000286 
[  226.310414]        c1465b64 fffd689a 0000000b 00000000 c02e8fda c1537040 00000292 c0425ab4 
[  226.310664]        c0425ab4 fffd689a c0123cd0 c14634f0 c04255c0 00000800 c1465f9c c0176bf5 
[  226.310914] Call Trace:
[  226.310995]  [<c02e8fda>] schedule_timeout+0x4a/0xc0
[  226.311075]  [<c0123cd0>] process_timeout+0x0/0x10
[  226.311148]  [<c0176bf5>] do_select+0x375/0x4b0
[  226.311231]  [<c01760e0>] __pollwait+0x0/0x100
[  226.311302]  [<c0117a50>] default_wake_function+0x0/0x10
[  226.311379]  [<c0138bad>] __lock_acquire+0x74d/0x1130
[  226.311452]  [<c01c0278>] do_get_write_access+0x2c8/0x570
[  226.311538]  [<c0164a39>] poison_obj+0x29/0x60
[  226.311613]  [<c0139997>] mark_held_locks+0x67/0x80
[  226.311684]  [<c01663dd>] kmem_cache_free+0xad/0xf0
[  226.311755]  [<c0139b64>] trace_hardirqs_on+0x104/0x170
[  226.311832]  [<c0138bad>] __lock_acquire+0x74d/0x1130
[  226.311903]  [<c0138bad>] __lock_acquire+0x74d/0x1130
[  226.311981]  [<c0138bad>] __lock_acquire+0x74d/0x1130
[  226.312052]  [<c01aefb6>] ext3_ordered_commit_write+0xa6/0xe0
[  226.312137]  [<c0138bad>] __lock_acquire+0x74d/0x1130
[  226.312207]  [<c02eb074>] _spin_unlock+0x14/0x20
[  226.312278]  [<c017c0d7>] __d_lookup+0x107/0x110
[  226.312352]  [<c01dbc95>] _atomic_dec_and_lock+0x15/0x40
[  226.312428]  [<c02eb074>] _spin_unlock+0x14/0x20
[  226.312498]  [<c01dbcaa>] _atomic_dec_and_lock+0x2a/0x40
[  226.312570]  [<c017ae71>] dput+0x51/0x120
[  226.312638]  [<c0172b0e>] __link_path_walk+0xc4e/0xca0
[  226.312718]  [<c0176ef6>] core_sys_select+0x1c6/0x320
[  226.312796]  [<c0164a39>] poison_obj+0x29/0x60
[  226.312868]  [<c01653c0>] cache_free_debugcheck+0xb0/0x1e0
[  226.312949]  [<c01e215f>] copy_to_user+0x3f/0x70
[  226.313020]  [<c016d1ff>] cp_new_stat64+0xef/0x110
[  226.313110]  [<c01773b1>] sys_select+0x51/0x1c0
[  226.313179]  [<c0139b64>] trace_hardirqs_on+0x104/0x170
[  226.313255]  [<c0104026>] sysenter_past_esp+0x5f/0x99
[  226.313336]  =======================
[  226.313380] kthreadd      S 00000000     0     2      0
[  226.313468]        c1467fd0 00000082 00000002 00000000 c012dee2 00000246 c03a4ee0 00000584 
[  226.313686]        c03a4efc 00000584 ded73c48 00000000 c012df3c c012de40 00000000 00000000 
[  226.313936]        c0104c23 00000000 00000000 00000000 00000000 00000000 00000000 
[  226.314163] Call Trace:
[  226.314237]  [<c012dee2>] kthreadd+0xa2/0x110
[  226.314311]  [<c012df3c>] kthreadd+0xfc/0x110
[  226.314379]  [<c012de40>] kthreadd+0x0/0x110
[  226.314447]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.314521]  =======================
[  226.314564] ksoftirqd/0   S c0139b64     0     3      2
[  226.314652]        c146bfcc 00000082 00000000 c0139b64 00000001 c012038f c01205b6 00000246 
[  226.314869]        00000000 fffffffc c0120640 00000000 c0120688 c012de34 c012ddc0 00000000 
[  226.315118]        00000000 c0104c23 c1465f04 00000000 00000000 00000000 00000000 00000000 
[  226.315367] Call Trace:
[  226.315441]  [<c0139b64>] trace_hardirqs_on+0x104/0x170
[  226.315512]  [<c012038f>] _local_bh_enable+0x4f/0xf0
[  226.315584]  [<c01205b6>] __do_softirq+0x76/0xb0
[  226.315654]  [<c0120640>] ksoftirqd+0x0/0x90
[  226.315721]  [<c0120688>] ksoftirqd+0x48/0x90
[  226.315788]  [<c012de34>] kthread+0x74/0x80
[  226.315855]  [<c012ddc0>] kthread+0x0/0x80
[  226.315923]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.315997]  =======================
[  226.316039] watchdog/0    S 00000073     0     4      2
[  226.316127]        c146ffc8 00000096 00000001 00000073 ffffffff 308b09e3 00000d34 00000000 
[  226.316345]        00000000 fffffffc c0147c60 00000000 c0147c97 00000063 c012de34 c012ddc0 
[  226.316595]        00000000 00000000 c0104c23 c1465f08 00000000 00000000 00000000 00000000 
[  226.316844] Call Trace:
[  226.316922]  [<c0147c60>] watchdog+0x0/0x50
[  226.316992]  [<c0147c97>] watchdog+0x37/0x50
[  226.317061]  [<c012de34>] kthread+0x74/0x80
[  226.317128]  [<c012ddc0>] kthread+0x0/0x80
[  226.317196]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.317270]  =======================
[  226.317312] events/0      R running      0     5      2
[  226.317400] khelper       S 00000002     0     6      2
[  226.317488]        c1473fac 00000086 c0139b64 00000002 00000046 df789444 00000286 df789444 
[  226.317706]        df789444 df789420 c012ae00 00000000 c012aed5 00000000 c146c070 c012e030 
[  226.317956]        df789460 df789460 df789420 fffffffc c012ae00 c012de34 c012ddc0 00000000 
[  226.318205] Call Trace:
[  226.318278]  [<c0139b64>] trace_hardirqs_on+0x104/0x170
[  226.318353]  [<c012ae00>] worker_thread+0x0/0x100
[  226.318422]  [<c012aed5>] worker_thread+0xd5/0x100
[  226.318491]  [<c012e030>] autoremove_wake_function+0x0/0x50
[  226.318566]  [<c012ae00>] worker_thread+0x0/0x100
[  226.318633]  [<c012de34>] kthread+0x74/0x80
[  226.318701]  [<c012ddc0>] kthread+0x0/0x80
[  226.318769]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.318843]  =======================
[  226.318885] kblockd/0     S 00000002     0    35      2
[  226.318973]        df751fac 00000086 c0139b64 00000002 00000046 c03c3ec0 00000286 df706e5c 
[  226.319191]        df706e5c df706e38 c012ae00 00000000 c012aed5 00000000 df748a90 c012e030 
[  226.319440]        df706e78 df706e78 df706e38 fffffffc c012ae00 c012de34 c012ddc0 00000000 
[  226.319690] Call Trace:
[  226.319764]  [<c0139b64>] trace_hardirqs_on+0x104/0x170
[  226.319840]  [<c012ae00>] worker_thread+0x0/0x100
[  226.319909]  [<c012aed5>] worker_thread+0xd5/0x100
[  226.319978]  [<c012e030>] autoremove_wake_function+0x0/0x50
[  226.320051]  [<c012ae00>] worker_thread+0x0/0x100
[  226.320120]  [<c012de34>] kthread+0x74/0x80
[  226.320187]  [<c012ddc0>] kthread+0x0/0x80
[  226.320255]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.320329]  =======================
[  226.320372] kacpid        S 00000002     0    38      2
[  226.320459]        df759fac 00000086 c0139b64 00000002 00000046 df706a34 00000286 df706a34 
[  226.320677]        df706a34 df706a10 c012ae00 00000000 c012aed5 00000000 df754ad0 c012e030 
[  226.320927]        df706a50 df706a50 df706a10 fffffffc c012ae00 c012de34 c012ddc0 00000000 
[  226.321177] Call Trace:
[  226.321251]  [<c0139b64>] trace_hardirqs_on+0x104/0x170
[  226.321326]  [<c012ae00>] worker_thread+0x0/0x100
[  226.321395]  [<c012aed5>] worker_thread+0xd5/0x100
[  226.321465]  [<c012e030>] autoremove_wake_function+0x0/0x50
[  226.321538]  [<c012ae00>] worker_thread+0x0/0x100
[  226.321606]  [<c012de34>] kthread+0x74/0x80
[  226.321673]  [<c012ddc0>] kthread+0x0/0x80
[  226.321741]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.321814]  =======================
[  226.321857] kacpi_notify  S 00000002     0    39      2
[  226.321945]        df75bfac 00000086 c0139b64 00000002 00000046 df70e99c 00000286 df70e99c 
[  226.322162]        df70e99c df70e978 c012ae00 00000000 c012aed5 00000000 df754070 c012e030 
[  226.322412]        df70e9b8 df70e9b8 df70e978 fffffffc c012ae00 c012de34 c012ddc0 00000000 
[  226.322662] Call Trace:
[  226.322735]  [<c0139b64>] trace_hardirqs_on+0x104/0x170
[  226.322810]  [<c012ae00>] worker_thread+0x0/0x100
[  226.322879]  [<c012aed5>] worker_thread+0xd5/0x100
[  226.322948]  [<c012e030>] autoremove_wake_function+0x0/0x50
[  226.323022]  [<c012ae00>] worker_thread+0x0/0x100
[  226.323090]  [<c012de34>] kthread+0x74/0x80
[  226.323157]  [<c012ddc0>] kthread+0x0/0x80
[  226.323226]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.324145]  =======================
[  226.324188] kseriod       S 00000002     0   159      2
[  226.324276]        c14bdf98 00000092 c0139b64 00000002 00000046 c03b8f80 00000286 c03b8f80 
[  226.324493]        00000000 00000000 00000000 00000000 c0269674 c02eb320 00000002 c02e87ff 
[  226.324742]        00000000 00000000 df720070 c012e030 c03b8f9c c03b8f9c 00000000 fffffffc 
[  226.324992] Call Trace:
[  226.325065]  [<c0139b64>] trace_hardirqs_on+0x104/0x170
[  226.325142]  [<c0269674>] serio_thread+0x204/0x330
[  226.325213]  [<c02eb320>] _spin_unlock_irq+0x20/0x30
[  226.325285]  [<c02e87ff>] schedule+0x1af/0x340
[  226.325355]  [<c012e030>] autoremove_wake_function+0x0/0x50
[  226.325430]  [<c0269470>] serio_thread+0x0/0x330
[  226.325500]  [<c012de34>] kthread+0x74/0x80
[  226.325567]  [<c012ddc0>] kthread+0x0/0x80
[  226.325635]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.325709]  =======================
[  226.325751] rt-test-0     S 00000046     0   184      2
[  226.325839]        c14e9fc8 00000096 c011cfe8 00000046 df71857c fffffffc df71857c fffffffc 
[  226.326056]        c0621f00 fffffffc c013e250 00000000 c013e2c8 c0621f00 c012de34 c012ddc0 
[  226.326306]        00000000 00000000 c0104c23 c1465efc 00000000 00000000 00000000 00000000 
[  226.326555] Call Trace:
[  226.326629]  [<c011cfe8>] allow_signal+0x28/0x80
[  226.326703]  [<c013e250>] test_func+0x0/0xb0
[  226.326773]  [<c013e2c8>] test_func+0x78/0xb0
[  226.326842]  [<c012de34>] kthread+0x74/0x80
[  226.326909]  [<c012ddc0>] kthread+0x0/0x80
[  226.326978]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.327051]  =======================
[  226.327094] rt-test-1     S 00000046     0   186      2
[  226.327182]        c14effc8 00000096 c011cfe8 00000046 c14edb3c fffffffc c14edb3c fffffffc 
[  226.327400]        c0621f90 fffffffc c013e250 00000000 c013e2c8 c0621f90 c012de34 c012ddc0 
[  226.327649]        00000000 00000000 c0104c23 c1465efc 00000000 00000000 00000000 00000000 
[  226.327899] Call Trace:
[  226.327972]  [<c011cfe8>] allow_signal+0x28/0x80
[  226.328046]  [<c013e250>] test_func+0x0/0xb0
[  226.328115]  [<c013e2c8>] test_func+0x78/0xb0
[  226.328184]  [<c012de34>] kthread+0x74/0x80
[  226.328252]  [<c012ddc0>] kthread+0x0/0x80
[  226.328319]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.328392]  =======================
[  226.328435] rt-test-2     S 00000046     0   188      2
[  226.328522]        c14f3fc8 00000096 c011cfe8 00000046 c14ed5dc fffffffc c14ed5dc fffffffc 
[  226.328740]        c0622020 fffffffc c013e250 00000000 c013e2c8 c0622020 c012de34 c012ddc0 
[  226.328990]        00000000 00000000 c0104c23 c1465efc 00000000 00000000 00000000 00000000 
[  226.329239] Call Trace:
[  226.329312]  [<c011cfe8>] allow_signal+0x28/0x80
[  226.329385]  [<c013e250>] test_func+0x0/0xb0
[  226.329453]  [<c013e2c8>] test_func+0x78/0xb0
[  226.329522]  [<c012de34>] kthread+0x74/0x80
[  226.329589]  [<c012ddc0>] kthread+0x0/0x80
[  226.329657]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.329730]  =======================
[  226.329772] rt-test-3     S 00000046     0   190      2
[  226.329860]        c14f7fc8 00000096 c011cfe8 00000046 c14ed07c fffffffc c14ed07c fffffffc 
[  226.330078]        c06220b0 fffffffc c013e250 00000000 c013e2c8 c06220b0 c012de34 c012ddc0 
[  226.330347]        00000000 00000000 c0104c23 c1465efc 00000000 00000000 00000000 00000000 
[  226.330597] Call Trace:
[  226.330670]  [<c011cfe8>] allow_signal+0x28/0x80
[  226.330744]  [<c013e250>] test_func+0x0/0xb0
[  226.330813]  [<c013e2c8>] test_func+0x78/0xb0
[  226.330882]  [<c012de34>] kthread+0x74/0x80
[  226.330949]  [<c012ddc0>] kthread+0x0/0x80
[  226.331017]  [<c0104c23>] kernel_thread_helper+0x7/0x14
[  226.331090]  =======================

And So on for every task.

Thanks,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 70%]

* Re: [Oops] on 2.6.23-rc9 sysRq Show Tasks (t)
  2007-10-06 20:14 70% [Oops] on 2.6.23-rc9 sysRq Show Tasks (t) Ahmed S. Darwish
@ 2007-10-06 20:52 99% ` Ahmed S. Darwish
    1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-06 20:52 UTC (permalink / raw)
  To: linux-kernel

On Sat, Oct 06, 2007 at 10:14:05PM +0200, ahmed wrote:
> Hi all,
> 
> Pressing sysRq+T always produce an Oops for every running system task (94 
> Oopses, that's a record ;)).
> The bug is 100% reproducable. Should I begin bisecting/investigating the 
> issue or it's a known problem ?
>

Shame, This is not an Oops at all. Really sorry.

/me wondering about my look now posting a normal message as an Ooops a day 
before the stable release :(.

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [Oops] on 2.6.23-rc9 sysRq Show Tasks (t)
  @ 2007-10-07 19:39 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-07 19:39 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: linux-kernel

On Sun, Oct 07, 2007 at 01:12:38AM +0400, Alexey Dobriyan wrote:
> On Sat, Oct 06, 2007 at 10:14:06PM +0200, Ahmed S. Darwish wrote:
> > Pressing sysRq+T always produce an Oops for every running system task (94 
> > Oopses, that's a record ;)).
> 
> uh-oh. For every sleeping task, I think.
> 
> > The bug is 100% reproducable. Should I begin bisecting/investigating the 
> > issue or it's a known problem ?
> 
> Start with some old kernel, like mmm.. 2.6.0. The fact that same behaviour
> was present there may make you think about faulty assumptions you've
> made.
> 

Yeah I understood my mistake (not an Oops, a normal behaviour). 
Thanks for your advice :).

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: PROBLEM: kernel 2.6.22.9-cfs-v22 compile warnings
  @ 2007-10-08 18:11 99% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-08 18:11 UTC (permalink / raw)
  To: Konstantin Oshovskij; +Cc: linux-kernel

Hi Konstantin,

On Mon, Oct 08, 2007 at 03:34:24PM +0300, Konstantin Oshovskij wrote:
>
> Hello,
> i have encountered 2.6.22.9 compile warnings. This is the first time i
> decided to report them. I had various compile warnings with earlier
> kernel versions, its just i didnt had courage to report them :)  I'm
> using instructions from REPORTING-BUGS file as template so please bear
> with me :)
> 

The "may be used uninitialized" errors are false positives from GCC. Mostly
this happens from code paths like: 

int x, y; 
set_method(&x); 
y = x;

> fs/xfs/xfs_bmap.c: In function 'xfs_bmap_rtalloc':
> fs/xfs/xfs_bmap.c:2650: warning: 'rtx' is used uninitialized in this
> function
> 

Hidden by uninitialized_var() macro in latest pull. This macro silence
the gcc by using the trick: #define uninitialized_var(x) x = x

> function
> ipc/msg.c:390: warning: 'setbuf.mode' may be used uninitialized in
> this function
>   CC      ipc/sem.o
> ipc/sem.c: In function 'sys_semctl':
> ipc/sem.c:861: warning: 'setbuf.uid' may be used uninitialized in this
> function
> ipc/sem.c:861: warning: 'setbuf.gid' may be used uninitialized in this
> function
> ipc/sem.c:861: warning: 'setbuf.mode' may be used uninitialized in
> this function
> 

Already hidden now by the uninitialized_var() macro.

> drivers/pci/search.c: In function 'pci_find_slot':
> drivers/pci/search.c:99: warning: 'pci_find_device' is deprecated
> (declared at include/linux/pci.h:477)

pci_find_slot is using pci_find_device on purpose here (equivalent to the
safe pci_get_slot method).

> drivers/pci/search.c: At top level:
> drivers/pci/search.c:434: warning: 'pci_find_device' is deprecated
> (declared at drivers/pci/search.c:241)
> drivers/pci/search.c:434: warning: 'pci_find_device' is deprecated
> (declared at drivers/pci/search.c:241)
> 

False positives from function definition and from the innocent EXPORT_SYMBOL
macro (It makes the method available to kernel modules).

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] NTFS error messages: replace static char pointers by static char arrays
  @ 2007-10-09 12:40 99% ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-10-09 12:40 UTC (permalink / raw)
  To: Dmitri Vorobiev; +Cc: aia21, linux-ntfs-dev, linux-kernel

On Tue, Oct 09, 2007 at 01:55:42AM +0400, Dmitri Vorobiev wrote:
> Hi,
> 
> The patch below contains a small code clean-up for the NTFS driver: all
> static char pointers to error message strings have been replaced by 
> static char arrays.
> 

Hi Dmitri,

Isn't the only difference between char *c = "msg" and char c[] = "msg" is 
that the first is a non-const pointer to a const char array while the second 
is a modifiable char array ?

If so, what's the point of the patch ?

Thanks,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Stop docproc segfaulting when SRCTREE isn't set.
  @ 2007-10-09 13:03 99% ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-10-09 13:03 UTC (permalink / raw)
  To: Rob Landley; +Cc: akpm, linux-kernel, rdunlap

Hi Rob,

On Tue, Oct 09, 2007 at 01:25:18AM -0500, Rob Landley wrote:
[...]
>  	FILE * infile;
> +
> +	srctree = getenv("SRCTREE");
> +	if (!srctree) srctree = getcwd(NULL,0);
>  	if (argc != 3) {
>  		usage();
>  		exit(1);

$ man getcwd

 char *getcwd(char *buf, size_t size);
      
 As an extension to the POSIX.1 standard, Linux (libc4, libc5, glibc) getcwd() 
 allocates the buffer dynamically using malloc() if buf is NULL on call.

Shouldn't "srctree" be free()ed in case getenv("SRCTREE") failed ?

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH -mm] fix wrong /proc/cpuinfo output
  @ 2007-10-09 13:32 99% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-09 13:32 UTC (permalink / raw)
  To: Akinobu Mita, linux-kernel, Mike Travis, Andrew Morton

On Tue, Oct 09, 2007 at 07:43:21PM +0900, Akinobu Mita wrote:
> This patch fixes the problem introduced by:
> http://kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.23-rc8/2.6.23-rc8-mm2/broken-out/x86-convert-cpuinfo_x86-array-to-a-per_cpu-array.patch
> 

Link is dead, same patch in lkml.org:

http://lkml.org/lkml/2007/9/24/394

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Stop docproc segfaulting when SRCTREE isn't set.
  @ 2007-10-09 17:19 99%     ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-10-09 17:19 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: Rob Landley, akpm, linux-kernel, rdunlap

On Tue, Oct 09, 2007 at 08:55:00AM -0700, Randy Dunlap wrote:
> On Tue, 9 Oct 2007 15:03:15 +0200 Ahmed S. Darwish wrote:
> 
> > Hi Rob,
> > 
> > On Tue, Oct 09, 2007 at 01:25:18AM -0500, Rob Landley wrote:
> > [...]
> > >  	FILE * infile;
> > > +
> > > +	srctree = getenv("SRCTREE");
> > > +	if (!srctree) srctree = getcwd(NULL,0);
> > >  	if (argc != 3) {
> > >  		usage();
> > >  		exit(1);
> > 
> > $ man getcwd
> > 
> >  char *getcwd(char *buf, size_t size);
> >       
> >  As an extension to the POSIX.1 standard, Linux (libc4, libc5, glibc) getcwd() 
> >  allocates the buffer dynamically using malloc() if buf is NULL on call.
> > 
> > Shouldn't "srctree" be free()ed in case getenv("SRCTREE") failed ?
> 
> What is there to free() at that point?  If getenv() fails (i.e.,
> the env. variable is not found), it returns NULL.
> or do I need another cup of coffee?
>

I meant if getenv() failed, "srctree = getcwd(NULL, 0)" will let 
"srctree" point to a _ malloc()ed _ buffer representing PWD. 
As said in the manpage, this buffer needs to be free()ed after usage.
Right or I'm the one who needs that cup of coffee :) ?

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Stop docproc segfaulting when SRCTREE isn't set.
  @ 2007-10-09 17:51 99%         ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-09 17:51 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: Rob Landley, akpm, linux-kernel, rdunlap

On Tue, Oct 09, 2007 at 10:24:03AM -0700, Randy Dunlap wrote:
> Ahmed S. Darwish wrote:
> >On Tue, Oct 09, 2007 at 08:55:00AM -0700, Randy Dunlap wrote:
> >>On Tue, 9 Oct 2007 15:03:15 +0200 Ahmed S. Darwish wrote:
> >>
> >>>Hi Rob,
> >>>
> >>>On Tue, Oct 09, 2007 at 01:25:18AM -0500, Rob Landley wrote:
> >>>[...]
> >>>> 	FILE * infile;
> >>>>+
> >>>>+	srctree = getenv("SRCTREE");
> >>>>+	if (!srctree) srctree = getcwd(NULL,0);
> >>>> 	if (argc != 3) {
> >>>> 		usage();
> >>>> 		exit(1);
> >>>$ man getcwd
> >>>
> >>> char *getcwd(char *buf, size_t size);
> >>>      
> >>> As an extension to the POSIX.1 standard, Linux (libc4, libc5, glibc) 
> >>> getcwd() allocates the buffer dynamically using malloc() if buf is NULL 
> >>> on call.
> >>>
> >>>Shouldn't "srctree" be free()ed in case getenv("SRCTREE") failed ?
> >>What is there to free() at that point?  If getenv() fails (i.e.,
> >>the env. variable is not found), it returns NULL.
> >>or do I need another cup of coffee?
> >>
> >
> >I meant if getenv() failed, "srctree = getcwd(NULL, 0)" will let 
> >"srctree" point to a _ malloc()ed _ buffer representing PWD. 
> >As said in the manpage, this buffer needs to be free()ed after usage.
> >Right or I'm the one who needs that cup of coffee :) ?
> 
> so it needs to be freed at program termination, is that what you are
> saying?  That will happen automatically (along with any open files being
> closed, etc.).
> 

I didn't know that leaked mem will be automatically freed at program 
termination. A new info, Thanks!.

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] NTFS error messages: replace static char pointers by static char arrays
  @ 2007-10-09 22:03 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-09 22:03 UTC (permalink / raw)
  To: Philipp Matthias Hahn; +Cc: Kernel Mailing List

On Tue, Oct 09, 2007 at 08:33:59PM +0200, Philipp Matthias Hahn wrote:
> Hello!
> 
> On Tue, Oct 09, 2007 at 02:40:35PM +0200, Ahmed S. Darwish wrote:
> > On Tue, Oct 09, 2007 at 01:55:42AM +0400, Dmitri Vorobiev wrote:
> > > The patch below contains a small code clean-up for the NTFS driver: all
> > > static char pointers to error message strings have been replaced by 
> > > static char arrays.
> 
>       char *       a = "a"; // pointer and content can be changed

Only the pointer can be changed here. AFAIK "a" is a const string.

> const char *       b = "b"; // the thing pointed to is const

The "const" here is redundant (just useful for forcing the compiler to
prevent us from shooting our feet). The "b" string is already constant.

>       char * const c = "c"; // the pointer is const
> const char * const d = "d"; // pointer and content can't be changed
> 
> void foo(void) {
>         *a = 'A';

This will segfault.

>         a++;
>         *b = 'B'; // error: assignment of read-only location
>         b++;
>         *c = 'C';

Last line will segfault too.

>         c++;      // error: increment  of read-only variable 'c'
>         *d = 'D'; // error: assignment of read-only location
>         d++;      // error: increment  of read-only variable 'd'
> }
> 

Please continue below.

> > Isn't the only difference between char *c = "msg" and char c[] = "msg" is 
> > that the first is a non-const pointer to a const char array while the second 
> > is a modifiable char array ?
> 
> $ cat [ab].c
> const char *a = "a";
> const char b[] = "b";
> $ gcc -c [ab].c
> $ size [ab].o
>    text    data     bss     dec     hex filename
>       2       4       0       6       6 a.o
>       2       0       0       2       2 b.o
> 
> 'a' has two entries: one for the named read-writeable pointer, and one for the
>     anonymous read-only string, the pointer points to.
> 'b' has a single entry: just the named read-only string.
> 

Got the point, Thanks!.

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH try #2] Input/Joystick Driver: add support AD7142 joystick driver
  @ 2007-10-12 16:41 99% ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-10-12 16:41 UTC (permalink / raw)
  To: Bryan Wu; +Cc: dmitry.torokhov, linux-input, linux-joystick, linux-kernel, akpm

On Fri, Oct 12, 2007 at 03:38:47PM +0800, Bryan Wu wrote:
>
> Signed-off-by: Bryan Wu <bryan.wu@analog.com>
> ---

Hi Bryan,

Why creating module's own kthread to call ad7142_decode and process keycodes 
instead of using a tasklet ?

Isn't disabling device interrupts from the begining of the ISR "ad7142_interrupt"
till the kthread "ad7142_thread" got waked-up and scheduled a long time,
espicially if there's a high load on the userspace side ?

Minor issues below.

> +
> +/* R    ADC stage 0 - 11 result (uncompensated) actually located in SRAM */
> +#define ADCRESULT_S0		0x0B
> +#define ADCRESULT_S1		0x0C
> +#define ADCRESULT_S2		0x0D
> +#define ADCRESULT_S3		0x0E
> +#define ADCRESULT_S4		0x0F
> +#define ADCRESULT_S5		0x10
> +#define ADCRESULT_S6		0x11
> +#define ADCRESULT_S7		0x12
> +#define ADCRESULT_S8		0x13
> +#define ADCRESULT_S9		0x14
> +#define ADCRESULT_S10		0x15
> +#define ADCRESULT_S11		0x16
> +

Keeping last two lines aligned with their above counterparts ?

> +static int
> +ad7142_probe(struct i2c_adapter *adap, int addr, int kind)
> +{
> +	struct i2c_client *client;
> +	int rc;
> +
> +	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
> +	if (!client)
> +		return -ENOMEM;
> +	memset(client, 0, sizeof(struct i2c_client));

kzalloc.

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH try #2] Input/Joystick Driver: add support AD7142 joystick driver
  @ 2007-10-12 19:21 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-12 19:21 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Bryan Wu, linux-input, linux-joystick, linux-kernel, akpm

On Fri, Oct 12, 2007 at 01:29:31PM -0400, Dmitry Torokhov wrote:
> Hi Ahmed,
> 

Hi :),

> On 10/12/07, Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> > On Fri, Oct 12, 2007 at 03:38:47PM +0800, Bryan Wu wrote:
> > >
> > > Signed-off-by: Bryan Wu <bryan.wu@analog.com>
> > > ---
> >
> > Hi Bryan,
> >
> > Why creating module's own kthread to call ad7142_decode and process keycodes
> > instead of using a tasklet ?
> >
> 
> Yo can't access i2c from a tasklet context.
> 
> > Isn't disabling device interrupts from the begining of the ISR "ad7142_interrupt"
> > till the kthread "ad7142_thread" got waked-up and scheduled a long time,
> > espicially if there's a high load on the userspace side ?
> >
> 
> It is OK - you disable a specific interrupt line preventing it from
> raising any more IRQs until current one is serviced. 

Won't this affect system responsiveness if the IRQ line was shared ?

>
> This is different from disabling interrupts on CPU.
> 

mm, Why disabling interrupts in general. Doesn't IRQ hanlers of the same kind got
executed in a serialized fashion even on SMPs ?. If so, why not just wakeup our
custom-thread or use workqueues and let them do their business ?

It's the first time for me to read others' patches carefully and kindly ask about
some explanations. I hope I'm not bothering people with my misunderstandings!
(till I get more experienced).


Thanks,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: 2.6.23-git2 buid failure
  @ 2007-10-14 11:18 99% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-14 11:18 UTC (permalink / raw)
  To: Kamalesh Babulal; +Cc: LKML

On Sat, Oct 13, 2007 at 12:45:47PM +0530, Kamalesh Babulal wrote:
> Hi,
> 
> The 2.6.23-git2 build fails with build error 
> 
>   CC [M]  drivers/mmc/core/core.o
>   CC [M]  drivers/mmc/core/sysfs.o
>   CC [M]  drivers/mmc/core/bus.o
>   CC [M]  drivers/mmc/core/host.o
> drivers/mmc/core/host.c: In function ‘mmc_remove_host’:
> drivers/mmc/core/host.c:146: error: implicit declaration of function ‘led_trigger_unregister’
> drivers/mmc/core/host.c:146: error: ‘struct mmc_host’ has no member named ‘led’
> make[3]: *** [drivers/mmc/core/host.o] Error 1
> make[2]: *** [drivers/mmc/core] Error 2
> make[1]: *** [drivers/mmc] Error 2
> make: *** [drivers] Error 2
> 

You can fix it using this patch: http://lkml.org/lkml/2007/10/12/380
Or the patch titled: mmc-fix-compile-without-led-triggers.patch

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Version 7 (2.6.23) Smack: Simplified Mandatory Access Control Kernel
  @ 2007-10-14 23:13 90% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-14 23:13 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: torvalds, akpm, linux-security-module, linux-kernel

Hi Casey,

On Sun, Oct 14, 2007 at 10:15:42AM -0700, Casey Schaufler wrote:
> 
> +
> +CIPSO Configuration
> +
> +It is normally unnecessary to specify the CIPSO configuration. The default
> +values used by the system handle all internal cases. Smack will compose CIPSO
> +label values to match the Smack labels being used without administrative
> +intervention. 
>

I have two issues with CIPSO and Smack:

1-

Using default configuration (system startup script + smacfs fstab line), system
can't access any service outside the Lan. "ICMP parameter problem message" always
appear from the first Wan router (traceroute + tcpdump at [1]).

Services inside the LAN can be accessed normally. System can connect to a Lan
Windows share. It also connects to the gateway HTTP server easily.

After some tweaking, I discovered that using CIPSOv6 solves all above problems:
$ echo -n "NLBL_CIPSOv6" > /smack/nltype

Is this a normal behaviour ?

2-

> 4. Any access requested on an object labeled "*" is permitted.
[...]
> +Unlabeled packets that come into the system will be given the
> +ambient label.

Default conf let the ambient attribute = _ which works fine. Setting ambient = *
stops all external (non lo) network traffic. Did I miss another use of "ambient"
or this is a normal behaviour ?.

> +Administration
> +
> +Smack supports some mount options:
> +
> +	smackfsdef=label: specifies the label to give files that lack
> +	the Smack label extended attribute.
> +

Although using smackfsdef=* as a mount option, all my system files have the floor
attribute. Most of the /dev files have the * attribute though.


[1]

traceroute to google.com (64.233.187.99), 30 hops max, 40 byte packets
 1  host-196.218.207.17.tedata.net (196.218.207.17)  1.976 ms  1.850 ms  2.127 ms
 2  DOKKI-R03C-GZ-EG (163.121.170.78)  27.429 ms  28.091 ms  23.336 ms

Here's the tcpdump for accessing google.com:

22:51:26.008883 IP host-196.218.207.18.tedata.net.54011 > host-196.218.207.17.tedata.net.domain:  11001+ A? google.com. (28)
22:51:26.011066 IP host-196.218.207.18.tedata.net.45317 > host-196.218.207.17.tedata.net.domain:  44913+[|domain]
22:51:26.052154 IP host-196.218.207.17.tedata.net.domain > host-196.218.207.18.tedata.net.54011:  11001 3/0/0 A py-in-f99.google.com,[|domain]
22:51:26.052700 IP host-196.218.207.18.tedata.net.57180 > py-in-f99.google.com.www: S 282373541:282373541(0) win 5840 <mss 1460,sackOK,timestamp 741383 0,nop,wscale 5>
22:51:26.090608 IP host-196.218.207.17.tedata.net.domain > host-196.218.207.18.tedata.net.45317:  44913 1/0/0 (89)
22:51:26.091473 IP host-196.218.207.18.tedata.net.34417 > host-196.218.207.17.tedata.net.domain:  49202+[|domain]
--> 22:51:26.105443 IP DOKKI-R03C-GZ-EG > host-196.218.207.18.tedata.net: ICMP parameter problem - octet 20, length 48

Best Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 90%]

* Re: [PATCH try #3] Input/Joystick Driver: add support AD7142 joystick driver
  @ 2007-10-15 18:27 99%   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-10-15 18:27 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: bryan.wu, Andrey Panin, Roel Kluin, linux-input, linux-joystick,
	linux-kernel, akpm, Jean Delvare

On Mon, Oct 15, 2007 at 11:48:17AM -0400, Dmitry Torokhov wrote:
> Hi Bryan,
> 
> On 10/15/07, Bryan Wu <bryan.wu@analog.com> wrote:
> > +
> > +static int ad7142_thread(void *nothing)
> > +{
> > +       do {
> > +               wait_for_completion(&ad7142_completion);
> > +               ad7142_decode();
> > +               enable_irq(CONFIG_BFIN_JOYSTICK_IRQ_PFX);
> > +       } while (!kthread_should_stop());
> > +
> 
> No, this is not going to work well:
> - you at least need to reinitialize the completion before enabling
> IRQ, otherwise you will spin in a very tight loop
> - if noone would touch the joystick ad7142_clsoe would() block
> infinitely because noone would signal the completion and
> ad7142_thread() would never stop.
> 
> Completion is just not a good abstraction here... Please use work
> abstraction and possibly a separate workqueue.
> 

Bryan, I'm very interested in the technical advantage of using a completion
here.

In my _not-experienced_ opinion, I remember completions was created mainly for
"create_task, wait till task got finished, go on" case. Why using it in a
different context while workqueues was created for a similar situation to
ad7142 one (non-irq context bottom-half) ?

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH try #3] Input/Joystick Driver: add support AD7142 joystick driver
  @ 2007-10-16 16:40 99%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-16 16:40 UTC (permalink / raw)
  To: Bryan Wu
  Cc: Dmitry Torokhov, bryan.wu, Andrey Panin, Roel Kluin, linux-input,
	linux-joystick, linux-kernel, akpm, Jean Delvare

On Tue, Oct 16, 2007 at 02:08:04PM +0800, Bryan Wu wrote:
> On 10/16/07, Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> > On Mon, Oct 15, 2007 at 11:48:17AM -0400, Dmitry Torokhov wrote:
> > > Hi Bryan,
> > >
> > > On 10/15/07, Bryan Wu <bryan.wu@analog.com> wrote:
> > > > +
> > > > +static int ad7142_thread(void *nothing)
> > > > +{
> > > > +       do {
> > > > +               wait_for_completion(&ad7142_completion);
> > > > +               ad7142_decode();
> > > > +               enable_irq(CONFIG_BFIN_JOYSTICK_IRQ_PFX);
> > > > +       } while (!kthread_should_stop());
> > > > +
> > >
> > > No, this is not going to work well:
> > > - you at least need to reinitialize the completion before enabling
> > > IRQ, otherwise you will spin in a very tight loop
> > > - if noone would touch the joystick ad7142_clsoe would() block
> > > infinitely because noone would signal the completion and
> > > ad7142_thread() would never stop.
> > >
> > > Completion is just not a good abstraction here... Please use work
> > > abstraction and possibly a separate workqueue.
> > >
> >
> > Bryan, I'm very interested in the technical advantage of using a completion
> > here.
> >
> You are welcome, I'd like to discuss these things here.
> 
> > In my _not-experienced_ opinion, I remember completions was created mainly for
> > "create_task, wait till task got finished, go on" case. Why using it in a
> > different context while workqueues was created for a similar situation to
> > ad7142 one (non-irq context bottom-half) ?
> 
> I like completion because it is simple to use and understand. Your
> understanding is right. But there is no limit for using different
> context with completion. completion is a wrapper of waitqueue+done
> flag. For some drivers, in process context call
> wait_for_completetion(), then schedule out and in irq handler call
> complete(). This is very simple and helpful for driver design (For
> example, you call dma function to transfer data, then you schedule out
> and then DMA IRQ handler will call complete() to wakeup you).
> 

Thank you for such a useful information.

> But in this driver, a) can not call ad7142_decode() in IRQ handler,
> because it will sleep in IRQ context by calling some i2c API, b) in
> original design, creating a new kthread and using some waitqueue API
> is the same way as using workqueue, c) cannot use completion as Dmitry
> said.
> 
> I am going to use workqueue here.
> 
> Any idea?
> 

I have no better thoughts than the ones provided by Dmitry actually.

> Thanks
> -Bryan Wu

Regards :),

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Version 8 (2.6.23) Smack: Simplified Mandatory Access Control Kernel
  @ 2007-10-19 12:39 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-19 12:39 UTC (permalink / raw)
  To: Al Viro
  Cc: Casey Schaufler, torvalds, akpm, linux-security-module, linux-kernel

On 10/18/07, Al Viro <viro@ftp.linux.org.uk> wrote:
> On Thu, Oct 18, 2007 at 05:57:05AM +0100, Al Viro wrote:
> > On Tue, Oct 16, 2007 at 09:17:40PM -0700, Casey Schaufler wrote:
>
> > Think what happens if CPU1 adds to list and CPU2 sees write to smk_known
> > *before* it sees write to ->smk_next.  We see a single-element list and
> > we'll be lucky if that single entry won't be FUBAR.
>
> While we are at it, what protects smack_cipso_count?
> -

My fault. I sent to Casey a one-liner patch to make "smack_cipso_count++"
be protected by the smk_cipsolock spinlock.

We don't need a lock in the reading side since we don't do a write operation
depending on that read, right ?.

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH] Smackv8: Omit non-cipso labels in cipso_seq_start
    @ 2007-10-21  1:40 96% ` Ahmed S. Darwish
  2007-10-21  2:25 93%   ` [PATCH] Smackv8: Safe lockless {cipso,load} read operation Ahmed S. Darwish
  1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-10-21  1:40 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: torvalds, akpm, linux-security-module, linux-kernel

Hi!,

[Casey, sending patches in public to get an early review]

Omit non-cipso labels in cipso_seq_start().

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
stopping seq_show() if smk_cipso = NULL only fixes the bug 
symptom. We'll issue a BUG() in that case cause it signals a
serious misbehavior in the list entries.

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 55ba2dc..b061cd0 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -297,14 +297,22 @@ void smk_cipso_doi(void)
 
 /*
  * Seq_file read operations for /smack/cipso
+ *
+ * Omit labels with no associated cipso values from being
+ * displayed in seq_show()
  */
 
 static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
 {
+	struct smack_known *skp = smack_known;
+
 	if (*pos >= smack_cipso_count)
 		return NULL;
 
-	return smack_known;
+	while (skp && !skp->smk_cipso)
+		skp = skp->smk_next;
+
+	return skp;
 }
 
 static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
@@ -313,9 +321,6 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 
 	(*pos)++;
 
-	/*
-	 * Omit labels with no associated cipso value
-	 */
 	while (skp && !skp->smk_cipso)
 		skp = skp->smk_next;
 
@@ -336,12 +341,11 @@ static int cipso_seq_show(struct seq_file *s, void *v)
 	int i;
 	unsigned char m;
 
-	if (scp == NULL)
-		return 0;
+	BUG_ON(!scp);
+	cbp = scp->smk_catset;
 
 	seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level);
 
-	cbp = scp->smk_catset;
 	for (i = 0; i < SMK_LABELLEN; i++)
 		for (m = 0x80; m != 0; m >>= 1) {
 			if (m & cbp[i]) {


-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 96%]

* [PATCH] Smackv8: Safe lockless {cipso,load} read operation
  2007-10-21  1:40 96% ` [PATCH] Smackv8: Omit non-cipso labels in cipso_seq_start Ahmed S. Darwish
@ 2007-10-21  2:25 93%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-21  2:25 UTC (permalink / raw)
  To: Casey Schaufler, Al Viro
  Cc: torvalds, akpm, linux-security-module, linux-kernel

Hi,

Utilizing Al's concers about using smack_cipso_count without locking,
here's a patch that remove smack_cipso_count and uses simple list 
traversing in read() without any counting mechanism.

CC: Al Viro <viro@ftp.linux.org.uk>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>

---

Please apply over omit-non-cipso-lables-in-cipso-seq-start.patch
Using smack_{list,cipso}_count in the read context was useless
anyway cause we were just traversing the list.

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index b061cd0..c38d0d0 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -63,16 +63,17 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
 
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 static int smack_list_count;
-static int smack_cipso_count;
 struct smk_list_entry *smack_list;
 
+#define SEQ_READ_FINISHED	1
+
 /*
  * Seq_file read operations for /smack/load
  */
 
 static void *load_seq_start(struct seq_file *s, loff_t *pos)
 {
-	if (*pos >= smack_list_count)
+	if (*pos == SEQ_READ_FINISHED)
 		return NULL;
 
 	return smack_list;
@@ -80,8 +81,13 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
 
 static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	(*pos)++;
-	return ((struct smk_list_entry *) v)->smk_next;
+	struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
+
+	if (skp)
+		return skp;
+
+	*pos = SEQ_READ_FINISHED;
+	return NULL;
 }
 
 static int load_seq_show(struct seq_file *s, void *v)
@@ -306,7 +312,7 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
 {
 	struct smack_known *skp = smack_known;
 
-	if (*pos >= smack_cipso_count)
+	if (*pos == SEQ_READ_FINISHED)
 		return NULL;
 
 	while (skp && !skp->smk_cipso)
@@ -319,12 +325,14 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
 	struct smack_known *skp = ((struct smack_known *) v)->smk_next;
 
-	(*pos)++;
-
 	while (skp && !skp->smk_cipso)
 		skp = skp->smk_next;
 
-	return skp;
+	if (skp)
+		return skp;
+
+	*pos = SEQ_READ_FINISHED;
+	return NULL;
 }
 
 /*
@@ -488,7 +496,6 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
 				rc = -ENOMEM;
 				break;
 			}
-			++smack_cipso_count;
 		} else
 			scp = NULL;
 

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 93%]

* Rule parsing from a virtual FS write() syscall
@ 2007-10-24 11:00 99% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-24 11:00 UTC (permalink / raw)
  To: linux-kernel; +Cc: casey, viro

Hi all,

In SMACK, some rules are written to a virtual fs file named 
"cipso".

Rule format is

label level[/cat[,cat]]

Under high I/O load we don't recieve the whole rule in one shot.
This means that sometimes the write() operation begins from the 
middle of the rule. Under some conditions, the first rule _letter_
was only recieved while others were recieved in remaining write() 
calls.

Current SMACK versions don't assume fragmented input like above
cases. This means that sometimes bogus rules that does not 
represent users' intent got created.

What is the best way to parse a rule in such hard coditions?

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH 2/2] Version 9 (2.6.24-rc1) Smack: Simplified Mandatory Access Control Kernel
  @ 2007-10-27  3:00 85% ` Ahmed S. Darwish
  2007-10-27  9:01 96% ` Ahmed S. Darwish
  1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-27  3:00 UTC (permalink / raw)
  To: casey; +Cc: akpm, torvalds, linux-security-module, linux-kernel

Hi Casey,

Casey <casey@schaufler-ca.com> wrote:
>
> This version is again aimed at addressing Al Viro's issues in
> smackfs. Ahmed Darwish has again contributed in the repair of the
> locking issues there. The move to 2.6.24 was also an important
> release incentive.
>

My patches mentiond above is not applied in this version. The same 
lock issues remain. Did you forget applying them ? In that case, 
here're the same patches again (on ver8):

==> 1:
cipso_seq_show should not be passed smack labels with no cipso
mapping. Omit non-cipso mapped labels in cipso_seq_start and 
BUG in case cipso_seq_show was passed a non-cipso label.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.coM>
---

smackv8-omit-noncipso-in-seq-start.patch

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 55ba2dc..b061cd0 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -297,14 +297,22 @@ void smk_cipso_doi(void)
 
 /*
  * Seq_file read operations for /smack/cipso
+ *
+ * Omit labels with no associated cipso values from being
+ * displayed in seq_show()
  */
 
 static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
 {
+	struct smack_known *skp = smack_known;
+
 	if (*pos >= smack_cipso_count)
 		return NULL;
 
-	return smack_known;
+	while (skp && !skp->smk_cipso)
+		skp = skp->smk_next;
+
+	return skp;
 }
 
 static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
@@ -313,9 +321,6 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 
 	(*pos)++;
 
-	/*
-	 * Omit labels with no associated cipso value
-	 */
 	while (skp && !skp->smk_cipso)
 		skp = skp->smk_next;
 
@@ -336,12 +341,11 @@ static int cipso_seq_show(struct seq_file *s, void *v)
 	int i;
 	unsigned char m;
 
-	if (scp == NULL)
-		return 0;
+	BUG_ON(!scp);
+	cbp = scp->smk_catset;
 
 	seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level);
 
-	cbp = scp->smk_catset;
 	for (i = 0; i < SMK_LABELLEN; i++)
 		for (m = 0x80; m != 0; m >>= 1) {
 			if (m & cbp[i]) {

==> 2:

Avoid racy use of smack_{list,cipso}_count in traversing lists.
Simple smack_list and smack_known lockless list traversal is all 
what's needed.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

smackv8-lockless-read.patch

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index b061cd0..e343827 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -63,16 +63,17 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
 
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 static int smack_list_count;
-static int smack_cipso_count;
 struct smk_list_entry *smack_list;
 
+#define SEQ_READ_FINISHED	1
+
 /*
  * Seq_file read operations for /smack/load
  */
 
 static void *load_seq_start(struct seq_file *s, loff_t *pos)
 {
-	if (*pos >= smack_list_count)
+	if (*pos == SEQ_READ_FINISHED)
 		return NULL;
 
 	return smack_list;
@@ -80,8 +81,12 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
 
 static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	(*pos)++;
-	return ((struct smk_list_entry *) v)->smk_next;
+	struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
+
+	if (!skp)
+		*pos = SEQ_READ_FINISHED;
+
+	return skp;
 }
 
 static int load_seq_show(struct seq_file *s, void *v)
@@ -306,7 +311,7 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
 {
 	struct smack_known *skp = smack_known;
 
-	if (*pos >= smack_cipso_count)
+	if (*pos == SEQ_READ_FINISHED)
 		return NULL;
 
 	while (skp && !skp->smk_cipso)
@@ -319,11 +324,12 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
 	struct smack_known *skp = ((struct smack_known *) v)->smk_next;
 
-	(*pos)++;
-
 	while (skp && !skp->smk_cipso)
 		skp = skp->smk_next;
 
+	if (!skp)
+		*pos = SEQ_READ_FINISHED;
+
 	return skp;
 }
 
@@ -488,7 +494,6 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
 				rc = -ENOMEM;
 				break;
 			}
-			++smack_cipso_count;
 		} else
 			scp = NULL;
 

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 85%]

* Re: [PATCH 2/2] Version 9 (2.6.24-rc1) Smack: Simplified Mandatory Access Control Kernel
    2007-10-27  3:00 85% ` Ahmed S. Darwish
@ 2007-10-27  9:01 96% ` Ahmed S. Darwish
    1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-10-27  9:01 UTC (permalink / raw)
  To: casey; +Cc: akpm, torvalds, linux-security-module, linux-kernel

> +/**
> + * smk_write_cipso - write() for /smack/cipso
> + * @filp: file pointer, not actually used
> + * @buf: where to get the data from
> + * @count: bytes sent
> + * @ppos: where to start
> + *
> + * Returns number of bytes written or error code, as appropriate
> + */
> +static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
> +			       size_t count, loff_t *ppos)
> +{

[...]

> +
> +	/*
> +	 * Only allow one writer at a time. Writes should be
> +	 * quite rare and small in any case.
> +	 */
> +	mutex_lock(&smack_cipso_lock);
> +
> +	*(data + count) = '\0';
> +
> +	for (eolp = strchr(data, '\n'), linep = data;
> +		eolp != NULL && rc >= 0;
> +		linep = eolp + 1, eolp = strchr(linep, '\n')) {
> +

The problem here (As discussed in private mails) is that the for loop 
assumes that the beginning of given user-space buffer is the beginning
of a rule. This leads to situations where the rule becomes "ecret 20",
or "cret 20" instead of "Secret 20". Big input buffers/files leads 
smack to recieve a rule like "Secret 20" in fragmented chunks like:

write("<lots of rules before ours>\nSec", ..)
write("r", 1, ..)
write("et 20\n<remaing rules after ours>", ..)

Parsing a rule in such tough conditions in _kernel space_ is very
hard. I began to feel that it will be much easier if we do the parsing 
in a userspace utility and let smack accept only small buffers (80 char). 

i.e. A user space utility that takes a big input file like
exit 10/3,7,4
exit 10/3,7,4
exit 10/3,7,4
<100 times>

And transform it to 100 small write() calls. By this way we can return
-EINVAL if write()'s count field > 80, or if input contains no \n or
more than one.

Any Ideas ?. 

Casey, I can begin modifying cipso_write() and writing this small 
user-space utility now if you agree on this.

Regards,

-- 
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 96%]

* Re: [PATCH 2/2] Version 9 (2.6.24-rc1) Smack: Simplified Mandatory Access Control Kernel
  @ 2007-10-28 12:46 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-10-28 12:46 UTC (permalink / raw)
  To: Al Viro; +Cc: casey, akpm, torvalds, linux-security-module, linux-kernel

On 10/28/07, Al Viro <viro@ftp.linux.org.uk> wrote:
> On Sat, Oct 27, 2007 at 11:01:12AM +0200, Ahmed S. Darwish wrote:
> > The problem here (As discussed in private mails) is that the for loop
> > assumes that the beginning of given user-space buffer is the beginning
> > of a rule. This leads to situations where the rule becomes "ecret 20",
> > or "cret 20" instead of "Secret 20". Big input buffers/files leads
> > smack to recieve a rule like "Secret 20" in fragmented chunks like:
> >
> > write("<lots of rules before ours>\nSec", ..)
> > write("r", 1, ..)
> > write("et 20\n<remaing rules after ours>", ..)
> >
> > Parsing a rule in such tough conditions in _kernel space_ is very
> > hard. I began to feel that it will be much easier if we do the parsing
> > in a userspace utility and let smack accept only small buffers (80 char).
>
> For crying out louf, all it takes is a finite state machine...  BTW, folks,
> your parser *and* input language suck.  Really.  Silently allowing noise
> is Dumb(tm).
>

Ehem .., I really thought about the FSM thing but I thought it won't
be possible with concurrent writes (forgetting that several related
writes is done in one open(),release() session and we can lock writes
in open()).

<Getting back to coding>

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH] Smackv9: Use a stateful parser for parsing Smack rules
  @ 2007-11-01 15:54 74% ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-11-01 15:54 UTC (permalink / raw)
  To: casey; +Cc: akpm, torvalds, linux-security-module, linux-kernel, viro

Hi Casey/Al/all,

A patch that utilizes Al Viro's concerns on previous smack parser
and solves pevious parser bugs discovered by Ahmed Darwish. By now,
no problem will occur if given smack rules are fragmented over
multiple write() calls.

CC: Al Viro <viro@ftp.linux.org.uk>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

A similar patch for parsing CIPSO rules will be sent soon.

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 88b3f7b..9b56281 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -67,6 +67,39 @@ static int smack_cipso_count;
 struct smk_list_entry *smack_list;
 
 /*
+ * Disable concurrent writing open() operations
+ */
+static struct semaphore smack_write_sem;
+
+/*
+ * States for parsing /smack/load rules
+ */
+enum load_state {
+	subject      = 0,
+	object       = 1,
+	access       = 2,
+	eol          = 3,
+};
+
+/*
+ * Represent current parsing state of /smack/load. Struct
+ * also stores data needed between an open-release session's
+ * multiple write() calls
+ */
+static struct smack_load_state {
+	enum load_state state;
+	struct  smack_rule rule;
+	int     label_len;
+	char    subject[SMK_LABELLEN];
+	char    object[SMK_LABELLEN];
+} *load_state;
+
+static inline int isblank(char c)
+{
+	return (c == ' ' || c == '\t');
+}
+
+/*
  * Seq_file read operations for /smack/load
  */
 
@@ -127,12 +160,43 @@ static struct seq_operations load_seq_ops = {
  * @inode: inode structure representing file
  * @file: "load" file pointer
  *
- * Connect our load_seq_* operations with /smack/load
- * file_operations
+ * For reading, use load_seq_* seq_file reading operations.
+ * For writing, prepare a load_state struct to parse
+ * incoming rules.
  */
 static int smk_open_load(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &load_seq_ops);
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return seq_open(file, &load_seq_ops);
+
+	if (down_interruptible(&smack_write_sem))
+		return -ERESTARTSYS;
+
+	load_state = kzalloc(sizeof(struct smack_load_state), GFP_KERNEL);
+	if (!load_state)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * smk_release_load - release() for /smack/load
+ * @inode: inode structure representing file
+ * @file: "load" file pointer
+ *
+ * For a reading session, use the seq_file release
+ * implementation.
+ * Otherwise, we are at the end of a writing session so
+ * clean everything up.
+ */
+static int smk_release_load(struct inode *inode, struct file *file)
+{
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return seq_release(inode, file);
+
+	kfree(load_state);
+	up(&smack_write_sem);
+	return 0;
 }
 
 /**
@@ -171,7 +235,6 @@ static void smk_set_access(struct smack_rule *srp)
 	return;
 }
 
-
 /**
  * smk_write_load - write() for /smack/load
  * @filp: file pointer, not actually used
@@ -179,19 +242,20 @@ static void smk_set_access(struct smack_rule *srp)
  * @count: bytes sent
  * @ppos: where to start
  *
- * Returns number of bytes written or error code, as appropriate
+ * Parse smack rules of format "subject object accesss". Handle
+ * defragmented rules over several write calls using the
+ * load_state structure.
  */
 static ssize_t smk_write_load(struct file *file, const char __user *buf,
 			      size_t count, loff_t *ppos)
 {
-	struct smack_rule rule;
-	ssize_t rc = count;
+	struct smack_rule *rule = &load_state->rule;
+	int *label_len = &load_state->label_len;
+	char *subjectstr = load_state->subject;
+	char *objectstr = load_state->object;
+	ssize_t rc = -EINVAL;
 	char *data = NULL;
-	char subjectstr[SMK_LABELLEN];
-	char objectstr[SMK_LABELLEN];
-	char modestr[8];
-	char *cp;
-
+	int i;
 
 	if (!capable(CAP_MAC_OVERRIDE))
 		return -EPERM;
@@ -205,7 +269,7 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
 	 * 80 characters per line ought to be enough.
 	 */
 	if (count > SMACK_LIST_MAX * 80)
-		return -ENOMEM;
+		return -EFBIG;
 
 	data = kzalloc(count + 1, GFP_KERNEL);
 	if (data == NULL)
@@ -218,30 +282,74 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
 
 	*(data + count) = '\0';
 
-	for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) {
-		if (*++cp == '\0')
+	for (i = 0; i < count && data[i]; i ++)
+		switch (load_state->state) {
+		case subject:
+			if (isblank(data[i])) {
+				load_state->state = object;
+				subjectstr[*label_len] = '\0';
+				*label_len = 0;
+				break;
+			}
+			if (*label_len >= SMK_MAXLEN)
+				goto out;
+			subjectstr[(*label_len) ++] = data[i];
 			break;
-		if (sscanf(cp, "%23s %23s %7s\n", subjectstr, objectstr,
-			   modestr) != 3)
+
+		case object:
+			if (isblank(data[i])) {
+				load_state->state = access;
+				objectstr[*label_len] = '\0';
+				*label_len = 0;
+				break;
+			}
+
+			if (*label_len >= SMK_MAXLEN)
+				goto out;
+			objectstr[(*label_len) ++] = data[i];
 			break;
-		rule.smk_subject = smk_import(subjectstr, 0);
-		if (rule.smk_subject == NULL)
+
+		case access:
+			if (isblank(data[i]) || data[i] == '\n') {
+				load_state->state = eol;
+				/* Let "eol" take control from current char */
+				--i;
+				break;
+			}
+
+			if (data[i] == 'r')
+				rule->smk_access |= MAY_READ;
+			else if (data[i] == 'w')
+				rule->smk_access |= MAY_WRITE;
+			else if (data[i] == 'x')
+				rule->smk_access |= MAY_EXEC;
+			else if (data[i] == 'a')
+				rule->smk_access |= MAY_APPEND;
+			else
+				goto out;
 			break;
-		rule.smk_object = smk_import(objectstr, 0);
-		if (rule.smk_object == NULL)
+
+		case eol:
+			if (isblank(data[i]))
+				break;
+
+			load_state->state = subject;
+			*label_len = 0;
+
+			rule->smk_subject = smk_import(subjectstr, 0);
+			if (rule->smk_subject == NULL)
+				goto out;
+
+			rule->smk_object = smk_import(objectstr, 0);
+			if (rule->smk_object == NULL)
+				goto out;
+
+			smk_set_access(rule);
 			break;
-		rule.smk_access = 0;
-		if (strpbrk(modestr, "rR") != NULL)
-			rule.smk_access |= MAY_READ;
-		if (strpbrk(modestr, "wW") != NULL)
-			rule.smk_access |= MAY_WRITE;
-		if (strpbrk(modestr, "xX") != NULL)
-			rule.smk_access |= MAY_EXEC;
-		if (strpbrk(modestr, "aA") != NULL)
-			rule.smk_access |= MAY_APPEND;
-		smk_set_access(&rule);
-	}
+		}
 
+	rc = count;
+out:
 	kfree(data);
 	return rc;
 }
@@ -251,7 +359,7 @@ static const struct file_operations smk_load_ops = {
 	.read		= seq_read,
 	.llseek         = seq_lseek,
 	.write		= smk_write_load,
-	.release        = seq_release
+	.release        = smk_release_load,
 };
 
 /**
@@ -921,6 +1029,7 @@ static int __init init_smk_fs(void)
 		}
 	}
 
+	sema_init(&smack_write_sem, 1);
 	smk_cipso_doi();
 
 	return err;

--
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 74%]

* Re: [PATCH] Smackv9: Use a stateful parser for parsing Smack rules
  @ 2007-11-02 18:50 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-02 18:50 UTC (permalink / raw)
  To: Jan Engelhardt
  Cc: casey, akpm, torvalds, linux-security-module, linux-kernel, viro

On 11/1/07, Jan Engelhardt <jengelh@computergmbh.de> wrote:
>
> On Nov 1 2007 17:54, Ahmed S. Darwish wrote:
> >+
> >+static inline int isblank(char c)
> >+{
> >+      return (c == ' ' || c == '\t');
> >+}
>
> Use isspace().
>

isspace accepts newlines and carriage-returns too which is not
accepted between elements of a one rule.

> >+      for (i = 0; i < count && data[i]; i ++)
> >...
> >+                      subjectstr[(*label_len) ++] = data[i];
>
> i++ w/o space
>

Notes Taken. Thanks for the review.

Regards,

Darwish

^ permalink raw reply	[relevance 99%]

* [PATCH] Smackv10: Smack rules grammar + their stateful parser
  @ 2007-11-03 16:43 65% ` Ahmed S. Darwish
                       ` (4 more replies)
  0 siblings, 5 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-03 16:43 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: akpm, torvalds, linux-security-module, linux-kernel

On Fri, Nov 02, 2007 at 01:50:55PM -0700, Casey Schaufler wrote:
> 
> Still to come:
> 
>   - Final cleanup of smack_load_write and smack_cipso_write.

Hi All,

After agreeing with Casey on the "load" input grammar yesterday, here's
the final grammar and its parser (which needs more testing):

A Smack Rule in an "egrep" format is:

"^[:space:]*Subject[:space:]+Object[:space:]+[rwxaRWXA-]+[:space:]*\n"

where Subject/Object strings are in the form:

"^[^/[:space:][:cntrl:]]{1,SMK_MAXLEN}$"

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

Bashv3 builtin "echo" behaves very strangely to -EINVAL. It sends all
the buffers that causes -EINVAL again in subsequent echo invocations.

i.e.
echo "Invalid Rule" > /smack/load  # -EINVAL returned
echo "Valid Rule" > /smack/load

In seconod iteration, echo sends the first invalid buffer again 
then sends the new one. This causes a 
"Invalid Rule\nValid Rule" buffer sent to write().

IMHO, this is a bug in builtin echo. The external /bin/echo doesn't 
cause such strange behaviour.

diff --git a/security/smack/smack.h b/security/smack/smack.h
index e0b7d26..8dcdb79 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -219,4 +219,16 @@ static inline char *smk_of_inode(const struct inode *isp)
 	return sip->smk_inode;
 }
 
+static inline int isblank(char c)
+{
+	return (c == ' ' || c == '\t');
+}
+
+#define swap(x, y, type)      \
+do {			      \
+	type tmp = x;	      \
+	x = y;		      \
+	y = tmp;	      \
+} while (0);		      \
+
 #endif  /* _SECURITY_SMACK_H */
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 3572ae5..0b1b530 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -25,6 +25,7 @@
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 #include <linux/seq_file.h>
+#include <linux/ctype.h>
 #include "smack.h"
 
 /*
@@ -67,6 +68,39 @@ struct smk_list_entry *smack_list;
 #define	SEQ_READ_FINISHED	1
 
 /*
+ * Disable concurrent writing open() operations
+ */
+static struct semaphore smack_write_sem;
+
+/*
+ * States for parsing /smack/load rules
+ */
+enum load_state {
+	bol          = 0,            /* At Beginning Of Line */
+	subject      = 1,            /* At a "subject" token */
+	object       = 2,            /* At an "object" token */
+	access       = 3,            /* At an "access" token */
+	newline      = 4,            /* At end Of Line */
+	blank        = 5,            /* At a space or tab */
+};
+
+/*
+ * Represent current parsing state of /smack/load. Struct
+ * also stores data needed between an open-release session's
+ * multiple write() calls
+ */
+static struct smack_load_state {
+	enum load_state state;       /* Current FSM parsing state */
+	enum load_state prevstate;   /* Previous FSM state */
+	struct smack_rule rule;      /* Rule to be loaded */
+	int label_len;               /* Subject/Object labels length so far */
+	char subject[SMK_LABELLEN];  /* Subject label */
+	char object[SMK_LABELLEN];   /* Object label */
+	int access;                  /* Bool, parsed an "access" token ? */
+} *load_state;
+
+
+/*
  * Seq_file read operations for /smack/load
  */
 
@@ -131,12 +165,43 @@ static struct seq_operations load_seq_ops = {
  * @inode: inode structure representing file
  * @file: "load" file pointer
  *
- * Connect our load_seq_* operations with /smack/load
- * file_operations
+ * For reading, use load_seq_* seq_file reading operations.
+ * For writing, prepare a load_state struct to parse
+ * incoming rules.
  */
 static int smk_open_load(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &load_seq_ops);
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return seq_open(file, &load_seq_ops);
+
+	if (down_interruptible(&smack_write_sem))
+		return -ERESTARTSYS;
+
+	load_state = kzalloc(sizeof(struct smack_load_state), GFP_KERNEL);
+	if (!load_state)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * smk_release_load - release() for /smack/load
+ * @inode: inode structure representing file
+ * @file: "load" file pointer
+ *
+ * For a reading session, use the seq_file release
+ * implementation.
+ * Otherwise, we are at the end of a writing session so
+ * clean everything up.
+ */
+static int smk_release_load(struct inode *inode, struct file *file)
+{
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return seq_release(inode, file);
+
+	kfree(load_state);
+	up(&smack_write_sem);
+	return 0;
 }
 
 /**
@@ -174,7 +239,6 @@ static void smk_set_access(struct smack_rule *srp)
 	return;
 }
 
-
 /**
  * smk_write_load - write() for /smack/load
  * @filp: file pointer, not actually used
@@ -182,19 +246,26 @@ static void smk_set_access(struct smack_rule *srp)
  * @count: bytes sent
  * @ppos: where to start
  *
- * Returns number of bytes written or error code, as appropriate
+ * Parse smack rules in below extended regex format:
+ * "^[:space:]*Subject[:space:]+Object[:space:]+[rwxaRWXA-]+[:space:]*\n"
+ * Where Subject/Object are: "^[^/[:space:][:cntrl:]]{1,SMK_MAXLEN}$"
+ *
+ * Handle defragmented rules over several write calls using a Finite
+ * State Machine that saves its state in the load_state structure.
  */
 static ssize_t smk_write_load(struct file *file, const char __user *buf,
 			      size_t count, loff_t *ppos)
 {
-	struct smack_rule rule;
-	ssize_t rc = count;
+	struct smack_rule *rule = &load_state->rule;
+	enum load_state *state = &load_state->state;
+	enum load_state *prevstate = &load_state->prevstate;
+	int *label_len = &load_state->label_len;
+	char *subjectstr = load_state->subject;
+	char *objectstr = load_state->object;
+	int *accesstok = &load_state->access;
+	ssize_t rc = -EINVAL;
 	char *data = NULL;
-	char subjectstr[SMK_LABELLEN];
-	char objectstr[SMK_LABELLEN];
-	char modestr[8];
-	char *cp;
-
+	int i;
 
 	if (!capable(CAP_MAC_OVERRIDE))
 		return -EPERM;
@@ -208,7 +279,7 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
 	 * 80 characters per line ought to be enough.
 	 */
 	if (count > SMACK_LIST_MAX * 80)
-		return -ENOMEM;
+		return -EFBIG;
 
 	data = kzalloc(count + 1, GFP_KERNEL);
 	if (data == NULL)
@@ -221,30 +292,93 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
 
 	data[count] = '\0';
 
-	for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) {
-		if (*++cp == '\0')
+	for (i = 0; i < count && data[i]; i++) {
+		if (!isgraph(data[i]) && !isspace(data[i]))
+			goto out;
+
+		/* If a char-blank transition occurred */
+		if (isblank(data[i]) && *state != blank)
+			*prevstate = *state;
+		/* If a blank-char transition occurred */
+		if (!isblank(data[i]) && *state == blank) {
+			swap(*state, *prevstate, typeof(*state));
+			++(*state);
+		}
+
+		if (isblank(data[i]))
+			*state = blank;
+
+		if (data[i] == '\n')
+			*state = newline;
+
+		switch (*state) {
+		case bol:
+		case subject:
+			if (*label_len >= SMK_MAXLEN)
+				goto out;
+			subjectstr[(*label_len)++] = data[i];
+			*state = subject;
+			break;
+
+		case object:
+			if (*prevstate == blank) {
+				subjectstr[*label_len] = '\0';
+				*label_len = 0;
+				*prevstate = *state = object;
+			}
+
+			if (*label_len >= SMK_MAXLEN)
+				goto out;
+			objectstr[(*label_len)++] = data[i];
 			break;
-		if (sscanf(cp, "%23s %23s %7s\n", subjectstr, objectstr,
-			   modestr) != 3)
+
+		case access:
+			if (*prevstate == blank) {
+				objectstr[*label_len] = '\0';
+				*label_len = 0;
+				*prevstate = *state = access;
+			}
+
+			if (data[i] == 'r' || data[i] == 'R')
+				rule->smk_access |= MAY_READ;
+			else if (data[i] == 'w' || data[i] == 'W')
+				rule->smk_access |= MAY_WRITE;
+			else if (data[i] == 'x' || data[i] == 'X')
+				rule->smk_access |= MAY_EXEC;
+			else if (data[i] == 'a' || data[i] == 'A')
+				rule->smk_access |= MAY_APPEND;
+			else if (data[i] == '-')
+				/* No-Op, '-' is a placeholder */;
+			else
+				goto out;
+			*accesstok = 1;
 			break;
-		rule.smk_subject = smk_import(subjectstr, 0);
-		if (rule.smk_subject == NULL)
+
+		case newline:
+			if (*accesstok == 0)
+				goto out;
+
+			rule->smk_subject = smk_import(subjectstr, 0);
+			if (rule->smk_subject == NULL)
+				goto out;
+
+			rule->smk_object = smk_import(objectstr, 0);
+			if (rule->smk_object == NULL)
+				goto out;
+
+			smk_set_access(rule);
+
+			/* Reset everything, a new rule will come */
+			memset(load_state, 0, sizeof(*load_state));
 			break;
-		rule.smk_object = smk_import(objectstr, 0);
-		if (rule.smk_object == NULL)
+
+		case blank:
 			break;
-		rule.smk_access = 0;
-		if (strpbrk(modestr, "rR") != NULL)
-			rule.smk_access |= MAY_READ;
-		if (strpbrk(modestr, "wW") != NULL)
-			rule.smk_access |= MAY_WRITE;
-		if (strpbrk(modestr, "xX") != NULL)
-			rule.smk_access |= MAY_EXEC;
-		if (strpbrk(modestr, "aA") != NULL)
-			rule.smk_access |= MAY_APPEND;
-		smk_set_access(&rule);
+		}
 	}
 
+	rc = count;
+out:
 	kfree(data);
 	return rc;
 }
@@ -254,7 +388,7 @@ static const struct file_operations smk_load_ops = {
 	.read		= seq_read,
 	.llseek         = seq_lseek,
 	.write		= smk_write_load,
-	.release        = seq_release
+	.release        = smk_release_load,
 };
 
 /**
@@ -924,6 +1058,7 @@ static int __init init_smk_fs(void)
 		}
 	}
 
+	sema_init(&smack_write_sem, 1);
 	smk_cipso_doi();
 
 	return err;

--
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 65%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
  @ 2007-11-03 22:12 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-03 22:12 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: Casey Schaufler, akpm, torvalds, linux-security-module, linux-kernel

On 11/3/07, Kyle Moffett <mrmacman_g4@mac.com> wrote:
> On Nov 03, 2007, at 12:43:06, Ahmed S. Darwish wrote:
> > Bashv3 builtin "echo" behaves very strangely to -EINVAL. It sends
> > all the buffers that causes -EINVAL again in subsequent echo
> > invocations.
> >
> > i.e.
> > echo "Invalid Rule" > /smack/load  # -EINVAL returned
> > echo "Valid Rule" > /smack/load
> >
> > In seconod iteration, echo sends the first invalid buffer again
> > then sends the new one. This causes a "Invalid Rule\nValid Rule"
> > buffer sent to write().
> >
> > IMHO, this is a bug in builtin echo. The external /bin/echo doesn't
> > cause such strange behaviour.
>
> Actually, what causes problems here is something between a bug and a
> feature in libc's buffering.  Basically the -EINVAL error causes libc
> to leave its data in the file-output buffer despite the file being
> closed and reopened. Since a standalone echo just exits that buffer
> is discarded, but for the bash builtin it hangs around in the buffer
> for a while and ends up getting prepended to the following echo
> statement.  There's actually multiple ways to make this fail; this is
> just the simplest.
>

Thanks a lot for such a useful info. Is there a way from my side  to
make subsequent echo invocations not affected by previous failed ones
?

Regards,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
  @ 2007-11-04 13:23 99%     ` Ahmed S. Darwish
  2007-11-05  9:41 99%     ` Ahmed S. Darwish
  1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-04 13:23 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Casey Schaufler, akpm, torvalds, linux-security-module, linux-kernel

On 11/4/07, Pavel Machek <pavel@ucw.cz> wrote:
> Hi!
>
> > > Still to come:
> > >
> > >   - Final cleanup of smack_load_write and smack_cipso_write.
> >
> > Hi All,
> >
> > After agreeing with Casey on the "load" input grammar yesterday, here's
> > the final grammar and its parser (which needs more testing):
> >
> > A Smack Rule in an "egrep" format is:
> >
> > "^[:space:]*Subject[:space:]+Object[:space:]+[rwxaRWXA-]+[:space:]*\n"
> >
> > where Subject/Object strings are in the form:
> >
> > "^[^/[:space:][:cntrl:]]{1,SMK_MAXLEN}$"
>
> Can we avoid string parsers in the kernel?
>

I've suggested that at first, but (hoping not to misquote Al) Al viro
said that the parsing is simple enough and no need exists for a
user-space utility.

>
> > +static inline int isblank(char c)
> > +{
> > +     return (c == ' ' || c == '\t');
> > +}
>
> This sounds like enough for 'NAK'.
>

Would you please show the reason for the NAK so I can modify the code ?

Thank you,

>                                                 Pavel,
>                 who still thinks smack rules should be parsed
>                 in userspace and compiled into selinux rules...
>

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
  2007-11-03 16:43 65% ` [PATCH] Smackv10: Smack rules grammar + their stateful parser Ahmed S. Darwish
    @ 2007-11-04 20:06 99%   ` Ahmed S. Darwish
  2007-11-05  0:56 69%   ` [PATCH] Smackv10: Smack rules grammar + their stateful parser(2) Ahmed S. Darwish
    4 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-04 20:06 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: akpm, torvalds, linux-security-module, linux-kernel

On 11/3/07, Ahmed S. Darwish <darwish.07@gmail.com> wrote:
>  static int smk_open_load(struct inode *inode, struct file *file)
>  {
> -       return seq_open(file, &load_seq_ops);
> +       if ((file->f_flags & O_ACCMODE) == O_RDONLY)
> +               return seq_open(file, &load_seq_ops);
> +
> +       if (down_interruptible(&smack_write_sem))
> +               return -ERESTARTSYS;
> +
> +       load_state = kzalloc(sizeof(struct smack_load_state), GFP_KERNEL);
> +       if (!load_state)
> +               return -ENOMEM;
> +
> +       return 0;
> +}

Is it right to do the kzalloc with the semaphore being held? Will the
lock be held forever If kzalloc failed and -ENOMEM was returned ?

Thanks,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH] Smackv10: Smack rules grammar + their stateful parser(2)
  2007-11-03 16:43 65% ` [PATCH] Smackv10: Smack rules grammar + their stateful parser Ahmed S. Darwish
                     ` (2 preceding siblings ...)
  2007-11-04 20:06 99%   ` Ahmed S. Darwish
@ 2007-11-05  0:56 69%   ` Ahmed S. Darwish
        4 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-05  0:56 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: akpm, torvalds, linux-security-module, linux-kernel, Al Viro

On Sat, Nov 03, 2007 at 06:43:06PM +0200, Ahmed S. Darwish wrote:
> On Fri, Nov 02, 2007 at 01:50:55PM -0700, Casey Schaufler wrote:
> > 
> > Still to come:
> > 
> >   - Final cleanup of smack_load_write and smack_cipso_write.
> 
> Hi All,
> 
> After agreeing with Casey on the "load" input grammar yesterday, here's
> the final grammar and its parser (which needs more testing):
> 
> A Smack Rule in an "egrep" format is:
> 
> "^[:space:]*Subject[:space:]+Object[:space:]+[rwxaRWXA-]+[:space:]*\n"
> 
> where Subject/Object strings are in the form:
> 
> "^[^/[:space:][:cntrl:]]{1,SMK_MAXLEN}$"
> 
> Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
> ---
> 

Same parser with adhering Casey's concers about previous one 
and with using the FSM states in a more readable way. 

I've double-checked the code for any possible off-by-one/overflow 
errors. Could someone overcheck this for any possible hidden 
security holes. Al, please :) ?

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 3572ae5..c9461cb 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -25,6 +25,7 @@
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 #include <linux/seq_file.h>
+#include <linux/ctype.h>
 #include "smack.h"
 
 /*
@@ -67,6 +68,47 @@ struct smk_list_entry *smack_list;
 #define	SEQ_READ_FINISHED	1
 
 /*
+ * Disable concurrent writing open() operations
+ */
+static struct semaphore smack_write_sem;
+
+/*
+ * States for parsing /smack/load rules
+ */
+enum load_state {
+	bol          = 0,            /* At Beginning Of Line */
+	subject      = 1,            /* At a "subject" token */
+	object       = 2,            /* At an "object" token */
+	access       = 3,            /* At an "access" token */
+	newline      = 4,            /* At end Of Line */
+	blank        = 5,            /* At a space or tab */
+};
+
+/*
+ * Represent current parsing state of /smack/load. Struct
+ * also stores data needed between an open-release session's
+ * multiple write() calls
+ */
+static struct smack_load_state {
+	enum load_state state;       /* Current FSM parsing state */
+	enum load_state prevstate;   /* Previous FSM state */
+	enum load_state prevtoken;   /* Handle state = prevstate = blank */
+	struct smack_rule rule;      /* Rule to be loaded */
+	int label_len;               /* Subject/Object labels length so far */
+	char subject[SMK_LABELLEN];  /* Subject label */
+	char object[SMK_LABELLEN];   /* Object label */
+} *load_state;
+
+/*
+ * Rule's tokens separators are spaces and tabs only
+ */
+static inline int isblank(char c)
+{
+	return (c == ' ' || c == '\t');
+}
+
+
+/*
  * Seq_file read operations for /smack/load
  */
 
@@ -131,12 +173,43 @@ static struct seq_operations load_seq_ops = {
  * @inode: inode structure representing file
  * @file: "load" file pointer
  *
- * Connect our load_seq_* operations with /smack/load
- * file_operations
+ * For reading, use load_seq_* seq_file reading operations.
+ * For writing, prepare a load_state struct to parse
+ * incoming rules.
  */
 static int smk_open_load(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &load_seq_ops);
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return seq_open(file, &load_seq_ops);
+
+	if (down_interruptible(&smack_write_sem))
+		return -ERESTARTSYS;
+
+	load_state = kzalloc(sizeof(struct smack_load_state), GFP_KERNEL);
+	if (!load_state)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * smk_release_load - release() for /smack/load
+ * @inode: inode structure representing file
+ * @file: "load" file pointer
+ *
+ * For a reading session, use the seq_file release
+ * implementation.
+ * Otherwise, we are at the end of a writing session so
+ * clean everything up.
+ */
+static int smk_release_load(struct inode *inode, struct file *file)
+{
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return seq_release(inode, file);
+
+	kfree(load_state);
+	up(&smack_write_sem);
+	return 0;
 }
 
 /**
@@ -174,7 +247,6 @@ static void smk_set_access(struct smack_rule *srp)
 	return;
 }
 
-
 /**
  * smk_write_load - write() for /smack/load
  * @filp: file pointer, not actually used
@@ -182,19 +254,26 @@ static void smk_set_access(struct smack_rule *srp)
  * @count: bytes sent
  * @ppos: where to start
  *
- * Returns number of bytes written or error code, as appropriate
+ * Parse smack rules in below extended regex format:
+ * "^[:space:]*Subject[:space:]+Object[:space:]+[rwxaRWXA-]+[:space:]*$"
+ * Where Subject/Object are: "^[^/[:space:][:cntrl:]]{1,SMK_MAXLEN}$"
+ *
+ * Handle defragmented rules over several write calls using the
+ * load_state structure.
  */
 static ssize_t smk_write_load(struct file *file, const char __user *buf,
 			      size_t count, loff_t *ppos)
 {
-	struct smack_rule rule;
-	ssize_t rc = count;
+	struct smack_rule *rule = &load_state->rule;
+	enum load_state *state = &load_state->state;
+	enum load_state *prevstate = &load_state->prevstate;
+	enum load_state *prevtoken = &load_state->prevtoken;
+	int *label_len = &load_state->label_len;
+	char *subjectstr = load_state->subject;
+	char *objectstr = load_state->object;
+	ssize_t rc = -EINVAL;
 	char *data = NULL;
-	char subjectstr[SMK_LABELLEN];
-	char objectstr[SMK_LABELLEN];
-	char modestr[8];
-	char *cp;
-
+	int i;
 
 	if (!capable(CAP_MAC_OVERRIDE))
 		return -EPERM;
@@ -208,7 +287,7 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
 	 * 80 characters per line ought to be enough.
 	 */
 	if (count > SMACK_LIST_MAX * 80)
-		return -ENOMEM;
+		return -EFBIG;
 
 	data = kzalloc(count + 1, GFP_KERNEL);
 	if (data == NULL)
@@ -221,30 +300,94 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
 
 	data[count] = '\0';
 
-	for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) {
-		if (*++cp == '\0')
+	for (i = 0; i < count && data[i]; i++) {
+		if (!isgraph(data[i]) && !isspace(data[i]))
+			goto out;
+
+		if (isblank(data[i])) {
+			*state = blank;
+			/* A token-blank trasition */
+			if (*prevstate != blank)
+				*prevtoken = *prevstate;
+		} else {
+			if (data[i] == '\n')
+				*state = newline;
+			/* A blank-token transition */
+			else if (*prevstate == blank)
+				*state = *prevtoken + 1;
+			else
+				*state = *prevstate;
+		}
+
+		switch (*state) {
+		case bol:
+		case subject:
+			if (*label_len >= SMK_MAXLEN)
+				goto out;
+			subjectstr[(*label_len)++] = data[i];
+			*prevstate = subject;
 			break;
-		if (sscanf(cp, "%23s %23s %7s\n", subjectstr, objectstr,
-			   modestr) != 3)
+
+		case object:
+			if (*prevstate == blank) {
+				subjectstr[*label_len] = '\0';
+				*label_len = 0;
+			}
+
+			if (*label_len >= SMK_MAXLEN)
+				goto out;
+			objectstr[(*label_len)++] = data[i];
+			*prevstate = object;
+			break;
+
+		case access:
+			if (*prevstate == blank) {
+				objectstr[*label_len] = '\0';
+				*label_len = 0;
+			}
+
+			if (data[i] == 'R' || data[i] == 'r')
+				rule->smk_access |= MAY_READ;
+			else if (data[i] == 'W' || data[i] == 'w')
+				rule->smk_access |= MAY_WRITE;
+			else if (data[i] == 'X' || data[i] == 'x')
+				rule->smk_access |= MAY_EXEC;
+			else if (data[i] == 'A' || data[i] == 'a')
+				rule->smk_access |= MAY_APPEND;
+			else if (data[i] == '-')
+				/* No-Op, '-' is a placeholder */;
+			else
+				goto out;
+
+			*prevstate = *prevtoken = access;
 			break;
-		rule.smk_subject = smk_import(subjectstr, 0);
-		if (rule.smk_subject == NULL)
+
+		case newline:
+			if (*prevtoken != access || data[i] != '\n')
+				goto out;
+
+			rule->smk_subject = smk_import(subjectstr, 0);
+			if (rule->smk_subject == NULL)
+				goto out;
+
+			rule->smk_object = smk_import(objectstr, 0);
+			if (rule->smk_object == NULL)
+				goto out;
+
+			smk_set_access(rule);
+
+			/* Reset everything, a new rule will come */
+			memset(load_state, 0, sizeof(*load_state));
 			break;
-		rule.smk_object = smk_import(objectstr, 0);
-		if (rule.smk_object == NULL)
+
+		case blank:
+			*prevstate = blank;
 			break;
-		rule.smk_access = 0;
-		if (strpbrk(modestr, "rR") != NULL)
-			rule.smk_access |= MAY_READ;
-		if (strpbrk(modestr, "wW") != NULL)
-			rule.smk_access |= MAY_WRITE;
-		if (strpbrk(modestr, "xX") != NULL)
-			rule.smk_access |= MAY_EXEC;
-		if (strpbrk(modestr, "aA") != NULL)
-			rule.smk_access |= MAY_APPEND;
-		smk_set_access(&rule);
+		}
 	}
 
+	rc = count;
+out:
 	kfree(data);
 	return rc;
 }
@@ -254,7 +397,7 @@ static const struct file_operations smk_load_ops = {
 	.read		= seq_read,
 	.llseek         = seq_lseek,
 	.write		= smk_write_load,
-	.release        = seq_release
+	.release        = smk_release_load,
 };
 
 /**
@@ -924,6 +1067,7 @@ static int __init init_smk_fs(void)
 		}
 	}
 
+	sema_init(&smack_write_sem, 1);
 	smk_cipso_doi();
 
 	return err;

--
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 69%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
    2007-11-04 13:23 99%     ` Ahmed S. Darwish
@ 2007-11-05  9:41 99%     ` Ahmed S. Darwish
    1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-11-05  9:41 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Casey Schaufler, akpm, torvalds, linux-security-module,
	linux-kernel, Al Viro

On Sun, Nov 04, 2007 at 12:28:48PM +0000, Pavel Machek wrote:
> Hi!
> 
> > > Still to come:
> > > 
> > >   - Final cleanup of smack_load_write and smack_cipso_write.
> > 
> > Hi All,
> > 
> > After agreeing with Casey on the "load" input grammar yesterday, here's
> > the final grammar and its parser (which needs more testing):
> > 
> > A Smack Rule in an "egrep" format is:
> > 
> > "^[:space:]*Subject[:space:]+Object[:space:]+[rwxaRWXA-]+[:space:]*\n"
> > 
> > where Subject/Object strings are in the form:
> > 
> > "^[^/[:space:][:cntrl:]]{1,SMK_MAXLEN}$"
> 
> Can we avoid string parsers in the kernel?
> 

Ok, Could someone suggest a better idea please ?. 

I thought about packing the rules in a structure and sending
it over an ioctl() command. Is this applicable ?

> 
> > +static inline int isblank(char c)
> > +{
> > +	return (c == ' ' || c == '\t');
> > +}
> 
> This sounds like enough for 'NAK'.
> 
> 						Pavel,
> 		who still thinks smack rules should be parsed
> 		in userspace and compiled into selinux rules...
> 		
> -- 
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
  @ 2007-11-05 23:38 99%         ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-05 23:38 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Pavel Machek, Casey Schaufler, akpm, linux-security-module,
	linux-kernel, Al Viro

On 11/5/07, Linus Torvalds <torvalds@linux-foundation.org> wrote:
>
>
> On Mon, 5 Nov 2007, Ahmed S. Darwish wrote:
>
> > On Sun, Nov 04, 2007 at 12:28:48PM +0000, Pavel Machek wrote:
> > >
> > > Can we avoid string parsers in the kernel?
> > >
> >
> > Ok, Could someone suggest a better idea please ?.
>
> I personally think string parsers are *much* better than the alternatives
> (which basically boil down to nasty binary interfaces)
>
> > I thought about packing the rules in a structure and sending
> > it over an ioctl() command. Is this applicable ?
>
> That's *MUCH* worse.
>
> Strings are nice. They aren't that complex, and as long as it's not a
> performance-critical area, there are basically no downsides.
>
> Binary structures and ioctl's are *much* worse. They are totally
> undebuggable with generic tools (think "echo" or "strace"), and they are a
> total nightmare to parse across architectures and pointer sizes.
>
> So the rule should be: always use strings if at all possible and relevant.
> If the data is fundamentally binary, it shouldn't be re-coded to ascii (no
> real advantage), but if the data is "stringish", and there aren't big
> performance issues, then keep it as strings.
>

Thanks a lot for such a kind advice. I'll keep that in my mind.

Regards,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
  @ 2007-11-06 11:34 99%         ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-11-06 11:34 UTC (permalink / raw)
  To: Adrian Bunk
  Cc: Kyle Moffett, Casey Schaufler, akpm, torvalds,
	linux-security-module, linux-kernel

Hi,

On Tue, Nov 06, 2007 at 09:56:51AM +0100, Adrian Bunk wrote:
> On Tue, Nov 06, 2007 at 03:26:12AM -0500, Kyle Moffett wrote:
> > On Nov 06, 2007, at 01:33:05, Adrian Bunk wrote:
> >> Can you limit this to 7bit ASCII and use isascii() somewhere?
> >>
> >> Otherwise I'd expect funny things to happen when you e.g. use isspace() on 
> >> the UTF-8 encoded character ??.
> >
> > Actually, you don't need to.  You tell them it expects UTF-8 encoded 
> > strings and be done with it.  All US-ASCII characters from 0 through 127 
> > (IE: high bit clear) are exactly the same in UTF-8, and UTF-8 special 
> > characters have the high bit set in all bytes.  Therefore you just assume 
> > that anything with the high bit set is part of a word and you can handle 
> > basic UTF-8.  (It doesn't work on special UTF-8 space characters like 
> > nonbreaking space and similar, but handling those is significantly more 
> > complicated).
> 
> The documentations says:
> "Smack labels cannot contain unprintable characters or the "/" (slash) 
>  character."
> 
> What you propose might contain unprintable characters, and it might even 
> be invalid UTF-8.
> 

As far as I understand the problem now, isspace() accepts the 0xa0
character which might collide with some of UTF-8 encoded characters
cause the high bit is set.

I used "if (!isspace(c) && !isgraph(c)) return -EINVAL;" to test 
rules' characters validity which seems not enough. I'll add !isascii(c)
in the condition and ask Casey to change the documentation to be
something like:

Smack labels are represented in ASCII characters, they cannot contain
unprintable characters or the '/' (slash) character.

and in write():
if (!isascii(c) return -EINVAL;
if (!isspace(c) && !isgraph(c)) return -EINVAL;

This satisfy above customized labels rule, right ?

Regards,

--
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
  @ 2007-11-06 12:23 99%             ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-11-06 12:23 UTC (permalink / raw)
  To: Adrian Bunk
  Cc: Kyle Moffett, Casey Schaufler, akpm, torvalds,
	linux-security-module, linux-kernel

On 11/6/07, Adrian Bunk <bunk@kernel.org> wrote:
> On Tue, Nov 06, 2007 at 01:34:05PM +0200, Ahmed S. Darwish wrote:
> > Hi,
> >
> > On Tue, Nov 06, 2007 at 09:56:51AM +0100, Adrian Bunk wrote:
> > > On Tue, Nov 06, 2007 at 03:26:12AM -0500, Kyle Moffett wrote:
> > > > On Nov 06, 2007, at 01:33:05, Adrian Bunk wrote:
> > > >> Can you limit this to 7bit ASCII and use isascii() somewhere?
> > > >>
> > > >> Otherwise I'd expect funny things to happen when you e.g. use isspace() on
> > > >> the UTF-8 encoded character ??.
> > > >
> > > > Actually, you don't need to.  You tell them it expects UTF-8 encoded
> > > > strings and be done with it.  All US-ASCII characters from 0 through 127
> > > > (IE: high bit clear) are exactly the same in UTF-8, and UTF-8 special
> > > > characters have the high bit set in all bytes.  Therefore you just assume
> > > > that anything with the high bit set is part of a word and you can handle
> > > > basic UTF-8.  (It doesn't work on special UTF-8 space characters like
> > > > nonbreaking space and similar, but handling those is significantly more
> > > > complicated).
> > >
> > > The documentations says:
> > > "Smack labels cannot contain unprintable characters or the "/" (slash)
> > >  character."
> > >
> > > What you propose might contain unprintable characters, and it might even
> > > be invalid UTF-8.
> >
> > As far as I understand the problem now, isspace() accepts the 0xa0
> > character which might collide with some of UTF-8 encoded characters
> > cause the high bit is set.
> >
> > I used "if (!isspace(c) && !isgraph(c)) return -EINVAL;" to test
> > rules' characters validity which seems not enough. I'll add !isascii(c)
> > in the condition and ask Casey to change the documentation to be
> > something like:
> >
> > Smack labels are represented in ASCII characters, they cannot contain
> > unprintable characters or the '/' (slash) character.
> >
> > and in write():
> > if (!isascii(c) return -EINVAL;
> > if (!isspace(c) && !isgraph(c)) return -EINVAL;
> >
> > This satisfy above customized labels rule, right ?
>
> It should work for all charsets you'll usually have to handle.
>

I admit I'm not experienced in such encoding stuff, but shouldn't the
ASCII and the ASCII-compatible UTF-8 encodings be enough for the
labels ?

> It would not work if someone would e.g. give you UTF-16 encoded strings,
> but I don't see this happening in practice.

Won't this complicate the code too much ?

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
  @ 2007-11-06 14:05 99%                   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2007-11-06 14:05 UTC (permalink / raw)
  To: Adrian Bunk
  Cc: Kyle Moffett, Casey Schaufler, akpm, torvalds,
	linux-security-module, linux-kernel

On Tue, Nov 06, 2007 at 02:34:46PM +0100, Adrian Bunk wrote:
> On Tue, Nov 06, 2007 at 07:49:26AM -0500, Kyle Moffett wrote:
> > On Nov 06, 2007, at 07:23:36, Ahmed S. Darwish wrote:
> >> On 11/6/07, Adrian Bunk <bunk@kernel.org> wrote:
> >>> On Tue, Nov 06, 2007 at 01:34:05PM +0200, Ahmed S. Darwish wrote:
> >>>> As far as I understand the problem now, isspace() accepts the 0xa0 
> >>>> character which might collide with some of UTF-8 encoded characters 
> >>>> cause the high bit is set.
> >>
> >> I admit I'm not experienced in such encoding stuff, but shouldn't the 
> >> ASCII and the ASCII-compatible UTF-8 encodings be enough for the labels?
> >>
> >>> It would not work if someone would e.g. give you UTF-16 encoded strings, 
> >>> but I don't see this happening in practice.
> >>
> >> Won't this complicate the code too much ?
> >
> > Well the VFS (for example) certainly doesn't support any encodings other 
> > than various extended-ASCII forms (which includes UTF-8).  Something like 
> > UTF-16 has extra null characters in-between every normal character, and as 
> > such would fail completely if passed to the VFS.
> 
> Good point.
> 
> > Personally I think that isspace() accepting character 0xA0 is a bug, as 
> > there are several variants of extended ASCII only one of which has that 
> > character as a space.  Others have it as ?? (accented A), etc.
> 
> But even then Smack would still have a similar problem with isgraph().
> 

Great, To summarize the discussion. Will there be a problem in 
accepting ASCII and the UTF-8 ASCII _subset_ _only_ and  return 
-EINVAL for all other cases/ecnodings ?.

i.e. The fragment I sent in a previous message:

/* Filter UTF-8 non-ascii compatible bytes (> 0x7F) */
if (!isascii(c)) return -EINVAL; 
/* Filter unwanted ascii chars */
if (!isspace(c) && !isgraph(c)) return -EINVAL; 

> > In addition 
> > the "canonical" internal text format of the kernel is UTF-8 as that 
> > encoding can represent any character in any other encoding and it is 
> > backwards-compatible with traditional ASCII.
> > 
> > Cheers,
> > Kyle Moffett-
> 
> cu
> Adrian
> 

--
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser
  @ 2007-11-06 14:30 99%                       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-06 14:30 UTC (permalink / raw)
  To: Adrian Bunk
  Cc: Kyle Moffett, Casey Schaufler, akpm, torvalds,
	linux-security-module, linux-kernel

On 11/6/07, Adrian Bunk <bunk@kernel.org> wrote:
> On Tue, Nov 06, 2007 at 04:05:13PM +0200, Ahmed S. Darwish wrote:
> >
> > Great, To summarize the discussion. Will there be a problem in
> > accepting ASCII and the UTF-8 ASCII _subset_ _only_ and  return
> > -EINVAL for all other cases/ecnodings ?.
>
> The UTF-8 ASCII subset is the complete ASCII.
>
> > i.e. The fragment I sent in a previous message:
> >
> > /* Filter UTF-8 non-ascii compatible bytes (> 0x7F) */
> > if (!isascii(c)) return -EINVAL;
> > /* Filter unwanted ascii chars */
> > if (!isspace(c) && !isgraph(c)) return -EINVAL;
> >...
>
> As I already said, this should work fine.
>

I thought you were objecting not handling the remaining non-ASCII
UTF-8 bytes. Everything is clear now. A Big thank you to everybody in
this thread for your effort on this :).

Regards,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser(2)
  @ 2007-11-10 19:45 99%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-10 19:45 UTC (permalink / raw)
  To: Jakob Oestergaard
  Cc: Casey Schaufler, akpm, torvalds, linux-security-module,
	linux-kernel, Al Viro

On Nov 10, 2007 7:05 PM, Jakob Oestergaard <jakob@unthought.net> wrote:
> ...
> > I've double-checked the code for any possible off-by-one/overflow
> > errors.
> ...
>
> Two things caught my eye.
>
> ...
> > +             case bol:
> > +             case subject:
> > +                     if (*label_len >= SMK_MAXLEN)
> > +                             goto out;
> > +                     subjectstr[(*label_len)++] = data[i];
>
> Why is the '>' necessary?  Could it happen that you had incremented past the
> point of equality?
>
> If that could not happen, then in my oppinion '>=' is very misleading when '=='
> is really what is needed.
>

Indeed, you're absolutely right.

> ...
> > +             case object:
> > +                     if (*prevstate == blank) {
> > +                             subjectstr[*label_len] = '\0';
> > +                             *label_len = 0;
> > +                     }
>
> I wonder why it is valid to uncritically use the already incremented label_len
> here, without checking its value (like is done above).
>
> It seems strangely asymmetrical. I'm not saying it's wrong, because there may
> be a subtle reason as to why it's not, but if that's the case then I think that
> subtle reason should be documented with a comment.
>

Maximum value label_len could reach is "SMK_MAXLEN". The subjectstr
and objectstr arrays are of "SMK_MAXLEN + 1" length. So I think no
danger is here.

Yes, this deserved a comment.

> ...
> > +             case access:
> > +                     if (*prevstate == blank) {
> > +                             objectstr[*label_len] = '\0';
> > +                             *label_len = 0;
> > +                     }
>
> Same applies here.
>
>  / jakob
>

Good spots, thanks a lot for the review.

Regards,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Smackv10: Smack rules grammar + their stateful parser(2)
  @ 2007-11-11 18:37 99%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2007-11-11 18:37 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Casey Schaufler, akpm, torvalds, linux-security-module,
	linux-kernel, Al Viro

Hi Pavel,

On Nov 11, 2007 2:44 PM, Pavel Machek <pavel@ucw.cz> wrote:
> Hi!
>
> > > A Smack Rule in an "egrep" format is:
> > >
> > > "^[:space:]*Subject[:space:]+Object[:space:]+[rwxaRWXA-]+[:space:]*\n"
>
> Perhaps you should make it space, not 'space or tab', and only allow
> lowercase permissions? That way, parser will be slightly simpler, and
> you'll still have a chance to use 'R' as 'slightly different r'.
>

Thanks for your care about this. It seems not a lot of people have
noticed, but to stop any objections not related to the core smack
code, Casey decided to let the parsing be done in a user-space utility
that sends the rules to the kernel in a predefined strict format.

You can find how the whole story in the smackv11 announcement here:
http://article.gmane.org/gmane.linux.kernel.lsm/4463

Regards,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [Lguest/x86]: Clash with ioremap_nocache() + _PAGE_PWT
@ 2008-02-06 23:21 98% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-06 23:21 UTC (permalink / raw)
  To: Rusty Russel, Suresh Siddha, Ingo Molnar, Thomas Gleixner
  Cc: lguest, linux-kernel

Hi all,

Beginning from commit 4138cc3418f5, ioremap_nocache() sets the _PAGE_PWT
flag. 

Lguest doesn't accept a guest pte with a _PWT flag and reports a
"bad page table entry" in that case. 

I've removed check from lguest code and everything worked fine. 
Is this safe from the Lguest side ?

Mentioned commit [*]:

commit 4138cc3418f5eaa7524ff8e927102863f1ba0ea5
Author: Siddha, Suresh B <suresh.b.siddha@intel.com>
Date:   Wed Jan 30 13:33:43 2008 +0100

    x86: set strong uncacheable where UC is really desired
    
    Also use _PAGE_PWT for all the mappings which need uncache mapping.
    Instead of existing PAT2 which is UC- (and can be overwritten by MTRRs),
    we now use PAT3 which is strong uncacheable.
    
    This makes it consistent with pgprot_noncached()

diff --git a/arch/x86/mm/ioremap_32.c b/arch/x86/mm/ioremap_32.c
index 0b27831..ef0f6a4 100644
--- a/arch/x86/mm/ioremap_32.c
+++ b/arch/x86/mm/ioremap_32.c
@@ -119,7 +119,7 @@ EXPORT_SYMBOL(__ioremap);
 void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
 {
 	unsigned long last_addr;
-	void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);
+	void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD | _PAGE_PWT);
 	if (!p) 
 		return p; 

Thanks,

[*]: latest pull calls set_memory_uc() which also sets the _PWT flag.

--
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 98%]

* [PATCH] lguest: Accept guest _PAGE_PWT page table entries
  @ 2008-02-07  0:51 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-07  0:51 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Rusty Russel, Suresh Siddha, Thomas Gleixner, lguest, linux-kernel

On Thu, Feb 07, 2008 at 12:59:23AM +0100, Ingo Molnar wrote:
> 
> * Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> 
> > Hi all,
> > 
> > Beginning from commit 4138cc3418f5, ioremap_nocache() sets the _PAGE_PWT
> > flag. 
> > 
> > Lguest doesn't accept a guest pte with a _PWT flag and reports a "bad 
> > page table entry" in that case.
> > 
> > I've removed check from lguest code and everything worked fine. Is 
> > this safe from the Lguest side ?
> 
> yes, should be safe. Could you send a patch so that others can apply it 
> too?
> 

Ofcourse :) :

Accept guest _PAGE_PWT page table entries, otherwise lguest will
always fail with a "bad page table entry" message.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index 74b4cf2..952160b 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -178,8 +178,8 @@ static void release_pte(pte_t pte)
 
 static void check_gpte(struct lg_cpu *cpu, pte_t gpte)
 {
-	if ((pte_flags(gpte) & (_PAGE_PWT|_PAGE_PSE))
-	    || pte_pfn(gpte) >= cpu->lg->pfn_limit)
+	if ((pte_flags(gpte) & _PAGE_PSE) || 
+	    pte_pfn(gpte) >= cpu->lg->pfn_limit)
 		kill_guest(cpu, "bad page table entry");
 }
 

Regards,

--
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH - BUGFIX] Smack: Check for 'struct socket' with NULL sk
  @ 2008-02-11 23:23 96% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-11 23:23 UTC (permalink / raw)
  To: Joerg Platte; +Cc: linux-kernel, casey

On Mon, Feb 11, 2008 at 07:26:02PM +0100, Joerg Platte wrote:
> Hi,
> 
> when booting linux 2.6.25-rc1 I get the following error:
> 
> BUG: unable to handle kernel NULL pointer dereference at 00000138
> IP: [<c01aa59e>] smack_netlabel+0x13/0xc8
> *pde = 00000000
> Oops: 0000 [#1] PREEMPT
> Modules linked in: nfsd 
[...]
> Call Trace:
>  [<c01aacf8>] ? new_inode_smack+0x39/0x3f
>  [<c01aad52>] ? smack_inode_alloc_security+0x16/0x27
>  [<c01a7510>] ? security_inode_alloc+0x19/0x1b
>  [<c01aa665>] ? smack_socket_post_create+0x12/0x18
>  [<c01a7a06>] ? security_socket_post_create+0x16/0x1b
>  [<c02116ce>] ? sock_create_lite+0x44/0x64
>  [<c0211712>] ? kernel_accept+0x24/0x5f

Hi Joerg,

There's a small problem with smack and NFS. A similar report was also
sent here: http://lkml.org/lkml/2007/10/27/85

Could you please check below patch ? I think it should fix your problem.

I've also added similar checks in inode_{get/set}security(). Cheating
from SELinux post_create_socket(), it does the same. Casey, Thoughts ?

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1c11e42..eb04278 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -701,7 +701,7 @@ static int smack_inode_getsecurity(const struct inode *inode,
 		return -EOPNOTSUPP;
 
 	sock = SOCKET_I(ip);
-	if (sock == NULL)
+	if (sock == NULL || sock->sk == NULL)
 		return -EOPNOTSUPP;
 
 	ssp = sock->sk->sk_security;
@@ -1280,10 +1280,12 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
  */
 static int smack_netlabel(struct sock *sk)
 {
-	struct socket_smack *ssp = sk->sk_security;
+	struct socket_smack *ssp;
 	struct netlbl_lsm_secattr secattr;
 	int rc = 0;
 
+	BUG_ON(sk == NULL);
+	ssp = sk->sk_security;
 	netlbl_secattr_init(&secattr);
 	smack_to_secattr(ssp->smk_out, &secattr);
 	if (secattr.flags != NETLBL_SECATTR_NONE)
@@ -1331,7 +1333,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
 		return -EOPNOTSUPP;
 
 	sock = SOCKET_I(inode);
-	if (sock == NULL)
+	if (sock == NULL || sock->sk == NULL)
 		return -EOPNOTSUPP;
 
 	ssp = sock->sk->sk_security;
@@ -1362,7 +1364,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
 static int smack_socket_post_create(struct socket *sock, int family,
 				    int type, int protocol, int kern)
 {
-	if (family != PF_INET)
+	if (family != PF_INET || sock->sk == NULL)
 		return 0;
 	/*
 	 * Set the outbound netlbl.

^ permalink raw reply	[relevance 96%]

* [PATCH BUGFIX 25-rc1] Smack: Don't fail against Nulled sk sockets
@ 2008-02-13  1:25 96% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-13  1:25 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds; +Cc: Casey Schaufler, Joerg Platte, LKML, Netdev

Hi!,

Appropriately handle sockets with sk = NULL. This is usually the socket
case when starting kernel nfsd.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Acked-by: Casey Schaufler <casey@schuafler-ca.com>
Tested-by: Joerg Platte <jplatte@naasa.net>
--

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1c11e42..eb04278 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -701,7 +701,7 @@ static int smack_inode_getsecurity(const struct inode *inode,
 		return -EOPNOTSUPP;
 
 	sock = SOCKET_I(ip);
-	if (sock == NULL)
+	if (sock == NULL || sock->sk == NULL)
 		return -EOPNOTSUPP;
 
 	ssp = sock->sk->sk_security;
@@ -1280,10 +1280,12 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
  */
 static int smack_netlabel(struct sock *sk)
 {
-	struct socket_smack *ssp = sk->sk_security;
+	struct socket_smack *ssp;
 	struct netlbl_lsm_secattr secattr;
 	int rc = 0;
 
+	BUG_ON(sk == NULL);
+	ssp = sk->sk_security;
 	netlbl_secattr_init(&secattr);
 	smack_to_secattr(ssp->smk_out, &secattr);
 	if (secattr.flags != NETLBL_SECATTR_NONE)
@@ -1331,7 +1333,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
 		return -EOPNOTSUPP;
 
 	sock = SOCKET_I(inode);
-	if (sock == NULL)
+	if (sock == NULL || sock->sk == NULL)
 		return -EOPNOTSUPP;
 
 	ssp = sock->sk->sk_security;
@@ -1362,7 +1364,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
 static int smack_socket_post_create(struct socket *sock, int family,
 				    int type, int protocol, int kern)
 {
-	if (family != PF_INET)
+	if (family != PF_INET || sock->sk == NULL)
 		return 0;
 	/*
 	 * Set the outbound netlbl.


Warm regards

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 96%]

* Linux i386 clone(): %ebx 'frobbing' ?
@ 2008-02-15 18:42 98% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-15 18:42 UTC (permalink / raw)
  To: libc-alpha, libc-alpha; +Cc: linux-kernel

Hi all,

In the clone(int (*fn)(void *arg), void *child_stack, ..., void *arg, ...)
Glibc library function defind in sysdeps/unix/sysv/linux/i386/:

`fn' is saved in 8(child_stack), and `arg' is stored in 12(child_stack):

	movl	STACK(%esp),%ecx
	movl	ARG(%esp),%eax		/* no negative argument counts */
	movl	%eax,12(%ecx)		<---

	/* Save the function pointer as the zeroth argument.
	   It will be popped off in the child in the ebx frobbing below.  */
	movl	FUNC(%esp),%eax
	movl	%eax,8(%ecx)		<---

But after the exectuion of `sys_clone' system call, `fn' is 
called in the child thread by the statement 'call *%ebx' as follows:

	int	$0x80
	[...]

	test	%eax,%eax
	jz	L(thread_start)

/* Parent */
L(pseudo_end):
	ret

/* Child */
L(thread_start):
	/* Note: %esi is zero.  */
	movl	%esi,%ebp	/* terminate the stack frame */
	call	*%ebx

I don't understand how the `fn' argument reached the child thread
in the %ebx register. It's said in the comment that `fn' will be
popped to child 'in the ebx frobbing below'. But what does that mean ?

Thanks in advance

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 98%]

* Re: Linux i386 clone(): %ebx 'frobbing' ?
  @ 2008-02-15 23:07 99%   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-15 23:07 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-alpha, libc-alpha, linux-kernel

Hi Andreas,

On Fri, Feb 15, 2008, Andreas Schwab wrote:
> "Ahmed S. Darwish" <darwish.07@gmail.com> writes:
> 
> > I don't understand how the `fn' argument reached the child thread
> > in the %ebx register. It's said in the comment that `fn' will be
> > popped to child 'in the ebx frobbing below'. But what does that mean ?
> 
> See "popl %ebx" after "int $0x80".
> 

I hope I'm not misreading something obvious, but I can't find
the code where FUNC(%esp) is stored in %ebx before %ebx value
got pushed in the stack (and restored in above 'popl' statement).

Thanks a lot for help.

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: Linux i386 clone(): %ebx 'frobbing' ?
  @ 2008-02-15 23:54 99%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-15 23:54 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-alpha, libc-alpha, linux-kernel

On Sat, Feb 16, 2008 at 12:28:11AM +0100, Andreas Schwab wrote:
> "Ahmed S. Darwish" <darwish.07@gmail.com> writes:
> 
> > Hi Andreas,
> >
> > On Fri, Feb 15, 2008, Andreas Schwab wrote:
> >> "Ahmed S. Darwish" <darwish.07@gmail.com> writes:
> >> 
> >> > I don't understand how the `fn' argument reached the child thread
> >> > in the %ebx register. It's said in the comment that `fn' will be
> >> > popped to child 'in the ebx frobbing below'. But what does that mean ?
> >> 
> >> See "popl %ebx" after "int $0x80".
> >> 
> >
> > I hope I'm not misreading something obvious, but I can't find
> > the code where FUNC(%esp) is stored in %ebx before %ebx value
> > got pushed in the stack (and restored in above 'popl' statement).
> 
> It is stored in the new stack for the child, as explained in the
> comment.  The parent has a different stack.
> 

Ooh great, I got it. Sorry, my mind didn't connect the dots though 
I read the comment several times. Thanks a lot for bearing with me :).

Regards,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [PATCH x86] i8259A_32: Remove redundant irq_desc[NR_IRQ] initialization
@ 2008-02-17 22:59 98% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-17 22:59 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin; +Cc: LKML

Hi all,

Remove redundant irq_desc[NR_IRQS] element initialization in 
init_ISA_irqs(). irq_desc[NR_IRQS] is already statically 
initialized with the same values in kernel/irq/handle.c .

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 i8259_32.c |   26 ++++++--------------------
 1 file changed, 6 insertions(+), 20 deletions(-)

Tested only on a UP machine with an i8259A PIC.

diff --git a/arch/x86/kernel/i8259_32.c b/arch/x86/kernel/i8259_32.c
index 2d25b77..0fea87d 100644
--- a/arch/x86/kernel/i8259_32.c
+++ b/arch/x86/kernel/i8259_32.c
@@ -26,8 +26,6 @@
  * present in the majority of PC/AT boxes.
  * plus some generic x86 specific things if generic specifics makes
  * any sense at all.
- * this file should become arch/i386/kernel/irq.c when the old irq.c
- * moves to arch independent land
  */
 
 static int i8259A_auto_eoi;
@@ -362,24 +360,12 @@ void __init init_ISA_irqs (void)
 #endif
 	init_8259A(0);
 
-	for (i = 0; i < NR_IRQS; i++) {
-		irq_desc[i].status = IRQ_DISABLED;
-		irq_desc[i].action = NULL;
-		irq_desc[i].depth = 1;
-
-		if (i < 16) {
-			/*
-			 * 16 old-style INTA-cycle interrupts:
-			 */
-			set_irq_chip_and_handler_name(i, &i8259A_chip,
-						      handle_level_irq, "XT");
-		} else {
-			/*
-			 * 'high' PCI IRQs filled in on demand
-			 */
-			irq_desc[i].chip = &no_irq_chip;
-		}
-	}
+	/*
+	 * 16 old-style INTA-cycle interrupts:
+	 */
+	for (i = 0; i < 16; i++)
+		set_irq_chip_and_handler_name(i, &i8259A_chip,
+					      handle_level_irq, "XT");
 }
 
 /* Overridden in paravirt.c */

Regards,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 98%]

* [PATCH] Tasklets: Avoid duplicating __tasklet_{,hi_}schedule() code
@ 2008-02-19 15:37 99% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-19 15:37 UTC (permalink / raw)
  To: Andrew Morton, Ingo Molnar; +Cc: LKML

Hi all,

Avoid duplicating __tasklet_schedule() and __tasklet_hi_schedule()
code in tasklet_action() and tasklet_hi_action() respectively.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

This also saves a few bytes of image space:

   text	   data	    bss	    dec	    hex	filename
   3632	     12	    324	   3968	    f80	softirq.o.before
   3552	     12	    324	   3888	    f30	softirq.o.after

diff --git a/kernel/softirq.c b/kernel/softirq.c
index 5b3aea5..3068dc3 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -414,11 +414,8 @@ static void tasklet_action(struct softirq_action *a)
 			tasklet_unlock(t);
 		}
 
-		local_irq_disable();
-		t->next = __get_cpu_var(tasklet_vec).list;
-		__get_cpu_var(tasklet_vec).list = t;
-		__raise_softirq_irqoff(TASKLET_SOFTIRQ);
-		local_irq_enable();
+		/* We were not lucky enough to run, reschedule. */
+		__tasklet_schedule(t);
 	}
 }
 
@@ -447,11 +444,8 @@ static void tasklet_hi_action(struct softirq_action *a)
 			tasklet_unlock(t);
 		}
 
-		local_irq_disable();
-		t->next = __get_cpu_var(tasklet_hi_vec).list;
-		__get_cpu_var(tasklet_hi_vec).list = t;
-		__raise_softirq_irqoff(HI_SOFTIRQ);
-		local_irq_enable();
+		/* We were not lucky enough to run, reschedule. */
+		__tasklet_hi_schedule(t);
 	}
 }
 

Regards,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Tasklets: Avoid duplicating __tasklet_{,hi_}schedule() code
  @ 2008-02-19 16:27 99%   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-19 16:27 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Andrew Morton, Ingo Molnar, LKML

On Tue, Feb 19, 2008 at 04:52:52PM +0100, Ingo Molnar wrote:
> 
> * Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> 
> > -		local_irq_disable();
> > -		t->next = __get_cpu_var(tasklet_vec).list;
> > -		__get_cpu_var(tasklet_vec).list = t;
> > -		__raise_softirq_irqoff(TASKLET_SOFTIRQ);
> > -		local_irq_enable();
> > +		/* We were not lucky enough to run, reschedule. */
> > +		__tasklet_schedule(t);
> 
> i think there's a subtle difference that you missed: this one does 
> __raise_softirq_irqoff(), while __tasklet_schedule() does a 
> raise_softirq_irqoff(). (note the lack of undescores)
> 
> the reason is to avoid infinitely self-activating tasklets.
> 

Indeed, thanks a lot for the explanation. (maybe it's time to check
for new eyeglasses ;)).

Regards

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Tasklets: Avoid duplicating __tasklet_{,hi_}schedule() code
  @ 2008-02-20 13:37 99%       ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-20 13:37 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Andrew Morton, Ingo Molnar, LKML

On Wed, Feb 20, 2008 at 11:41:13AM +0100, Ingo Molnar wrote:
> 
> * Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> 
> > > > -		local_irq_disable();
> > > > -		t->next = __get_cpu_var(tasklet_vec).list;
> > > > -		__get_cpu_var(tasklet_vec).list = t;
> > > > -		__raise_softirq_irqoff(TASKLET_SOFTIRQ);
> > > > -		local_irq_enable();
> > > > +		/* We were not lucky enough to run, reschedule. */
> > > > +		__tasklet_schedule(t);
> > > 
> > > i think there's a subtle difference that you missed: this one does 
> > > __raise_softirq_irqoff(), while __tasklet_schedule() does a 
> > > raise_softirq_irqoff(). (note the lack of undescores)
> > > 
> > > the reason is to avoid infinitely self-activating tasklets.
> > 
> > Indeed, thanks a lot for the explanation. (maybe it's time to check 
> > for new eyeglasses ;)).
> 
> nah, it's rather subtle and the code looked good to me at first but i 
> remembered that there was some small detail here to watch out for.
> 
> i really dont like tasklets due to their many, arbitrary scheduling 
> limitations, we should really use the "turn tasklets into kthreads" 
> patch i posted last year.
> 

While we are at it, there's a small question that is bothering me
for a while (and I'm really thankful for help). 

I keep reading that softirqs (and naturally, tasklets) got executed 
in interrupt context at the return from hardirq code path.

Checking entry_32.S, I find no mentioning of softirqs on the return
path (beginning from ret_from_intr: to restore_all: )

The only invocation I'm able to find is from local_bh_enable() and
from ksoftirqd/n threads (by calling do_softirq()). AFAIK, both 
invocations occur in a _nont-interrupt_ context (exception context).

So, where does the interrupt-context tasklets invocation really 
occur ?

Thanks

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Tasklets: Avoid duplicating __tasklet_{,hi_}schedule() code
  @ 2008-02-20 19:39 99%           ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-20 19:39 UTC (permalink / raw)
  To: Dmitry Adamushko; +Cc: Ingo Molnar, LKML, Andrew Morton

On Wed, Feb 20, 2008 at 03:20:52PM +0100, Dmitry Adamushko wrote:
> On 20/02/2008, Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> > On Wed, Feb 20, 2008 at 11:41:13AM +0100, Ingo Molnar wrote:
> > >
> > > * Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> > >
> > > > > > -               local_irq_disable();
> > > > > > -               t->next = __get_cpu_var(tasklet_vec).list;
> > > > > > -               __get_cpu_var(tasklet_vec).list = t;
> > > > > > -               __raise_softirq_irqoff(TASKLET_SOFTIRQ);
> > > > > > -               local_irq_enable();
> > > > > > +               /* We were not lucky enough to run, reschedule. */
> > > > > > +               __tasklet_schedule(t);
> > > > >
> > > > > i think there's a subtle difference that you missed: this one does
> > > > > __raise_softirq_irqoff(), while __tasklet_schedule() does a
> > > > > raise_softirq_irqoff(). (note the lack of undescores)
> > > > >
> > > > > the reason is to avoid infinitely self-activating tasklets.
> > > >
> > > > Indeed, thanks a lot for the explanation. (maybe it's time to check
> > > > for new eyeglasses ;)).
> > >
> > > nah, it's rather subtle and the code looked good to me at first but i
> > > remembered that there was some small detail here to watch out for.
> > >
> > > i really dont like tasklets due to their many, arbitrary scheduling
> > > limitations, we should really use the "turn tasklets into kthreads"
> > > patch i posted last year.
> > >
> >
> > While we are at it, there's a small question that is bothering me
> > for a while (and I'm really thankful for help).
> >
> > I keep reading that softirqs (and naturally, tasklets) got executed
> > in interrupt context at the return from hardirq code path.
> >
> > Checking entry_32.S, I find no mentioning of softirqs on the return
> > path (beginning from ret_from_intr: to restore_all: )
> >
> > The only invocation I'm able to find is from local_bh_enable() and
> > from ksoftirqd/n threads (by calling do_softirq()). AFAIK, both
> > invocations occur in a _nont-interrupt_ context (exception context).
> >
> > So, where does the interrupt-context tasklets invocation really
> > occur ?
> 
> Look at irq_exit() in softirq.c.
> 
> The common sequence is ... -> do_IRQ() --> irq_exit() --> invoke_softirq()
> 
> 

Great, this was the last missing block in my understanding of softirqs :).
Thank you.

[btw, your MUA broke the CC list]

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [BUG + PATCH/Bugfix] x86/lguest: fix pgdir pmd index calculation
@ 2008-02-24 15:55 78% Ahmed S. Darwish
      0 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-24 15:55 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Rusty Russell
  Cc: LKML, lguest, akpm

Hi all,

Beginning from commits close to v2.6.25-rc2, running lguest always oopses
the host kernel. Oops is at [1].

Bisection led to the following commit:

commit 37cc8d7f963ba2deec29c9b68716944516a3244f

    x86/early_ioremap: don't assume we're using swapper_pg_dir
    
    At the early stages of boot, before the kernel pagetable has been
    fully initialized, a Xen kernel will still be running off the
    Xen-provided pagetables rather than swapper_pg_dir[].  Therefore,
    readback cr3 to determine the base of the pagetable rather than
    assuming swapper_pg_dir[].
    
 static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
 {
-	pgd_t *pgd = &swapper_pg_dir[pgd_index(addr)];
+	/* Don't assume we're using swapper_pg_dir at this point */
+	pgd_t *base = __va(read_cr3());
+	pgd_t *pgd = &base[pgd_index(addr)];
 	pud_t *pud = pud_offset(pgd, addr);
 	pmd_t *pmd = pmd_offset(pud, addr);
 
Trying to analyze the problem, it seems on the guest side of lguest, 
%cr3 has a different value from &swapper_pg-dir (which
is AFAIK fine on a pravirt guest): 

Putting some debugging messages in early_ioremap_pmd:

/* Appears 3 times */
[    0.000000] ***************************
[    0.000000] __va(%cr3) = c0000000, &swapper_pg_dir = c02cc000
[    0.000000] ***************************

After 8 hours of debugging and staring on lguest code, I noticed something
strange in paravirt_ops->set_pmd hypercall invocation:

static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
{
	*pmdp = pmdval;	
	lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
		   (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
}

The first hcall parameter is global pgdir which looks fine. The second
parameter is the pmd index in the pgdir which is suspectful.

AFAIK, calculating the index of pmd does not need a divisoin over four. 
Removing the division made lguest work fine again . Patch is at [2].

I am not sure why the division over four existed in the first place. It
seems bogus, maybe the Xen patch just made the problem appear ?

[2]: The patch:

[PATCH] lguest: fix pgdir pmd index cacluation

Remove an error in index calculation which leads to removing
a not existing shadow page table (leading to a Null dereference).

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 5afdde4..6636750 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -489,7 +489,7 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
 	*pmdp = pmdval;
 	lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
-		   (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+		   (__pa(pmdp)&(PAGE_SIZE-1)), 0);
 }
 
 /* There are a couple of legacy places where the kernel sets a PTE, but we


[1]: The oops:

[    9.936880] BUG: unable to handle kernel NULL pointer dereference at 00000ff8
[    9.938015] IP: [<c0204ef6>] release_pgd+0x6/0x60
[    9.938379] *pde = 00000000 
[    9.938618] Oops: 0000 [#1] 
[    9.938680] Modules linked in:
[    9.938680] 
[    9.938680] Pid: 173, comm: lguest Not tainted (2.6.25-rc2-dirty #59)
[    9.938680] EIP: 0060:[<c0204ef6>] EFLAGS: 00000202 CPU: 0
[    9.938680] EIP is at release_pgd+0x6/0x60
[    9.938680] EAX: c7cfe000 EBX: c7d06fb8 ECX: 00000000 EDX: 00000ff8
[    9.938680] ESI: c7cfe004 EDI: 00000ff8 EBP: 00000000 ESP: c7cebe5c
[    9.938680]  DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0058
[    9.938680] Process lguest (pid: 173, ti=c7cea000 task=c7c94ac0 task.ti=c7cea000)
[    9.938680] Stack: c7d06fb8 c7cfe004 c7cfe004 00000000 c0204a61 00000000 00000246 00000246 
[    9.938680]        c7cbd528 c10ed500 b5d65000 00000002 c02110f4 076a8067 c0151ccc c7cc8668 
[    9.938680]        01d65000 c7cbd528 00000007 c7cc8668 00000000 b5d65000 c01531b8 00000246 
[    9.938680] Call Trace:
[    9.938680]  [<c0204a61>] do_hcall+0x1a1/0x230
[    9.938680]  [<c02110f4>] _spin_unlock+0x14/0x20
[    9.938680]  [<c0151ccc>] follow_page+0x9c/0x190
[    9.938680]  [<c01531b8>] get_user_pages+0x108/0x2c0
[    9.938680]  [<c01bd9af>] copy_to_user+0x3f/0x70
[    9.938680]  [<c0206ae0>] read+0x0/0xb8
[    9.938680]  [<c0204ba9>] do_hypercalls+0xb9/0x2a0
[    9.938680]  [<c0207b5a>] lguest_arch_run_guest+0xfa/0x1d0
[    9.938680]  [<c0204651>] run_guest+0xc1/0x110
[    9.938680]  [<c0206ae0>] read+0x0/0xb8
[    9.938680]  [<c02045bb>] run_guest+0x2b/0x110
[    9.938680]  [<c01655df>] vfs_read+0x8f/0xc0
[    9.938680]  [<c0165ab6>] sys_pread64+0x76/0x80
[    9.938680]  [<c0103864>] sysenter_past_esp+0x6d/0xc5
[    9.938680]  =======================
[    9.938680] Code: 75 03 5b c3 90 89 d8 e8 39 dc f0 ff 90 8b 1d d8 44 4f c0 c1 e8 0c c1 e0 05 01 d8 5b e9 24 81 f4 ff 8d 74 26 00 55 57 89 d7 56 53 <8b> 02 e8 f3 db f0 ff 90 a8 01 74 3f 8b 07 e8 e7 db f0 ff 90 25 
[    9.938680] EIP: [<c0204ef6>] release_pgd+0x6/0x60 SS:ESP 0058:c7cebe5c
[    9.939759] ---[ end trace 0cda9e589a597173 ]---

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 78%]

* Re: [BUG + PATCH/Bugfix] x86/lguest: fix pgdir pmd index calculation
  @ 2008-02-24 16:26 99%   ` Ahmed S. Darwish
  2008-02-25  0:18 97%     ` Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-24 16:26 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Rusty Russell,
	LKML, lguest, akpm, Jeremy Fitzhardinge

On Sun, Feb 24, 2008 at 05:18:14PM +0100, Ingo Molnar wrote:
> 
> * Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> 
> > I am not sure why the division over four existed in the first place. 
> > It seems bogus, maybe the Xen patch just made the problem appear ?
> 
> i think so - nice detective work and nice fix!
> 

Thanks!. Your turn-around time is super, which is so nice too ;).

> I've picked up your patch into x86.git#testing (until Rusty picks it 
> up), you can track it the following way:
> 
>     http://people.redhat.com/mingo/x86.git/README
> 
> it has other lguest fixes as well - could you double-check that 
> x86.git#testing works fine for you as-is? (i've just updated the git 
> tree so it includes your fix as well)
> 

Ofcourse. I'll send you the results by GMT night.

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [BUG + PATCH/Bugfix] x86/lguest: fix pgdir pmd index calculation
  2008-02-24 16:26 99%   ` Ahmed S. Darwish
@ 2008-02-25  0:18 97%     ` Ahmed S. Darwish
  2008-02-29  0:32 89%       ` Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-25  0:18 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Rusty Russell,
	LKML, lguest, akpm, Jeremy Fitzhardinge

On Sun, Feb 24, 2008 at 06:26:53PM +0200, Ahmed S. Darwish wrote:
> On Sun, Feb 24, 2008 at 05:18:14PM +0100, Ingo Molnar wrote:
> 
> > I've picked up your patch into x86.git#testing (until Rusty picks it 
> > up), you can track it the following way:
> > 
> >     http://people.redhat.com/mingo/x86.git/README
> > 
> > it has other lguest fixes as well - could you double-check that 
> > x86.git#testing works fine for you as-is? (i've just updated the git 
> > tree so it includes your fix as well)
> > 
> 
> Ofcourse. I'll send you the results by GMT night.
> 

This thread's main bug no longer appears. There's a new bug though,
but it looks nicer than the original ugly bug!. 

The new bug does *not* appear in mainline with the same patch. It's
a panic, but this time on the _guest_ side (which is the same host's
kernel).

[    0.023996] CPU: Intel(R) Pentium(R) M processor 1500MHz stepping 05
[    0.023996] Kernel panic - not syncing: Kernel compiled for Pentium+, requires TSC feature!
[    0.023996] Pid: 0, comm: swapper Not tainted 2.6.25-rc2-00815-g3db3a05 #64
[    0.024996]  [<c011bbc7>] panic+0x47/0x120
[    0.024996]  [<c0101b30>] lguest_power_off+0x0/0x20
[    0.024996]  [<c02a88c5>] check_bugs+0x155/0x170
[    0.024996]  [<c02a2b1f>] start_kernel+0x22f/0x2d0
[    0.024996]  [<c02a2390>] unknown_bootoption+0x0/0x1f0
[    0.024996]  [<c0101450>] lguest_restart+0x0/0x20
[    0.024996]  [<c0101450>] lguest_restart+0x0/0x20
[    0.024996]  [<c02a5e22>] lguest_init+0x282/0x290
[    0.024996]  =======================

I'll track it further in my first free time slot.

It seems lguest is very sensitive to x86 tree changes. Could it be 
included in a sort of automatic guest-boot testing, please ?

Thank you,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 97%]

* Re: 2.6.25-rc3: Reported regressions from 2.6.24
  @ 2008-02-25 18:24 99% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-25 18:24 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: LKML, Andrew Morton, Linus Torvalds, Adrian Bunk, Ingo Molnar

On Mon, Feb 25, 2008 at 02:41:40AM +0100, Rafael J. Wysocki wrote:
> This message contains a list of some regressions from 2.6.24 reported since
> 2.6.25-rc1 was released, for which there are no fixes in the mainline I know
> of.  If any of them have been fixed already, please let me know.
> 
> If you know of any other unresolved regressions from 2.6.24, please let me know
> either and I'll add them to the list.  Also, please let me know if any of the
> entries below are invalid.
> 

There's an lguest Oops reported here:

http://lkml.org/lkml/2008/2/24/136

and a patch in the same report. It's not yet approved by Rusty, but
Ingo thinks it's fine.

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [PATCH -mm 0/4] LSM interfaced Audit (SELinux audit separation)
@ 2008-02-26 23:22 94% Ahmed S. Darwish
  2008-02-26 23:24 75% ` [PATCH -mm 1/4] LSM: Introduce inode_getsecid and ipc_getsecid hooks Ahmed S. Darwish
                   ` (3 more replies)
  0 siblings, 4 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-26 23:22 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse
  Cc: linux-security-module, LKML, akpm

Hi everybody,

This is a beginning of work (started and suggested by Casey Schaufler)
to let Audit be LSM neutral. This is done for proper audit<->SMACK 
integration which will also be useful for any future LSM.

What follows is four patches to remove the following exported 
SElinux interfaces:
selinux_get_inode_sid(inode, sid)
selinux_get_ipc_sid(ipcp, sid) 
selinux_get_task_sid(tsk, sid)
selinux_sid_to_string(sid, ctx, len)

and substitue them respectively with:
new LSM hook, inode_getsecid(inode, secid)
new LSM hook, ipc_getsecid*(ipcp, secid)
LSM hook, task_getsecid(tsk, secid)
LSM hook, sid_to_secctx(sid, ctx, len)

The work isn't complete yet, and those four patches are sent for
an early review. A new LSM interfaces/hooks will be created to
substitute the SELinux exported audit interfaces, thus completing
the separation.

It's worthy to note that those changes can be merged in
their current state. The tree is fully grepped to make sure
that no subsystem ,except the patched ones, will be affected
by this SELinux API breakage.

Diffstat:

 include/linux/security.h   |   23 +++++++++++++++-
 include/linux/selinux.h    |   62 ---------------------------------------------
 kernel/audit.c             |   14 +++++-----
 kernel/auditfilter.c       |    5 ++-
 kernel/auditsc.c           |   37 +++++++++++++-------------
 net/netlink/af_netlink.c   |    3 --
 security/dummy.c           |   16 ++++++++++-
 security/security.c        |   12 ++++++++
 security/selinux/exports.c |   42 ------------------------------
 security/selinux/hooks.c   |   19 ++++++++++++-
 10 files changed, 95 insertions(+), 138 deletions(-)

Thanks in advance for your reviews and comments.

-- 
Ahmed S. Darwish
Blog: http://darwish-07.blogspot.com
Homepage: http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 94%]

* [PATCH -mm 1/4] LSM: Introduce inode_getsecid and ipc_getsecid hooks
  2008-02-26 23:22 94% [PATCH -mm 0/4] LSM interfaced Audit (SELinux audit separation) Ahmed S. Darwish
@ 2008-02-26 23:24 75% ` Ahmed S. Darwish
    2008-02-26 23:25 74% ` [PATCH -mm 2/4] SELinux: Remove various exported symbols Ahmed S. Darwish
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-26 23:24 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse
  Cc: linux-security-module, LKML, akpm

Introduce inode_getsecid(inode, secid) and ipc_getsecid(ipcp, secid)
LSM hooks.

This hooks will be used instead of similar exported SELinux 
interfaces.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 include/linux/security.h |   18 ++++++++++++++++++
 security/dummy.c         |   12 ++++++++++++
 security/security.c      |   12 ++++++++++++
 3 files changed, 42 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index a33fd03..a7fb136 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -449,6 +449,10 @@ struct request_sock;
  *	@dentry is the dentry being changed.
  *	Return 0 on success.  If error is returned, then the operation
  *	causing setuid bit removal is failed.
+ * @inode_getsecid:
+ *      Get the secid associated with the node
+ *      @inode contains a pointer to the inode
+ *      @secid contains a pointer to the location to store the result
  *
  * Security hooks for file operations
  *
@@ -989,6 +993,10 @@ struct request_sock;
  *	@ipcp contains the kernel IPC permission structure
  *	@flag contains the desired (requested) permission set
  *	Return 0 if permission is granted.
+ * @ipc_getsecid:
+ *      Get the secid associated with the ipc object
+ *      @ipcp contains the kernel IPC permission structure
+ *      @secid contains a pointer to the location where result will be saved
  *
  * Security hooks for individual messages held in System V IPC message queues
  * @msg_msg_alloc_security:
@@ -1310,6 +1318,7 @@ struct security_operations {
 	int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc);
   	int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
   	int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
+	void (*inode_getsecid)(const struct inode *inode, u32 *secid);
 
 	int (*file_permission) (struct file * file, int mask);
 	int (*file_alloc_security) (struct file * file);
@@ -1362,6 +1371,7 @@ struct security_operations {
 	void (*task_to_inode)(struct task_struct *p, struct inode *inode);
 
 	int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+	void (*ipc_getsecid) (struct kern_ipc_perm *ipcp, u32 *secid);
 
 	int (*msg_msg_alloc_security) (struct msg_msg * msg);
 	void (*msg_msg_free_security) (struct msg_msg * msg);
@@ -1571,6 +1581,7 @@ int security_inode_killpriv(struct dentry *dentry);
 int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
 int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
 int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
+void security_inode_getsecid(const struct inode *inode, u32 *secid);
 int security_file_permission(struct file *file, int mask);
 int security_file_alloc(struct file *file);
 void security_file_free(struct file *file);
@@ -1615,6 +1626,7 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 void security_task_reparent_to_init(struct task_struct *p);
 void security_task_to_inode(struct task_struct *p, struct inode *inode);
 int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
+void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid);
 int security_msg_msg_alloc(struct msg_msg *msg);
 void security_msg_msg_free(struct msg_msg *msg);
 int security_msg_queue_alloc(struct msg_queue *msq);
@@ -1985,6 +1997,9 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer,
 	return 0;
 }
 
+static inline void security_inode_getsecid(const struct inode *inode, u32 *secid)
+{ }
+
 static inline int security_file_permission (struct file *file, int mask)
 {
 	return 0;
@@ -2179,6 +2194,9 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
 	return 0;
 }
 
+static inline void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{ }
+
 static inline int security_msg_msg_alloc (struct msg_msg * msg)
 {
 	return 0;
diff --git a/security/dummy.c b/security/dummy.c
index 6a0056b..c2f4c52 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -422,6 +422,11 @@ static int dummy_inode_listsecurity(struct inode *inode, char *buffer, size_t bu
 	return 0;
 }
 
+static void dummy_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	return;
+}
+
 static int dummy_file_permission (struct file *file, int mask)
 {
 	return 0;
@@ -614,6 +619,11 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
 	return 0;
 }
 
+static void dummy_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+	return;
+}
+
 static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
 {
 	return 0;
@@ -1062,6 +1072,7 @@ void security_fixup_ops (struct security_operations *ops)
 	set_to_dummy_if_null(ops, inode_getsecurity);
 	set_to_dummy_if_null(ops, inode_setsecurity);
 	set_to_dummy_if_null(ops, inode_listsecurity);
+	set_to_dummy_if_null(ops, inode_getsecid);
 	set_to_dummy_if_null(ops, file_permission);
 	set_to_dummy_if_null(ops, file_alloc_security);
 	set_to_dummy_if_null(ops, file_free_security);
@@ -1098,6 +1109,7 @@ void security_fixup_ops (struct security_operations *ops)
 	set_to_dummy_if_null(ops, task_reparent_to_init);
  	set_to_dummy_if_null(ops, task_to_inode);
 	set_to_dummy_if_null(ops, ipc_permission);
+	set_to_dummy_if_null(ops, ipc_getsecid);
 	set_to_dummy_if_null(ops, msg_msg_alloc_security);
 	set_to_dummy_if_null(ops, msg_msg_free_security);
 	set_to_dummy_if_null(ops, msg_queue_alloc_security);
diff --git a/security/security.c b/security/security.c
index 3e75b90..fcf2be3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -516,6 +516,12 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
 	return security_ops->inode_listsecurity(inode, buffer, buffer_size);
 }
 
+void security_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	security_ops->inode_getsecid(inode, secid);
+}
+EXPORT_SYMBOL(security_inode_getsecid);
+
 int security_file_permission(struct file *file, int mask)
 {
 	return security_ops->file_permission(file, mask);
@@ -705,6 +711,12 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 	return security_ops->ipc_permission(ipcp, flag);
 }
 
+void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+	security_ops->ipc_getsecid(ipcp, secid);
+}
+EXPORT_SYMBOL(security_ipc_getsecid);
+
 int security_msg_msg_alloc(struct msg_msg *msg)
 {
 	return security_ops->msg_msg_alloc_security(msg);

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 75%]

* [PATCH -mm 2/4] SELinux: Remove various exported symbols
  2008-02-26 23:22 94% [PATCH -mm 0/4] LSM interfaced Audit (SELinux audit separation) Ahmed S. Darwish
  2008-02-26 23:24 75% ` [PATCH -mm 1/4] LSM: Introduce inode_getsecid and ipc_getsecid hooks Ahmed S. Darwish
@ 2008-02-26 23:25 74% ` Ahmed S. Darwish
  2008-02-26 23:28 65% ` [PATCH -mm 3/4] Audit: start not to use SELinux " Ahmed S. Darwish
  2008-02-26 23:31 99% ` [PATCH -mm 4/4] Netlink: Use LSM interface instead of SELinux one Ahmed S. Darwish
  3 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-26 23:25 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse
  Cc: linux-security-module, LKML, akpm

Remove the following exported SELinux interfaces:
selinux_get_inode_sid(inode, sid)
selinux_get_ipc_sid(ipcp, sid) 
selinux_get_task_sid(tsk, sid)
selinux_sid_to_string(sid, ctx, len)

and substitue them with following equivalents respectively:
new LSM hook, inode_getsecid(inode, secid)
new LSM hook, ipc_getsecid*(ipcp, secid)
LSM hook, task_getsecid(tsk, secid)
LSM hook, sid_to_secctx(sid, ctx, len)

This is done to remove SELinux dependency from some
of the kernel subsystems (audit).

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 include/linux/selinux.h    |   62 ---------------------------------------------
 security/selinux/exports.c |   42 ------------------------------
 security/selinux/hooks.c   |   19 ++++++++++++-
 3 files changed, 17 insertions(+), 106 deletions(-)

diff --git a/include/linux/selinux.h b/include/linux/selinux.h
index 8c2cc4c..24b0af1 100644
--- a/include/linux/selinux.h
+++ b/include/linux/selinux.h
@@ -16,7 +16,6 @@
 
 struct selinux_audit_rule;
 struct audit_context;
-struct inode;
 struct kern_ipc_perm;
 
 #ifdef CONFIG_SECURITY_SELINUX
@@ -70,45 +69,6 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
 void selinux_audit_set_callback(int (*callback)(void));
 
 /**
- *     selinux_sid_to_string - map a security context ID to a string
- *     @sid: security context ID to be converted.
- *     @ctx: address of context string to be returned
- *     @ctxlen: length of returned context string.
- *
- *     Returns 0 if successful, -errno if not.  On success, the context
- *     string will be allocated internally, and the caller must call
- *     kfree() on it after use.
- */
-int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen);
-
-/**
- *     selinux_get_inode_sid - get the inode's security context ID
- *     @inode: inode structure to get the sid from.
- *     @sid: pointer to security context ID to be filled in.
- *
- *     Returns nothing
- */
-void selinux_get_inode_sid(const struct inode *inode, u32 *sid);
-
-/**
- *     selinux_get_ipc_sid - get the ipc security context ID
- *     @ipcp: ipc structure to get the sid from.
- *     @sid: pointer to security context ID to be filled in.
- *
- *     Returns nothing
- */
-void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid);
-
-/**
- *     selinux_get_task_sid - return the SID of task
- *     @tsk: the task whose SID will be returned
- *     @sid: pointer to security context ID to be filled in.
- *
- *     Returns nothing
- */
-void selinux_get_task_sid(struct task_struct *tsk, u32 *sid);
-
-/**
  *     selinux_string_to_sid - map a security context string to a security ID
  *     @str: the security context string to be mapped
  *     @sid: ID value returned via this.
@@ -175,28 +135,6 @@ static inline void selinux_audit_set_callback(int (*callback)(void))
 	return;
 }
 
-static inline int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
-{
-       *ctx = NULL;
-       *ctxlen = 0;
-       return 0;
-}
-
-static inline void selinux_get_inode_sid(const struct inode *inode, u32 *sid)
-{
-	*sid = 0;
-}
-
-static inline void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid)
-{
-	*sid = 0;
-}
-
-static inline void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
-{
-	*sid = 0;
-}
-
 static inline int selinux_string_to_sid(const char *str, u32 *sid)
 {
        *sid = 0;
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index 87d2bb3..64af2d3 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -25,48 +25,6 @@
 /* SECMARK reference count */
 extern atomic_t selinux_secmark_refcount;
 
-int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
-{
-	if (selinux_enabled)
-		return security_sid_to_context(sid, ctx, ctxlen);
-	else {
-		*ctx = NULL;
-		*ctxlen = 0;
-	}
-
-	return 0;
-}
-
-void selinux_get_inode_sid(const struct inode *inode, u32 *sid)
-{
-	if (selinux_enabled) {
-		struct inode_security_struct *isec = inode->i_security;
-		*sid = isec->sid;
-		return;
-	}
-	*sid = 0;
-}
-
-void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid)
-{
-	if (selinux_enabled) {
-		struct ipc_security_struct *isec = ipcp->security;
-		*sid = isec->sid;
-		return;
-	}
-	*sid = 0;
-}
-
-void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
-{
-	if (selinux_enabled) {
-		struct task_security_struct *tsec = tsk->security;
-		*sid = tsec->sid;
-		return;
-	}
-	*sid = 0;
-}
-
 int selinux_string_to_sid(char *str, u32 *sid)
 {
 	if (selinux_enabled)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f42ebfc..62a0f26 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2724,6 +2724,12 @@ static int selinux_inode_killpriv(struct dentry *dentry)
 	return secondary_ops->inode_killpriv(dentry);
 }
 
+static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	struct inode_security_struct *isec = inode->i_security;
+	*secid = isec->sid;
+}
+
 /* file security operations */
 
 static int selinux_revalidate_file_permission(struct file *file, int mask)
@@ -3120,7 +3126,8 @@ static int selinux_task_getsid(struct task_struct *p)
 
 static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
 {
-	selinux_get_task_sid(p, secid);
+	struct task_security_struct *tsec = p->security;
+	*secid = tsec->sid;
 }
 
 static int selinux_task_setgroups(struct group_info *group_info)
@@ -4090,7 +4097,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
 		goto out;
 
 	if (sock && family == PF_UNIX)
-		selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
+		selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
 	else if (skb)
 		selinux_skb_peerlbl_sid(skb, family, &peer_secid);
 
@@ -4970,6 +4977,12 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 	return ipc_has_perm(ipcp, av);
 }
 
+static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+	struct ipc_security_struct *isec = ipcp->security;
+	*secid = isec->sid;
+}
+
 /* module stacking operations */
 static int selinux_register_security (const char *name, struct security_operations *ops)
 {
@@ -5292,6 +5305,7 @@ static struct security_operations selinux_ops = {
 	.inode_listsecurity =           selinux_inode_listsecurity,
 	.inode_need_killpriv =		selinux_inode_need_killpriv,
 	.inode_killpriv =		selinux_inode_killpriv,
+	.inode_getsecid =               selinux_inode_getsecid,
 
 	.file_permission =		selinux_file_permission,
 	.file_alloc_security =		selinux_file_alloc_security,
@@ -5332,6 +5346,7 @@ static struct security_operations selinux_ops = {
 	.task_to_inode =                selinux_task_to_inode,
 
 	.ipc_permission =		selinux_ipc_permission,
+	.ipc_getsecid =                 selinux_ipc_getsecid,
 
 	.msg_msg_alloc_security =	selinux_msg_msg_alloc_security,
 	.msg_msg_free_security =	selinux_msg_msg_free_security,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 74%]

* [PATCH -mm 3/4] Audit: start not to use SELinux exported symbols
  2008-02-26 23:22 94% [PATCH -mm 0/4] LSM interfaced Audit (SELinux audit separation) Ahmed S. Darwish
  2008-02-26 23:24 75% ` [PATCH -mm 1/4] LSM: Introduce inode_getsecid and ipc_getsecid hooks Ahmed S. Darwish
  2008-02-26 23:25 74% ` [PATCH -mm 2/4] SELinux: Remove various exported symbols Ahmed S. Darwish
@ 2008-02-26 23:28 65% ` Ahmed S. Darwish
    2008-02-26 23:31 99% ` [PATCH -mm 4/4] Netlink: Use LSM interface instead of SELinux one Ahmed S. Darwish
  3 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-02-26 23:28 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse
  Cc: linux-security-module, LKML, akpm

Remove the following exported SELinux interfaces:
selinux_get_inode_sid(inode, sid)
selinux_get_ipc_sid(ipcp, sid) 
selinux_get_task_sid(tsk, sid)
selinux_sid_to_string(sid, ctx, len)

and substitue them with following generic LSM equivalents 
respectively:
security_inode_getsecid(inode, secid)
security_ipc_getsecid*(ipcp, secid)
security_task_getsecid(tsk, secid)
security_sid_to_secctx(sid, ctx, len)

Let the security_task_getsecid(tsk, secid) LSM hook set
the secid to 0 by default if CONFIG_SECURITY is not defined 
or if the hook is set to NULL (dummy). This is done to
notify the caller that no valid secid exists.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 include/linux/security.h |    5 ++++-
 kernel/audit.c           |   14 +++++++-------
 kernel/auditfilter.c     |    5 +++--
 kernel/auditsc.c         |   37 ++++++++++++++++++-------------------
 security/dummy.c         |    4 +++-
 6 files changed, 36 insertions(+), 32 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index a7fb136..35c98f0 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -621,6 +621,7 @@ struct request_sock;
  * @task_getsecid:
  *	Retrieve the security identifier of the process @p.
  *	@p contains the task_struct for the process and place is into @secid.
+ *      In case of failure, @secid will be set to zero
  * @task_setgroups:
  *	Check permission before setting the supplementary group set of the
  *	current process.
@@ -2115,7 +2116,9 @@ static inline int security_task_getsid (struct task_struct *p)
 }
 
 static inline void security_task_getsecid (struct task_struct *p, u32 *secid)
-{ }
+{ 
+	*secid = 0;
+}
 
 static inline int security_task_setgroups (struct group_info *group_info)
 {
diff --git a/security/dummy.c b/security/dummy.c
index c2f4c52..56b007e 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -545,7 +545,9 @@ static int dummy_task_getsid (struct task_struct *p)
 }
 
 static void dummy_task_getsecid (struct task_struct *p, u32 *secid)
-{ }
+{
+	*secid = 0;
+}
 
 static int dummy_task_setgroups (struct group_info *group_info)
 {
diff --git a/kernel/audit.c b/kernel/audit.c
index 8316a88..2bd4124 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -259,13 +259,13 @@ static int audit_log_config_change(char *function_name, int new, int old,
 		char *ctx = NULL;
 		u32 len;
 
-		rc = selinux_sid_to_string(sid, &ctx, &len);
+		rc = security_secid_to_secctx(sid, &ctx, &len);
 		if (rc) {
 			audit_log_format(ab, " sid=%u", sid);
 			allow_changes = 0; /* Something weird, deny request */
 		} else {
 			audit_log_format(ab, " subj=%s", ctx);
-			kfree(ctx);
+			security_release_secctx(ctx, len);
 		}
 	}
 	audit_log_format(ab, " res=%d", allow_changes);
@@ -543,12 +543,12 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
 	audit_log_format(*ab, "user pid=%d uid=%u auid=%u",
 			 pid, uid, auid);
 	if (sid) {
-		rc = selinux_sid_to_string(sid, &ctx, &len);
+		rc = security_secid_to_secctx(sid, &ctx, &len);
 		if (rc)
 			audit_log_format(*ab, " ssid=%u", sid);
 		else
 			audit_log_format(*ab, " subj=%s", ctx);
-		kfree(ctx);
+		security_release_secctx(ctx, len);
 	}
 
 	return rc;
@@ -750,18 +750,18 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 		break;
 	}
 	case AUDIT_SIGNAL_INFO:
-		err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
+		err = security_secid_to_secctx(audit_sig_sid, &ctx, &len);
 		if (err)
 			return err;
 		sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
 		if (!sig_data) {
-			kfree(ctx);
+			security_release_secctx(ctx, len);
 			return -ENOMEM;
 		}
 		sig_data->uid = audit_sig_uid;
 		sig_data->pid = audit_sig_pid;
 		memcpy(sig_data->ctx, ctx, len);
-		kfree(ctx);
+		security_release_secctx(ctx, len);
 		audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO,
 				0, 0, sig_data, sizeof(*sig_data) + len);
 		kfree(sig_data);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 2f2914b..894e3bd 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -28,6 +28,7 @@
 #include <linux/netlink.h>
 #include <linux/sched.h>
 #include <linux/inotify.h>
+#include <linux/security.h>
 #include <linux/selinux.h>
 #include "audit.h"
 
@@ -1515,11 +1516,11 @@ static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
 	if (sid) {
 		char *ctx = NULL;
 		u32 len;
-		if (selinux_sid_to_string(sid, &ctx, &len))
+		if (security_secid_to_secctx(sid, &ctx, &len))
 			audit_log_format(ab, " ssid=%u", sid);
 		else
 			audit_log_format(ab, " subj=%s", ctx);
-		kfree(ctx);
+		security_release_secctx(ctx, len);
 	}
 	audit_log_format(ab, " op=%s rule key=", action);
 	if (rule->filterkey)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d07fc4a..631c044 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -530,7 +530,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 			   logged upon error */
 			if (f->se_rule) {
 				if (need_sid) {
-					selinux_get_task_sid(tsk, &sid);
+					security_task_getsecid(tsk, &sid);
 					need_sid = 0;
 				}
 				result = selinux_audit_rule_match(sid, f->type,
@@ -885,11 +885,11 @@ void audit_log_task_context(struct audit_buffer *ab)
 	int error;
 	u32 sid;
 
-	selinux_get_task_sid(current, &sid);
+	security_task_getsecid(current, &sid);
 	if (!sid)
 		return;
 
-	error = selinux_sid_to_string(sid, &ctx, &len);
+	error = security_secid_to_secctx(sid, &ctx, &len);
 	if (error) {
 		if (error != -EINVAL)
 			goto error_path;
@@ -897,7 +897,7 @@ void audit_log_task_context(struct audit_buffer *ab)
 	}
 
 	audit_log_format(ab, " subj=%s", ctx);
-	kfree(ctx);
+	security_release_secctx(ctx, len);
 	return;
 
 error_path:
@@ -951,7 +951,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 
 	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
 			 uid, sessionid);
-	if (selinux_sid_to_string(sid, &s, &len)) {
+	if (security_secid_to_secctx(sid, &s, &len)) {
 		audit_log_format(ab, " obj=(none)");
 		rc = 1;
 	} else
@@ -1268,14 +1268,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 			if (axi->osid != 0) {
 				char *ctx = NULL;
 				u32 len;
-				if (selinux_sid_to_string(
+				if (security_secid_to_secctx(
 						axi->osid, &ctx, &len)) {
 					audit_log_format(ab, " osid=%u",
 							axi->osid);
 					call_panic = 1;
 				} else
 					audit_log_format(ab, " obj=%s", ctx);
-				kfree(ctx);
+				security_release_secctx(ctx, len);
 			}
 			break; }
 
@@ -1389,13 +1389,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 		if (n->osid != 0) {
 			char *ctx = NULL;
 			u32 len;
-			if (selinux_sid_to_string(
+			if (security_secid_to_secctx(
 				n->osid, &ctx, &len)) {
 				audit_log_format(ab, " osid=%u", n->osid);
 				call_panic = 2;
 			} else
 				audit_log_format(ab, " obj=%s", ctx);
-			kfree(ctx);
+			security_release_secctx(ctx, len);
 		}
 
 		audit_log_end(ab);
@@ -1772,7 +1772,7 @@ static void audit_copy_inode(struct audit_names *name, const struct inode *inode
 	name->uid   = inode->i_uid;
 	name->gid   = inode->i_gid;
 	name->rdev  = inode->i_rdev;
-	selinux_get_inode_sid(inode, &name->osid);
+	security_inode_getsecid(inode, &name->osid);
 }
 
 /**
@@ -2187,8 +2187,7 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp)
 	ax->uid = ipcp->uid;
 	ax->gid = ipcp->gid;
 	ax->mode = ipcp->mode;
-	selinux_get_ipc_sid(ipcp, &ax->osid);
-
+	security_ipc_getsecid(ipcp, &ax->osid);
 	ax->d.type = AUDIT_IPC;
 	ax->d.next = context->aux;
 	context->aux = (void *)ax;
@@ -2340,7 +2339,7 @@ void __audit_ptrace(struct task_struct *t)
 	context->target_auid = audit_get_loginuid(t);
 	context->target_uid = t->uid;
 	context->target_sessionid = audit_get_sessionid(t);
-	selinux_get_task_sid(t, &context->target_sid);
+	security_task_getsecid(t, &context->target_sid);
 	memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
 }
 
@@ -2368,7 +2367,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 				audit_sig_uid = tsk->loginuid;
 			else
 				audit_sig_uid = tsk->uid;
-			selinux_get_task_sid(tsk, &audit_sig_sid);
+			security_task_getsecid(tsk, &audit_sig_sid);
 		}
 		if (!audit_signals || audit_dummy_context())
 			return 0;
@@ -2381,7 +2380,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 		ctx->target_auid = audit_get_loginuid(t);
 		ctx->target_uid = t->uid;
 		ctx->target_sessionid = audit_get_sessionid(t);
-		selinux_get_task_sid(t, &ctx->target_sid);
+		security_task_getsecid(t, &ctx->target_sid);
 		memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
 		return 0;
 	}
@@ -2402,7 +2401,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 	axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
 	axp->target_uid[axp->pid_count] = t->uid;
 	axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
-	selinux_get_task_sid(t, &axp->target_sid[axp->pid_count]);
+	security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
 	memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
 	axp->pid_count++;
 
@@ -2432,16 +2431,16 @@ void audit_core_dumps(long signr)
 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
 	audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
 			auid, current->uid, current->gid, sessionid);
-	selinux_get_task_sid(current, &sid);
+	security_task_getsecid(current, &sid);
 	if (sid) {
 		char *ctx = NULL;
 		u32 len;
 
-		if (selinux_sid_to_string(sid, &ctx, &len))
+		if (security_secid_to_secctx(sid, &ctx, &len))
 			audit_log_format(ab, " ssid=%u", sid);
 		else
 			audit_log_format(ab, " subj=%s", ctx);
-		kfree(ctx);
+		security_release_secctx(ctx, len);
 	}
 	audit_log_format(ab, " pid=%d comm=", current->pid);
 	audit_log_untrustedstring(ab, current->comm);


-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 65%]

* [PATCH -mm 4/4] Netlink: Use LSM interface instead of SELinux one
  2008-02-26 23:22 94% [PATCH -mm 0/4] LSM interfaced Audit (SELinux audit separation) Ahmed S. Darwish
                   ` (2 preceding siblings ...)
  2008-02-26 23:28 65% ` [PATCH -mm 3/4] Audit: start not to use SELinux " Ahmed S. Darwish
@ 2008-02-26 23:31 99% ` Ahmed S. Darwish
  3 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-26 23:31 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse
  Cc: linux-security-module, LKML, akpm

Don't use SELinux exported selinux_get_task_sid symbol. 
Use the generic LSM equivalent instead.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1ab0da2..61fd277 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -54,7 +54,6 @@
 #include <linux/mm.h>
 #include <linux/types.h>
 #include <linux/audit.h>
-#include <linux/selinux.h>
 #include <linux/mutex.h>
 
 #include <net/net_namespace.h>
@@ -1239,7 +1238,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
 	NETLINK_CB(skb).pid	= nlk->pid;
 	NETLINK_CB(skb).dst_group = dst_group;
 	NETLINK_CB(skb).loginuid = audit_get_loginuid(current);
-	selinux_get_task_sid(current, &(NETLINK_CB(skb).sid));
+	security_task_getsecid(current, &(NETLINK_CB(skb).sid));
 	memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
 
 	/* What can I do? Netlink is asynchronous, so that

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH -mm 1/4] LSM: Introduce inode_getsecid and ipc_getsecid hooks
  @ 2008-02-27 16:45 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-27 16:45 UTC (permalink / raw)
  To: Paul Moore
  Cc: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, linux-security-module, LKML,
	akpm

Hi Paul,

On Wed, Feb 27, 2008 at 11:04:57AM -0500, Paul Moore wrote:
> On Tuesday 26 February 2008 6:24:11 pm Ahmed S. Darwish wrote:
> > Introduce inode_getsecid(inode, secid) and ipc_getsecid(ipcp, secid)
> > LSM hooks.
> >
> > This hooks will be used instead of similar exported SELinux
> > interfaces.
> >
> > Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> > Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
> > ---
> >
> >  include/linux/security.h |   18 ++++++++++++++++++
> >  security/dummy.c         |   12 ++++++++++++
> >  security/security.c      |   12 ++++++++++++
> >  3 files changed, 42 insertions(+)
> >
...
> ...
> 
> > +static inline void security_ipc_getsecid(struct kern_ipc_perm *ipcp,
> > u32 *secid)
> > +{ } 
> 
> Should these both do a  "*secid = 0;"?
> 

Yes, this will also lead to consistency in the interface espcially 
after changing task_getsecid to do the same (in patch #3).

> > diff --git a/security/dummy.c b/security/dummy.c
> > index 6a0056b..c2f4c52 100644
> > --- a/security/dummy.c
> > +++ b/security/dummy.c
> > @@ -422,6 +422,11 @@ static int dummy_inode_listsecurity(struct inode
> > *inode, char *buffer, size_t bu return 0;
> >  }
> >
> > +static void dummy_inode_getsecid(const struct inode *inode, u32
> > *secid)
> > +{ 
> > +	return;
> > +}
> 
> ...
> 
> > +static void dummy_ipc_getsecid(struct kern_ipc_perm *ipcp, u32
> > *secid)
> > +{ 
> > +	return;
> > +}
> 
> Same question.
> 

Both will be changed to *secid = 0 in the comming send. Thanks!

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH -mm 3/4] Audit: start not to use SELinux exported symbols
  @ 2008-02-27 17:11 98%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-27 17:11 UTC (permalink / raw)
  To: Paul Moore
  Cc: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, linux-security-module, LKML,
	akpm

Hi!,

On Wed, Feb 27, 2008 at 11:00:57AM -0500, Paul Moore wrote:
> On Tuesday 26 February 2008 6:28:08 pm Ahmed S. Darwish wrote:
...
> >
> > Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> > Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
> 
> In the future, such patches should probably also be CC'd to the audit 
> list.
> 

No problem.

> > ---
> >
> >  include/linux/security.h |    5 ++++-
> >  kernel/audit.c           |   14 +++++++-------
> >  kernel/auditfilter.c     |    5 +++--
> >  kernel/auditsc.c         |   37
> > ++++++++++++++++++------------------- security/dummy.c         |    4
> > +++-
> >  6 files changed, 36 insertions(+), 32 deletions(-)
> >
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index a7fb136..35c98f0 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -621,6 +621,7 @@ struct request_sock;
> >   * @task_getsecid:
> >   *	Retrieve the security identifier of the process @p.
> >   *	@p contains the task_struct for the process and place is into
> > @secid.
> > + *      In case of failure, @secid will be set to zero
> 
> This is a nit, but you used spaces between the "*" and "In case ..." 
> where the rest of the files uses tabs.  When in doubt, try and stick 
> with whatever formatting the rest of the source file uses.
> 

I'll find a way to teach emacs how to print a tab ;). Will do.

> > diff --git a/kernel/audit.c b/kernel/audit.c
> > index 8316a88..2bd4124 100644
> > --- a/kernel/audit.c
> > +++ b/kernel/audit.c
> > @@ -259,13 +259,13 @@ static int audit_log_config_change(char
> > *function_name, int new, int old, char *ctx = NULL;
> >  		u32 len;
> >
> > -		rc = selinux_sid_to_string(sid, &ctx, &len);
> > +		rc = security_secid_to_secctx(sid, &ctx, &len);
> >  		if (rc) {
> >  			audit_log_format(ab, " sid=%u", sid);
> >  			allow_changes = 0; /* Something weird, deny request */
> >  		} else {
> >  			audit_log_format(ab, " subj=%s", ctx);
> > -			kfree(ctx);
> > +			security_release_secctx(ctx, len);
> >  		}
> >  	}
> >  	audit_log_format(ab, " res=%d", allow_changes);
> > @@ -543,12 +543,12 @@ static int audit_log_common_recv_msg(struct
> > audit_buffer **ab, u16 msg_type, audit_log_format(*ab, "user pid=%d
> > uid=%u auid=%u",
> >  			 pid, uid, auid);
> >  	if (sid) {
> > -		rc = selinux_sid_to_string(sid, &ctx, &len);
> > +		rc = security_secid_to_secctx(sid, &ctx, &len);
> >  		if (rc)
> >  			audit_log_format(*ab, " ssid=%u", sid);
> >  		else
> >  			audit_log_format(*ab, " subj=%s", ctx);
> > -		kfree(ctx);
> > +		security_release_secctx(ctx, len);
> >  	}
> >
> >  	return rc;
> 
> This next part isn't your fault, but you're touching the code so I'm 
> going to point it out and suggest you fix it while you are at it :)
> 
> If you look at how kfree()/security_release_secctx() is called in the 
> above two functions you notice how it is inconsistent: it is only 
> called on success in the first case, but called regardless in the 
> second.  Make this consistent, preferably using the approach taken in 
> the first case (only call it on success).
> 

My pleasure. You'll find them consistent in the next send.

[Same release_ctx() consistency point]
...

> 
> > @@ -951,7 +951,7 @@ static int audit_log_pid_context(struct
> > audit_context *context, pid_t pid,
> >
> >  	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
> >  			 uid, sessionid);
> > -	if (selinux_sid_to_string(sid, &s, &len)) {
> > +	if (security_secid_to_secctx(sid, &s, &len)) {
> >  		audit_log_format(ab, " obj=(none)");
> >  		rc = 1;
> >  	} else
> 
> You forgot to convert the matching kfree() call to a 
> security_release_secctx() call.  Also it might be nice to change the 
> context variable name from "s" to "ctx", but some ornery folks might 
> whine about that ...
> 

Nice spot, will do. 's' will be changed too, context is already
used as 'ctx' in the whole file anyway.

[...]
> 
> Only call the release routine on success.
> 
[...]
> 
> Here too.
> 
[...]
> 
> One last time.
> 

Thanks a lot for such a deep review :). I'll modify spotted problems
as suggested, reorder the patch in a non compilation-breaking order, 
and keep you informed.

Modified patches will be sent with the new ones that will complete 
the separation not to add too much noise in LKML.

Warm regards

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 98%]

* Re: [BUG + PATCH/Bugfix] x86/lguest: fix pgdir pmd index calculation
  2008-02-25  0:18 97%     ` Ahmed S. Darwish
@ 2008-02-29  0:32 89%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-02-29  0:32 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Rusty Russell,
	LKML, lguest, akpm, Jeremy Fitzhardinge

Hi Ingo/x86-folks,

On Mon, Feb 25, 2008 at 02:18:16AM +0200, Ahmed S. Darwish wrote:
...
> 
> This thread's main bug no longer appears. There's a new bug though,
> but it looks nicer than the original ugly bug!. 
> 
> The new bug does *not* appear in mainline with the same patch. It's
> a panic, but this time on the _guest_ side (which is the same host's
> kernel).
>
> [    0.023996] CPU: Intel(R) Pentium(R) M processor 1500MHz stepping 05
> [    0.023996] Kernel panic - not syncing: Kernel compiled for Pentium+, requires TSC feature!
> [    0.023996] Pid: 0, comm: swapper Not tainted 2.6.25-rc2-00815-g3db3a05 #64
> 

The bug appeared in mainline due to the latest x86 merge. The commit
that caused the bug is not faulty though:

commit 12c247a6719987aad65f83158d2bb3e73c75c1f5
    x86: fix boot failure on 486 due to TSC breakage

    1. arch/x86/kernel/tsc_32.c:tsc_init() sees !cpu_has_tsc,
       so bails and calls setup_clear_cpu_cap(X86_FEATURE_TSC).
    2. include/asm-x86/cpufeature.h:setup_clear_cpu_cap(bit) clears
       the bit in boot_cpu_data and sets it in cleared_cpu_caps
    3. arch/x86/kernel/cpu/common.c:identify_cpu() XORs all caps
       in with cleared_cpu_caps
       HOWEVER, at this point c->x86_capability correctly has TSC
       Off, cleared_cpu_caps has TSC On, so the XOR incorrectly
       sets TSC to On in c->x86_capability, with disastrous results.

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index f86a3c4..a38aafa 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -504,7 +504,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 
 	/* Clear all flags overriden by options */
 	for (i = 0; i < NCAPINTS; i++)
-		c->x86_capability[i] ^= cleared_cpu_caps[i];
+		c->x86_capability[i] &= ~cleared_cpu_caps[i];
 

Now the commit fixed everything, and x86_capability shows the right
thing (TSC = off). 

On the lguest _guest_ side, 'cpu_has_tsc' is _always_ false (due to 
lguest using his own clocksource ?), thus a guest with a pentium+ 
cpu always panics with:

#ifdef CONFIG_X86_TSC
	if (!cpu_has_tsc)
		panic("Kernel compiled for Pentium+, requires TSC feature!");
#endif


In older kernels (2.6.23), the problem was also hidden using 'tsc_disable':

tsc.c:
	if (!cpu_has_tsc || tsc_disable)
		tsc_disable = 1;

bug.c:
#ifdef CONFIG_X86_TSC
	if (!cpu_has_tsc && !tsc_disable)
		panic("Kernel compiled for Pentium+, requires TSC feature!");
#endif


I've tried solving the problem with several tweaks including something like:

	/* If we're running on a pentium+, fake an enabled TSC to bypass
	 * kernel checks for processor bugs (see x86/cpu/bugs.c) */
	if (boot_cpu_data.x86 >= 5)
		setup_force_cpu_cap(X86_FEATURE_TSC);

with no luck at all. 

Any idea how to solve this problem in a right/mergeable way ?

Thank you,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 89%]

* [RFC PATCH -mm] LSM: Add lsm= boot parameter
@ 2008-03-01 19:07 77% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 19:07 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, Alexey Dobriyan
  Cc: LKML, LSM-ML

Hi everybody,

This is a first try of adding lsm= boot parameter. 

Current situation is:
1- Ignore wrong input, with a small warning to users.
2- If user didn't specify a specific module, none will be loaded

Basically, the patch adds a @name attribute to each LSM. It
also adds a security_module_chosen(op) method where each
LSM _must_ pass before calling register_security().

Thanks,

 Documentation/kernel-parameters.txt |    4 ++++
 include/linux/security.h            |   10 ++++++++++
 security/dummy.c                    |    3 ++-
 security/security.c                 |   35 +++++++++++++++++++++++++++++++++++
 security/selinux/hooks.c            |    5 ++++-
 security/smack/smack_lsm.c          |    7 +++++++
 6 files changed, 62 insertions(+), 2 deletions(-)

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c64dfd7..dde04c8 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,10 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	lsm=		[SECURITY] Choose an LSM to enable at boot. If this boot
+			parameter is not specified, no security module will be 
+			loaded.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index eb663e5..4f695c0 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 struct audit_krule;
 
@@ -118,6 +121,10 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name: LSM name
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1262,6 +1269,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1530,6 +1539,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_chosen(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 241ab20..ed11f97 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -1022,7 +1022,7 @@ static inline void dummy_audit_rule_free(void *lsmrule)
 
 #endif /* CONFIG_AUDIT */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { "dummy" };
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
@@ -1035,6 +1035,7 @@ struct security_operations dummy_security_ops;
 
 void security_fixup_ops (struct security_operations *ops)
 {
+	BUG_ON(!ops->name);
 	set_to_dummy_if_null(ops, ptrace);
 	set_to_dummy_if_null(ops, capget);
 	set_to_dummy_if_null(ops, capset_check);
diff --git a/security/security.c b/security/security.c
index 1bf2ee4..7a84b4e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,8 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot time LSM user choice */
+char chosen_lsm[SECURITY_NAME_MAX + 1];
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -67,6 +69,39 @@ int __init security_init(void)
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	if (strlen(str) > SECURITY_NAME_MAX) {
+		printk(KERN_INFO "Security: LSM name length extends possible "
+		       "limit.\n");
+		printk(KERN_INFO "Security: Ignoring passed lsm= parameter.\n");
+		return 0;
+	}
+
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("lsm=", choose_lsm);
+
+/**
+ * security_module_chosen - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Return true if the passed LSM is the one chosen by user at
+ * boot time, otherwise return false.
+ */
+int security_module_chosen(struct security_operations *ops)
+{
+	if (!ops || !ops->name)
+		return 0;
+
+	if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		return 0;
+	
+	return 1;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index bef1834..d4926b0 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5247,6 +5247,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5443,7 +5445,8 @@ static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
-	if (!selinux_enabled) {
+	if (!selinux_enabled || !security_module_chosen(&selinux_ops)) {
+		selinux_enabled = 0;
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
 	}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 2b5d6f7..4348257 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2358,6 +2358,8 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 }
 
 static struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2485,6 +2487,11 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_chosen(&smack_ops)) {
+		printk(KERN_INFO "Smack: Disabled at boot.\n");
+		return 0;
+	}
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 77%]

* [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation)
@ 2008-03-01 19:47 95% Ahmed S. Darwish
  2008-03-01 19:51 70% ` [PATCH 1/9] LSM: Introduce inode_getsecid and ipc_getsecid hooks Ahmed S. Darwish
                   ` (8 more replies)
  0 siblings, 9 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 19:47 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Hi everybody,

A series of 9 patches to let Audit be LSM netural. This is done 
for proper future audit<->SMACK integration which will also be
useful for any future LSM.

Basically, patches add below new LSM hooks:

1- secid extraction:
inode_getsecid(inode, secid)
ipc_getsecid(ipcp, secid)

2- LSM-specific Audit rules manipulation:
audit_rule_init(field, op, rulestr, lsmrule)
audit_rule_known(krule)
audit_rule_match(secid, field, op, rule, actx)
audit_rule_free(rule)

and remove ,now redundant, equivalent SELinux exported interfaces.

Initial work and idea by: Casey Schaufler <casey@schaufler-ca.com>
Thanks to Paul Moore <paul.moore@hp.com> for his deep review of first
version.

 include/linux/audit.h            |   29 ++++++++
 include/linux/security.h         |  102 +++++++++++++++++++++++++++++
 include/linux/selinux.h          |  134 ---------------------------------------
 kernel/audit.c                   |   24 ++----
 kernel/audit.h                   |   25 -------
 kernel/auditfilter.c             |   99 ++++++++++------------------
 kernel/auditsc.c                 |   74 +++++++++++----------
 net/netlink/af_netlink.c         |    3 +-
 security/dummy.c                 |   47 +++++++++++++
 security/security.c              |   35 ++++++++++
 security/selinux/exports.c       |   42 ------------
 security/selinux/hooks.c         |   27 +++++++
 security/selinux/include/audit.h |   65 ++++++++++++++++++
 security/selinux/ss/services.c   |   45 +++++++++----
 14 files changed, 420 insertions(+), 331 deletions(-)

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 95%]

* [PATCH 1/9] LSM: Introduce inode_getsecid and ipc_getsecid hooks
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
@ 2008-03-01 19:51 70% ` Ahmed S. Darwish
  2008-03-01 19:52 93% ` [PATCH 2/9] SELinux: setup new inode/ipc getsecid hooks Ahmed S. Darwish
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 19:51 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Introduce inode_getsecid(inode, secid) and ipc_getsecid(ipcp, secid)
LSM hooks. These hooks will be used instead of similar exported 
SELinux interfaces.

Let {inode,ipc,task}_getsecid hooks set the secid to 0 by default 
if CONFIG_SECURITY is not defined or if the hook is set to 
NULL (dummy). This is done to notify the caller that no valid 
secid exists.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 include/linux/security.h |   30 +++++++++++++++++++++++++++++-
 security/dummy.c         |   16 +++++++++++++++-
 security/security.c      |   10 ++++++++++
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index a33fd03..205a053 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -449,6 +449,11 @@ struct request_sock;
  *	@dentry is the dentry being changed.
  *	Return 0 on success.  If error is returned, then the operation
  *	causing setuid bit removal is failed.
+ * @inode_getsecid:
+ *	Get the secid associated with the node.
+ *	@inode contains a pointer to the inode.
+ *	@secid contains a pointer to the location where result will be saved.
+ *	In case of failure, @secid will be set to zero.
  *
  * Security hooks for file operations
  *
@@ -617,6 +622,8 @@ struct request_sock;
  * @task_getsecid:
  *	Retrieve the security identifier of the process @p.
  *	@p contains the task_struct for the process and place is into @secid.
+ *	In case of failure, @secid will be set to zero.
+ *
  * @task_setgroups:
  *	Check permission before setting the supplementary group set of the
  *	current process.
@@ -989,6 +996,11 @@ struct request_sock;
  *	@ipcp contains the kernel IPC permission structure
  *	@flag contains the desired (requested) permission set
  *	Return 0 if permission is granted.
+ * @ipc_getsecid:
+ *	Get the secid associated with the ipc object.
+ *	@ipcp contains the kernel IPC permission structure.
+ *	@secid contains a pointer to the location where result will be saved.
+ *	In case of failure, @secid will be set to zero.
  *
  * Security hooks for individual messages held in System V IPC message queues
  * @msg_msg_alloc_security:
@@ -1310,6 +1322,7 @@ struct security_operations {
 	int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc);
   	int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
   	int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
+	void (*inode_getsecid)(const struct inode *inode, u32 *secid);
 
 	int (*file_permission) (struct file * file, int mask);
 	int (*file_alloc_security) (struct file * file);
@@ -1362,6 +1375,7 @@ struct security_operations {
 	void (*task_to_inode)(struct task_struct *p, struct inode *inode);
 
 	int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+	void (*ipc_getsecid) (struct kern_ipc_perm *ipcp, u32 *secid);
 
 	int (*msg_msg_alloc_security) (struct msg_msg * msg);
 	void (*msg_msg_free_security) (struct msg_msg * msg);
@@ -1571,6 +1585,7 @@ int security_inode_killpriv(struct dentry *dentry);
 int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
 int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
 int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
+void security_inode_getsecid(const struct inode *inode, u32 *secid);
 int security_file_permission(struct file *file, int mask);
 int security_file_alloc(struct file *file);
 void security_file_free(struct file *file);
@@ -1615,6 +1630,7 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 void security_task_reparent_to_init(struct task_struct *p);
 void security_task_to_inode(struct task_struct *p, struct inode *inode);
 int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
+void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid);
 int security_msg_msg_alloc(struct msg_msg *msg);
 void security_msg_msg_free(struct msg_msg *msg);
 int security_msg_queue_alloc(struct msg_queue *msq);
@@ -1985,6 +2001,11 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer,
 	return 0;
 }
 
+static inline void security_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	*secid = 0;
+}
+
 static inline int security_file_permission (struct file *file, int mask)
 {
 	return 0;
@@ -2100,7 +2121,9 @@ static inline int security_task_getsid (struct task_struct *p)
 }
 
 static inline void security_task_getsecid (struct task_struct *p, u32 *secid)
-{ }
+{
+	*secid = 0;
+}
 
 static inline int security_task_setgroups (struct group_info *group_info)
 {
@@ -2179,6 +2202,11 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
 	return 0;
 }
 
+static inline void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+	*secid = 0;
+}
+
 static inline int security_msg_msg_alloc (struct msg_msg * msg)
 {
 	return 0;
diff --git a/security/dummy.c b/security/dummy.c
index 6a0056b..f5e5f95 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -422,6 +422,11 @@ static int dummy_inode_listsecurity(struct inode *inode, char *buffer, size_t bu
 	return 0;
 }
 
+static void dummy_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	*secid = 0;
+}
+
 static int dummy_file_permission (struct file *file, int mask)
 {
 	return 0;
@@ -540,7 +545,9 @@ static int dummy_task_getsid (struct task_struct *p)
 }
 
 static void dummy_task_getsecid (struct task_struct *p, u32 *secid)
-{ }
+{
+	*secid = 0;
+}
 
 static int dummy_task_setgroups (struct group_info *group_info)
 {
@@ -614,6 +621,11 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
 	return 0;
 }
 
+static void dummy_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+	*secid = 0;
+}
+
 static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
 {
 	return 0;
@@ -1062,6 +1074,7 @@ void security_fixup_ops (struct security_operations *ops)
 	set_to_dummy_if_null(ops, inode_getsecurity);
 	set_to_dummy_if_null(ops, inode_setsecurity);
 	set_to_dummy_if_null(ops, inode_listsecurity);
+	set_to_dummy_if_null(ops, inode_getsecid);
 	set_to_dummy_if_null(ops, file_permission);
 	set_to_dummy_if_null(ops, file_alloc_security);
 	set_to_dummy_if_null(ops, file_free_security);
@@ -1098,6 +1111,7 @@ void security_fixup_ops (struct security_operations *ops)
 	set_to_dummy_if_null(ops, task_reparent_to_init);
  	set_to_dummy_if_null(ops, task_to_inode);
 	set_to_dummy_if_null(ops, ipc_permission);
+	set_to_dummy_if_null(ops, ipc_getsecid);
 	set_to_dummy_if_null(ops, msg_msg_alloc_security);
 	set_to_dummy_if_null(ops, msg_msg_free_security);
 	set_to_dummy_if_null(ops, msg_queue_alloc_security);
diff --git a/security/security.c b/security/security.c
index 3e75b90..1748329 100644
--- a/security/security.c
+++ b/security/security.c
@@ -516,6 +516,11 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
 	return security_ops->inode_listsecurity(inode, buffer, buffer_size);
 }
 
+void security_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	security_ops->inode_getsecid(inode, secid);
+}
+
 int security_file_permission(struct file *file, int mask)
 {
 	return security_ops->file_permission(file, mask);
@@ -705,6 +710,11 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 	return security_ops->ipc_permission(ipcp, flag);
 }
 
+void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+	security_ops->ipc_getsecid(ipcp, secid);
+}
+
 int security_msg_msg_alloc(struct msg_msg *msg)
 {
 	return security_ops->msg_msg_alloc_security(msg);


-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 70%]

* [PATCH 2/9] SELinux: setup new inode/ipc getsecid hooks
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
  2008-03-01 19:51 70% ` [PATCH 1/9] LSM: Introduce inode_getsecid and ipc_getsecid hooks Ahmed S. Darwish
@ 2008-03-01 19:52 93% ` Ahmed S. Darwish
  2008-03-01 19:54 67% ` [PATCH 3/9] Audit: use new LSM hooks instead of SELinux exports Ahmed S. Darwish
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 19:52 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Setup the new inode_getsecid and ipc_getsecid() LSM hooks
for SELinux.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 hooks.c |   19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f42ebfc..06597d7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2724,6 +2724,12 @@ static int selinux_inode_killpriv(struct dentry *dentry)
 	return secondary_ops->inode_killpriv(dentry);
 }
 
+static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	struct inode_security_struct *isec = inode->i_security;
+	*secid = isec->sid;
+}
+
 /* file security operations */
 
 static int selinux_revalidate_file_permission(struct file *file, int mask)
@@ -3120,7 +3126,8 @@ static int selinux_task_getsid(struct task_struct *p)
 
 static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
 {
-	selinux_get_task_sid(p, secid);
+	struct task_security_struct *tsec = p->security;
+	*secid = tsec->sid;
 }
 
 static int selinux_task_setgroups(struct group_info *group_info)
@@ -4090,7 +4097,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
 		goto out;
 
 	if (sock && family == PF_UNIX)
-		selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
+		selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
 	else if (skb)
 		selinux_skb_peerlbl_sid(skb, family, &peer_secid);
 
@@ -4970,6 +4977,12 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 	return ipc_has_perm(ipcp, av);
 }
 
+static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+	struct ipc_security_struct *isec = ipcp->security;
+	*secid = isec->sid;
+}
+
 /* module stacking operations */
 static int selinux_register_security (const char *name, struct security_operations *ops)
 {
@@ -5292,6 +5305,7 @@ static struct security_operations selinux_ops = {
 	.inode_listsecurity =           selinux_inode_listsecurity,
 	.inode_need_killpriv =		selinux_inode_need_killpriv,
 	.inode_killpriv =		selinux_inode_killpriv,
+	.inode_getsecid =               selinux_inode_getsecid,
 
 	.file_permission =		selinux_file_permission,
 	.file_alloc_security =		selinux_file_alloc_security,
@@ -5332,6 +5346,7 @@ static struct security_operations selinux_ops = {
 	.task_to_inode =                selinux_task_to_inode,
 
 	.ipc_permission =		selinux_ipc_permission,
+	.ipc_getsecid =                 selinux_ipc_getsecid,
 
 	.msg_msg_alloc_security =	selinux_msg_msg_alloc_security,
 	.msg_msg_free_security =	selinux_msg_msg_free_security,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 93%]

* [PATCH 3/9] Audit: use new LSM hooks instead of SELinux exports
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
  2008-03-01 19:51 70% ` [PATCH 1/9] LSM: Introduce inode_getsecid and ipc_getsecid hooks Ahmed S. Darwish
  2008-03-01 19:52 93% ` [PATCH 2/9] SELinux: setup new inode/ipc getsecid hooks Ahmed S. Darwish
@ 2008-03-01 19:54 67% ` Ahmed S. Darwish
  2008-03-01 19:56 98% ` [PATCH 4/9] Netlink: Use generic LSM hook Ahmed S. Darwish
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 19:54 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Stop using the following exported SELinux interfaces:
selinux_get_inode_sid(inode, sid)
selinux_get_ipc_sid(ipcp, sid) 
selinux_get_task_sid(tsk, sid)
selinux_sid_to_string(sid, ctx, len)
kfree(ctx)

and use following generic LSM equivalents respectively:
security_inode_getsecid(inode, secid)
security_ipc_getsecid*(ipcp, secid)
security_task_getsecid(tsk, secid)
security_sid_to_secctx(sid, ctx, len)
security_release_secctx(ctx, len)

Call security_release_secctx only if security_secid_to_secctx
succeeded.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 audit.c       |   17 +++++++++--------
 auditfilter.c |    8 +++++---
 auditsc.c     |   55 +++++++++++++++++++++++++++++--------------------------
 3 files changed, 43 insertions(+), 37 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index 8316a88..d79f866 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -259,13 +259,13 @@ static int audit_log_config_change(char *function_name, int new, int old,
 		char *ctx = NULL;
 		u32 len;
 
-		rc = selinux_sid_to_string(sid, &ctx, &len);
+		rc = security_secid_to_secctx(sid, &ctx, &len);
 		if (rc) {
 			audit_log_format(ab, " sid=%u", sid);
 			allow_changes = 0; /* Something weird, deny request */
 		} else {
 			audit_log_format(ab, " subj=%s", ctx);
-			kfree(ctx);
+			security_release_secctx(ctx, len);
 		}
 	}
 	audit_log_format(ab, " res=%d", allow_changes);
@@ -543,12 +543,13 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
 	audit_log_format(*ab, "user pid=%d uid=%u auid=%u",
 			 pid, uid, auid);
 	if (sid) {
-		rc = selinux_sid_to_string(sid, &ctx, &len);
+		rc = security_secid_to_secctx(sid, &ctx, &len);
 		if (rc)
 			audit_log_format(*ab, " ssid=%u", sid);
-		else
+		else {
 			audit_log_format(*ab, " subj=%s", ctx);
-		kfree(ctx);
+			security_release_secctx(ctx, len);
+		}
 	}
 
 	return rc;
@@ -750,18 +751,18 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 		break;
 	}
 	case AUDIT_SIGNAL_INFO:
-		err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
+		err = security_secid_to_secctx(audit_sig_sid, &ctx, &len);
 		if (err)
 			return err;
 		sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
 		if (!sig_data) {
-			kfree(ctx);
+			security_release_secctx(ctx, len);
 			return -ENOMEM;
 		}
 		sig_data->uid = audit_sig_uid;
 		sig_data->pid = audit_sig_pid;
 		memcpy(sig_data->ctx, ctx, len);
-		kfree(ctx);
+		security_release_secctx(ctx, len);
 		audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO,
 				0, 0, sig_data, sizeof(*sig_data) + len);
 		kfree(sig_data);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 2f2914b..35e58a1 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -28,6 +28,7 @@
 #include <linux/netlink.h>
 #include <linux/sched.h>
 #include <linux/inotify.h>
+#include <linux/security.h>
 #include <linux/selinux.h>
 #include "audit.h"
 
@@ -1515,11 +1516,12 @@ static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
 	if (sid) {
 		char *ctx = NULL;
 		u32 len;
-		if (selinux_sid_to_string(sid, &ctx, &len))
+		if (security_secid_to_secctx(sid, &ctx, &len))
 			audit_log_format(ab, " ssid=%u", sid);
-		else
+		else {
 			audit_log_format(ab, " subj=%s", ctx);
-		kfree(ctx);
+			security_release_secctx(ctx, len);
+		}
 	}
 	audit_log_format(ab, " op=%s rule key=", action);
 	if (rule->filterkey)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d07fc4a..a9fc9dd 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -530,7 +530,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 			   logged upon error */
 			if (f->se_rule) {
 				if (need_sid) {
-					selinux_get_task_sid(tsk, &sid);
+					security_task_getsecid(tsk, &sid);
 					need_sid = 0;
 				}
 				result = selinux_audit_rule_match(sid, f->type,
@@ -885,11 +885,11 @@ void audit_log_task_context(struct audit_buffer *ab)
 	int error;
 	u32 sid;
 
-	selinux_get_task_sid(current, &sid);
+	security_task_getsecid(current, &sid);
 	if (!sid)
 		return;
 
-	error = selinux_sid_to_string(sid, &ctx, &len);
+	error = security_secid_to_secctx(sid, &ctx, &len);
 	if (error) {
 		if (error != -EINVAL)
 			goto error_path;
@@ -897,7 +897,7 @@ void audit_log_task_context(struct audit_buffer *ab)
 	}
 
 	audit_log_format(ab, " subj=%s", ctx);
-	kfree(ctx);
+	security_release_secctx(ctx, len);
 	return;
 
 error_path:
@@ -941,7 +941,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 				 u32 sid, char *comm)
 {
 	struct audit_buffer *ab;
-	char *s = NULL;
+	char *ctx = NULL;
 	u32 len;
 	int rc = 0;
 
@@ -951,15 +951,16 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 
 	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
 			 uid, sessionid);
-	if (selinux_sid_to_string(sid, &s, &len)) {
+	if (security_secid_to_secctx(sid, &ctx, &len)) {
 		audit_log_format(ab, " obj=(none)");
 		rc = 1;
-	} else
-		audit_log_format(ab, " obj=%s", s);
+	} else {
+		audit_log_format(ab, " obj=%s", ctx);
+		security_release_secctx(ctx, len);
+	}
 	audit_log_format(ab, " ocomm=");
 	audit_log_untrustedstring(ab, comm);
 	audit_log_end(ab);
-	kfree(s);
 
 	return rc;
 }
@@ -1268,14 +1269,15 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 			if (axi->osid != 0) {
 				char *ctx = NULL;
 				u32 len;
-				if (selinux_sid_to_string(
+				if (security_secid_to_secctx(
 						axi->osid, &ctx, &len)) {
 					audit_log_format(ab, " osid=%u",
 							axi->osid);
 					call_panic = 1;
-				} else
+				} else {
 					audit_log_format(ab, " obj=%s", ctx);
-				kfree(ctx);
+					security_release_secctx(ctx, len);
+				}
 			}
 			break; }
 
@@ -1389,13 +1391,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 		if (n->osid != 0) {
 			char *ctx = NULL;
 			u32 len;
-			if (selinux_sid_to_string(
+			if (security_secid_to_secctx(
 				n->osid, &ctx, &len)) {
 				audit_log_format(ab, " osid=%u", n->osid);
 				call_panic = 2;
-			} else
+			} else {
 				audit_log_format(ab, " obj=%s", ctx);
-			kfree(ctx);
+				security_release_secctx(ctx, len);
+			}
 		}
 
 		audit_log_end(ab);
@@ -1772,7 +1775,7 @@ static void audit_copy_inode(struct audit_names *name, const struct inode *inode
 	name->uid   = inode->i_uid;
 	name->gid   = inode->i_gid;
 	name->rdev  = inode->i_rdev;
-	selinux_get_inode_sid(inode, &name->osid);
+	security_inode_getsecid(inode, &name->osid);
 }
 
 /**
@@ -2187,8 +2190,7 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp)
 	ax->uid = ipcp->uid;
 	ax->gid = ipcp->gid;
 	ax->mode = ipcp->mode;
-	selinux_get_ipc_sid(ipcp, &ax->osid);
-
+	security_ipc_getsecid(ipcp, &ax->osid);
 	ax->d.type = AUDIT_IPC;
 	ax->d.next = context->aux;
 	context->aux = (void *)ax;
@@ -2340,7 +2342,7 @@ void __audit_ptrace(struct task_struct *t)
 	context->target_auid = audit_get_loginuid(t);
 	context->target_uid = t->uid;
 	context->target_sessionid = audit_get_sessionid(t);
-	selinux_get_task_sid(t, &context->target_sid);
+	security_task_getsecid(t, &context->target_sid);
 	memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
 }
 
@@ -2368,7 +2370,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 				audit_sig_uid = tsk->loginuid;
 			else
 				audit_sig_uid = tsk->uid;
-			selinux_get_task_sid(tsk, &audit_sig_sid);
+			security_task_getsecid(tsk, &audit_sig_sid);
 		}
 		if (!audit_signals || audit_dummy_context())
 			return 0;
@@ -2381,7 +2383,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 		ctx->target_auid = audit_get_loginuid(t);
 		ctx->target_uid = t->uid;
 		ctx->target_sessionid = audit_get_sessionid(t);
-		selinux_get_task_sid(t, &ctx->target_sid);
+		security_task_getsecid(t, &ctx->target_sid);
 		memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
 		return 0;
 	}
@@ -2402,7 +2404,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 	axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
 	axp->target_uid[axp->pid_count] = t->uid;
 	axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
-	selinux_get_task_sid(t, &axp->target_sid[axp->pid_count]);
+	security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
 	memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
 	axp->pid_count++;
 
@@ -2432,16 +2434,17 @@ void audit_core_dumps(long signr)
 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
 	audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
 			auid, current->uid, current->gid, sessionid);
-	selinux_get_task_sid(current, &sid);
+	security_task_getsecid(current, &sid);
 	if (sid) {
 		char *ctx = NULL;
 		u32 len;
 
-		if (selinux_sid_to_string(sid, &ctx, &len))
+		if (security_secid_to_secctx(sid, &ctx, &len))
 			audit_log_format(ab, " ssid=%u", sid);
-		else
+		else {
 			audit_log_format(ab, " subj=%s", ctx);
-		kfree(ctx);
+			security_release_secctx(ctx, len);
+		}
 	}
 	audit_log_format(ab, " pid=%d comm=", current->pid);
 	audit_log_untrustedstring(ab, current->comm);

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 67%]

* [PATCH 4/9] Netlink: Use generic LSM hook
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
                   ` (2 preceding siblings ...)
  2008-03-01 19:54 67% ` [PATCH 3/9] Audit: use new LSM hooks instead of SELinux exports Ahmed S. Darwish
@ 2008-03-01 19:56 98% ` Ahmed S. Darwish
  2008-03-01 19:58 81% ` [PATCH 5/9] SELinux: remove redundant exports Ahmed S. Darwish
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 19:56 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Don't use SELinux exported selinux_get_task_sid symbol. 
Use the generic LSM equivalent instead.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1ab0da2..61fd277 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -54,7 +54,6 @@
 #include <linux/mm.h>
 #include <linux/types.h>
 #include <linux/audit.h>
-#include <linux/selinux.h>
 #include <linux/mutex.h>
 
 #include <net/net_namespace.h>
@@ -1239,7 +1238,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
 	NETLINK_CB(skb).pid	= nlk->pid;
 	NETLINK_CB(skb).dst_group = dst_group;
 	NETLINK_CB(skb).loginuid = audit_get_loginuid(current);
-	selinux_get_task_sid(current, &(NETLINK_CB(skb).sid));
+	security_task_getsecid(current, &(NETLINK_CB(skb).sid));
 	memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
 
 	/* What can I do? Netlink is asynchronous, so that

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 98%]

* [PATCH 5/9] SELinux: remove redundant exports
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
                   ` (3 preceding siblings ...)
  2008-03-01 19:56 98% ` [PATCH 4/9] Netlink: Use generic LSM hook Ahmed S. Darwish
@ 2008-03-01 19:58 81% ` Ahmed S. Darwish
  2008-03-01 20:00 75% ` [PATCH 6/9] LSM/Audit: Introduce generic Audit LSM hooks Ahmed S. Darwish
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 19:58 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Remove the following exported SELinux interfaces:
selinux_get_inode_sid(inode, sid)
selinux_get_ipc_sid(ipcp, sid) 
selinux_get_task_sid(tsk, sid)
selinux_sid_to_string(sid, ctx, len)

They can be substitued with the following generic equivalents 
respectively:
new LSM hook, inode_getsecid(inode, secid)
new LSM hook, ipc_getsecid*(ipcp, secid)
LSM hook, task_getsecid(tsk, secid)
LSM hook, sid_to_secctx(sid, ctx, len)

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 include/linux/selinux.h    |   62 ---------------------------------------------
 security/selinux/exports.c |   42 ------------------------------
 2 files changed, 104 deletions(-)

diff --git a/include/linux/selinux.h b/include/linux/selinux.h
index 8c2cc4c..24b0af1 100644
--- a/include/linux/selinux.h
+++ b/include/linux/selinux.h
@@ -16,7 +16,6 @@
 
 struct selinux_audit_rule;
 struct audit_context;
-struct inode;
 struct kern_ipc_perm;
 
 #ifdef CONFIG_SECURITY_SELINUX
@@ -70,45 +69,6 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
 void selinux_audit_set_callback(int (*callback)(void));
 
 /**
- *     selinux_sid_to_string - map a security context ID to a string
- *     @sid: security context ID to be converted.
- *     @ctx: address of context string to be returned
- *     @ctxlen: length of returned context string.
- *
- *     Returns 0 if successful, -errno if not.  On success, the context
- *     string will be allocated internally, and the caller must call
- *     kfree() on it after use.
- */
-int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen);
-
-/**
- *     selinux_get_inode_sid - get the inode's security context ID
- *     @inode: inode structure to get the sid from.
- *     @sid: pointer to security context ID to be filled in.
- *
- *     Returns nothing
- */
-void selinux_get_inode_sid(const struct inode *inode, u32 *sid);
-
-/**
- *     selinux_get_ipc_sid - get the ipc security context ID
- *     @ipcp: ipc structure to get the sid from.
- *     @sid: pointer to security context ID to be filled in.
- *
- *     Returns nothing
- */
-void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid);
-
-/**
- *     selinux_get_task_sid - return the SID of task
- *     @tsk: the task whose SID will be returned
- *     @sid: pointer to security context ID to be filled in.
- *
- *     Returns nothing
- */
-void selinux_get_task_sid(struct task_struct *tsk, u32 *sid);
-
-/**
  *     selinux_string_to_sid - map a security context string to a security ID
  *     @str: the security context string to be mapped
  *     @sid: ID value returned via this.
@@ -175,28 +135,6 @@ static inline void selinux_audit_set_callback(int (*callback)(void))
 	return;
 }
 
-static inline int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
-{
-       *ctx = NULL;
-       *ctxlen = 0;
-       return 0;
-}
-
-static inline void selinux_get_inode_sid(const struct inode *inode, u32 *sid)
-{
-	*sid = 0;
-}
-
-static inline void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid)
-{
-	*sid = 0;
-}
-
-static inline void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
-{
-	*sid = 0;
-}
-
 static inline int selinux_string_to_sid(const char *str, u32 *sid)
 {
        *sid = 0;
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index 87d2bb3..64af2d3 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -25,48 +25,6 @@
 /* SECMARK reference count */
 extern atomic_t selinux_secmark_refcount;
 
-int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
-{
-	if (selinux_enabled)
-		return security_sid_to_context(sid, ctx, ctxlen);
-	else {
-		*ctx = NULL;
-		*ctxlen = 0;
-	}
-
-	return 0;
-}
-
-void selinux_get_inode_sid(const struct inode *inode, u32 *sid)
-{
-	if (selinux_enabled) {
-		struct inode_security_struct *isec = inode->i_security;
-		*sid = isec->sid;
-		return;
-	}
-	*sid = 0;
-}
-
-void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid)
-{
-	if (selinux_enabled) {
-		struct ipc_security_struct *isec = ipcp->security;
-		*sid = isec->sid;
-		return;
-	}
-	*sid = 0;
-}
-
-void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
-{
-	if (selinux_enabled) {
-		struct task_security_struct *tsec = tsk->security;
-		*sid = tsec->sid;
-		return;
-	}
-	*sid = 0;
-}
-
 int selinux_string_to_sid(char *str, u32 *sid)
 {
 	if (selinux_enabled)

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 81%]

* [PATCH 6/9] LSM/Audit: Introduce generic Audit LSM hooks
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
                   ` (4 preceding siblings ...)
  2008-03-01 19:58 81% ` [PATCH 5/9] SELinux: remove redundant exports Ahmed S. Darwish
@ 2008-03-01 20:00 75% ` Ahmed S. Darwish
  2008-03-01 20:01 63% ` [PATCH 7/9] Audit: internally use the new LSM audit hooks Ahmed S. Darwish
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 20:00 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Introduce a generic Audit interface for security modules
by adding the following new LSM hooks:

audit_rule_init(field, op, rulestr, lsmrule)
audit_rule_known(krule)
audit_rule_match(secid, field, op, rule, actx)
audit_rule_free(rule)

Those hooks are only available if CONFIG_AUDIT is enabled.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 include/linux/security.h |   72 +++++++++++++++++++++++++++++++++++++++++++++++
 security/dummy.c         |   31 +++++++++++++++++++-
 security/security.c      |   25 ++++++++++++++++
 3 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index b5d1ad7..eb663e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -43,6 +43,7 @@
 extern unsigned securebits;
 
 struct ctl_table;
+struct audit_krule;
 
 /*
  * These functions are in security/capability.c and are used
@@ -1227,6 +1228,37 @@ struct request_sock;
  *	@secdata contains the security context.
  *	@seclen contains the length of the security context.
  *
+ * Security hooks for Audit
+ *
+ * @audit_rule_init:
+ *	Allocate and initialize an LSM audit rule structure.
+ *	@field contains the required Audit action. Fields flags are defined in include/linux/audit.h
+ *	@op contains the operator the rule uses.
+ *	@rulestr contains the context where the rule will be applied to.
+ *	@lsmrule contains a pointer to receive the result.
+ *	Return 0 if @lsmrule has been successfully set,
+ *	-EINVAL in case of an invalid rule.
+ *
+ * @audit_rule_known:
+ *	Specifies whether given @rule contains any fields related to current LSM.
+ *	@rule contains the audit rule of interest.
+ *	Return 1 in case of relation found, 0 otherwise.
+ *
+ * @audit_rule_match:
+ *	Determine if given @secid matches a rule previously approved
+ *	by @audit_rule_known.
+ *	@secid contains the security id in question.
+ *	@field contains the field which relates to current LSM.
+ *	@op contains the operator that will be used for matching.
+ *	@rule points to the audit rule that will be checked against.
+ *	@actx points to the audit context associated with the check.
+ *	Return 1 if secid matches the rule, 0 if it does not, -ERRNO on failure.
+ *
+ * @audit_rule_free:
+ *	Deallocate the LSM audit rule structure previously allocated by
+ *	audit_rule_init.
+ *	@rule contains the allocated rule
+ *
  * This is the main security structure.
  */
 struct security_operations {
@@ -1487,6 +1519,13 @@ struct security_operations {
 	int (*key_getsecurity)(struct key *key, char **_buffer);
 #endif	/* CONFIG_KEYS */
 
+#ifdef CONFIG_AUDIT
+	int (*audit_rule_init)(u32 field, u32 op, char *rulestr, void **lsmrule);
+	int (*audit_rule_known)(struct audit_krule *krule);
+	int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule,
+				struct audit_context *actx);
+	void (*audit_rule_free)(void *lsmrule);
+#endif /* CONFIG_AUDIT */
 };
 
 /* prototypes */
@@ -2670,5 +2709,38 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
 #endif
 #endif /* CONFIG_KEYS */
 
+#ifdef CONFIG_AUDIT
+#ifdef CONFIG_SECURITY
+int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
+int security_audit_rule_known(struct audit_krule *krule);
+int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
+			      struct audit_context *actx);
+void security_audit_rule_free(void *lsmrule);
+
+#else
+
+static inline int security_audit_rule_init(u32 field, u32 op, char *rulestr,
+					   void **lsmrule)
+{
+	return 0;
+}
+
+static inline int security_audit_rule_known(struct audit_krule *krule)
+{
+	return 0;
+}
+
+static inline int security_audit_rule_match(u32 secid, u32 field, u32 op,
+				   void *lsmrule, struct audit_context *actx)
+{
+	return 0;
+}
+
+static inline void security_audit_rule_free(void *lsmrule)
+{ }
+
+#endif /* CONFIG_SECURITY */
+#endif /* CONFIG_AUDIT */
+
 #endif /* ! __LINUX_SECURITY_H */
 
diff --git a/security/dummy.c b/security/dummy.c
index b4967f4..241ab20 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -998,6 +998,30 @@ static int dummy_key_getsecurity(struct key *key, char **_buffer)
 
 #endif /* CONFIG_KEYS */
 
+#ifdef CONFIG_AUDIT
+static inline int dummy_audit_rule_init(u32 field, u32 op, char *rulestr,
+					void **lsmrule)
+{
+	return 0;
+}
+
+static inline int dummy_audit_rule_known(struct audit_krule *krule)
+{
+	return 0;
+}
+
+static inline int dummy_audit_rule_match(u32 secid, u32 field, u32 op,
+					 void *lsmrule,
+					 struct audit_context *actx)
+{
+	return 0;
+}
+
+static inline void dummy_audit_rule_free(void *lsmrule)
+{ }
+
+#endif /* CONFIG_AUDIT */
+
 struct security_operations dummy_security_ops;
 
 #define set_to_dummy_if_null(ops, function)				\
@@ -1187,6 +1211,11 @@ void security_fixup_ops (struct security_operations *ops)
 	set_to_dummy_if_null(ops, key_permission);
 	set_to_dummy_if_null(ops, key_getsecurity);
 #endif	/* CONFIG_KEYS */
-
+#ifdef CONFIG_AUDIT
+	set_to_dummy_if_null(ops, audit_rule_init);
+	set_to_dummy_if_null(ops, audit_rule_known);
+	set_to_dummy_if_null(ops, audit_rule_match);
+	set_to_dummy_if_null(ops, audit_rule_free);
+#endif
 }
 
diff --git a/security/security.c b/security/security.c
index 1748329..1bf2ee4 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1118,3 +1118,28 @@ int security_key_getsecurity(struct key *key, char **_buffer)
 }
 
 #endif	/* CONFIG_KEYS */
+
+#ifdef CONFIG_AUDIT
+
+int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
+{
+	return security_ops->audit_rule_init(field, op, rulestr, lsmrule);
+}
+
+int security_audit_rule_known(struct audit_krule *krule)
+{
+	return security_ops->audit_rule_known(krule);
+}
+
+void security_audit_rule_free(void *lsmrule)
+{
+	security_ops->audit_rule_free(lsmrule);
+}
+
+int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
+			      struct audit_context *actx)
+{
+	return security_ops->audit_rule_match(secid, field, op, lsmrule, actx);
+}
+
+#endif /* CONFIG_AUDIT */

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 75%]

* [PATCH 7/9] Audit: internally use the new LSM audit hooks
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
                   ` (5 preceding siblings ...)
  2008-03-01 20:00 75% ` [PATCH 6/9] LSM/Audit: Introduce generic Audit LSM hooks Ahmed S. Darwish
@ 2008-03-01 20:01 63% ` Ahmed S. Darwish
    2008-03-01 20:03 57% ` [PATCH 8/9] SELinux: use new audit hooks, remove redundant exports Ahmed S. Darwish
  2008-03-01 20:05 71% ` [PATCH 9/9] Audit: Final renamings and cleanup Ahmed S. Darwish
  8 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 20:01 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Convert Audit to use the new LSM Audit hooks instead of
the exported SELinux interface.

Basically, use:
security_audit_rule_init
secuirty_audit_rule_free
security_audit_rule_known
security_audit_rule_match

instad of (respectively) :
selinux_audit_rule_init
selinux_audit_rule_free
audit_rule_has_selinux
selinux_audit_rule_match

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 audit.c       |    7 ------
 auditfilter.c |   61 ++++++++++++++++------------------------------------------
 auditsc.c     |    9 +++-----
 3 files changed, 22 insertions(+), 55 deletions(-)

Andrew, please atomically merge patch #7 and patch #8. Although
a system with patch7 and without patch8 will be compiled fine,
the SELinux Audit hooks are not set up yet. This means below
audit hooks will point to the dummy hooks instead of SELinux
ones even if SELinux is enabled.

I could not setup the SELinux hooks first cause they have
the same name of the old exported SELinux interface with a 
difference of one parameter.

Thanks!

diff --git a/kernel/audit.c b/kernel/audit.c
index d79f866..40c3507 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -21,7 +21,7 @@
  *
  * Written by Rickard E. (Rik) Faith <faith@redhat.com>
  *
- * Goals: 1) Integrate fully with SELinux.
+ * Goals: 1) Integrate fully with Security Modules.
  *	  2) Minimal run-time overhead:
  *	     a) Minimal when syscall auditing is disabled (audit_enable=0).
  *	     b) Small when syscall auditing is enabled and no audit record
@@ -55,7 +55,6 @@
 #include <net/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
-#include <linux/selinux.h>
 #include <linux/inotify.h>
 #include <linux/freezer.h>
 #include <linux/tty.h>
@@ -874,10 +873,6 @@ static int __init audit_init(void)
 	audit_enabled = audit_default;
 	audit_ever_enabled |= !!audit_default;
 
-	/* Register the callback with selinux.  This callback will be invoked
-	 * when a new policy is loaded. */
-	selinux_audit_set_callback(&selinux_audit_rule_update);
-
 	audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
 
 #ifdef CONFIG_AUDITSYSCALL
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 35e58a1..7c69cb5 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -29,7 +29,6 @@
 #include <linux/sched.h>
 #include <linux/inotify.h>
 #include <linux/security.h>
-#include <linux/selinux.h>
 #include "audit.h"
 
 /*
@@ -39,7 +38,7 @@
  * 		Synchronizes writes and blocking reads of audit's filterlist
  * 		data.  Rcu is used to traverse the filterlist and access
  * 		contents of structs audit_entry, audit_watch and opaque
- * 		selinux rules during filtering.  If modified, these structures
+ * 		LSM rules during filtering.  If modified, these structures
  * 		must be copied and replace their counterparts in the filterlist.
  * 		An audit_parent struct is not accessed during filtering, so may
  * 		be written directly provided audit_filter_mutex is held.
@@ -141,7 +140,7 @@ static inline void audit_free_rule(struct audit_entry *e)
 		for (i = 0; i < e->rule.field_count; i++) {
 			struct audit_field *f = &e->rule.fields[i];
 			kfree(f->se_str);
-			selinux_audit_rule_free(f->se_rule);
+			security_audit_rule_free(f->se_rule);
 		}
 	kfree(e->rule.fields);
 	kfree(e->rule.filterkey);
@@ -598,12 +597,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 				goto exit_free;
 			entry->rule.buflen += f->val;
 
-			err = selinux_audit_rule_init(f->type, f->op, str,
-						      &f->se_rule);
+			err = security_audit_rule_init(f->type, f->op, str,
+						       (void **)&f->se_rule);
 			/* Keep currently invalid fields around in case they
 			 * become valid after a policy reload. */
 			if (err == -EINVAL) {
-				printk(KERN_WARNING "audit rule for selinux "
+				printk(KERN_WARNING "audit rule for LSM "
 				       "\'%s\' is invalid\n",  str);
 				err = 0;
 			}
@@ -863,9 +862,9 @@ out:
 	return new;
 }
 
-/* Duplicate selinux field information.  The se_rule is opaque, so must be
+/* Duplicate LSM field information.  The se_rule is opaque, so must be
  * re-initialized. */
-static inline int audit_dupe_selinux_field(struct audit_field *df,
+static inline int audit_dupe_lsm_field(struct audit_field *df,
 					   struct audit_field *sf)
 {
 	int ret = 0;
@@ -878,12 +877,12 @@ static inline int audit_dupe_selinux_field(struct audit_field *df,
 	df->se_str = se_str;
 
 	/* our own (refreshed) copy of se_rule */
-	ret = selinux_audit_rule_init(df->type, df->op, df->se_str,
-				      &df->se_rule);
+	ret = security_audit_rule_init(df->type, df->op, df->se_str,
+				       (void **)&df->se_rule);
 	/* Keep currently invalid fields around in case they
 	 * become valid after a policy reload. */
 	if (ret == -EINVAL) {
-		printk(KERN_WARNING "audit rule for selinux \'%s\' is "
+		printk(KERN_WARNING "audit rule for LSM \'%s\' is "
 		       "invalid\n", df->se_str);
 		ret = 0;
 	}
@@ -892,7 +891,7 @@ static inline int audit_dupe_selinux_field(struct audit_field *df,
 }
 
 /* Duplicate an audit rule.  This will be a deep copy with the exception
- * of the watch - that pointer is carried over.  The selinux specific fields
+ * of the watch - that pointer is carried over.  The LSM specific fields
  * will be updated in the copy.  The point is to be able to replace the old
  * rule with the new rule in the filterlist, then free the old rule.
  * The rlist element is undefined; list manipulations are handled apart from
@@ -945,7 +944,7 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
 		case AUDIT_OBJ_TYPE:
 		case AUDIT_OBJ_LEV_LOW:
 		case AUDIT_OBJ_LEV_HIGH:
-			err = audit_dupe_selinux_field(&new->fields[i],
+			err = audit_dupe_lsm_field(&new->fields[i],
 						       &old->fields[i]);
 			break;
 		case AUDIT_FILTERKEY:
@@ -1763,38 +1762,12 @@ unlock_and_return:
 	return result;
 }
 
-/* Check to see if the rule contains any selinux fields.  Returns 1 if there
-   are selinux fields specified in the rule, 0 otherwise. */
-static inline int audit_rule_has_selinux(struct audit_krule *rule)
-{
-	int i;
-
-	for (i = 0; i < rule->field_count; i++) {
-		struct audit_field *f = &rule->fields[i];
-		switch (f->type) {
-		case AUDIT_SUBJ_USER:
-		case AUDIT_SUBJ_ROLE:
-		case AUDIT_SUBJ_TYPE:
-		case AUDIT_SUBJ_SEN:
-		case AUDIT_SUBJ_CLR:
-		case AUDIT_OBJ_USER:
-		case AUDIT_OBJ_ROLE:
-		case AUDIT_OBJ_TYPE:
-		case AUDIT_OBJ_LEV_LOW:
-		case AUDIT_OBJ_LEV_HIGH:
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
 /* This function will re-initialize the se_rule field of all applicable rules.
- * It will traverse the filter lists serarching for rules that contain selinux
+ * It will traverse the filter lists serarching for rules that contain LSM
  * specific filter fields.  When such a rule is found, it is copied, the
- * selinux field is re-initialized, and the old rule is replaced with the
+ * LSM field is re-initialized, and the old rule is replaced with the
  * updated rule. */
-int selinux_audit_rule_update(void)
+int audit_update_lsm_rules(void)
 {
 	struct audit_entry *entry, *n, *nentry;
 	struct audit_watch *watch;
@@ -1806,7 +1779,7 @@ int selinux_audit_rule_update(void)
 
 	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
 		list_for_each_entry_safe(entry, n, &audit_filter_list[i], list) {
-			if (!audit_rule_has_selinux(&entry->rule))
+			if (!security_audit_rule_known(&entry->rule))
 				continue;
 
 			watch = entry->rule.watch;
@@ -1817,7 +1790,7 @@ int selinux_audit_rule_update(void)
 				 * return value */
 				if (!err)
 					err = PTR_ERR(nentry);
-				audit_panic("error updating selinux filters");
+				audit_panic("error updating LSM filters");
 				if (watch)
 					list_del(&entry->rule.rlist);
 				list_del_rcu(&entry->list);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index a9fc9dd..8afd349 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -61,7 +61,6 @@
 #include <linux/security.h>
 #include <linux/list.h>
 #include <linux/tty.h>
-#include <linux/selinux.h>
 #include <linux/binfmts.h>
 #include <linux/highmem.h>
 #include <linux/syscalls.h>
@@ -533,7 +532,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 					security_task_getsecid(tsk, &sid);
 					need_sid = 0;
 				}
-				result = selinux_audit_rule_match(sid, f->type,
+				result = security_audit_rule_match(sid, f->type,
 				                                  f->op,
 				                                  f->se_rule,
 				                                  ctx);
@@ -549,12 +548,12 @@ static int audit_filter_rules(struct task_struct *tsk,
 			if (f->se_rule) {
 				/* Find files that match */
 				if (name) {
-					result = selinux_audit_rule_match(
+					result = security_audit_rule_match(
 					           name->osid, f->type, f->op,
 					           f->se_rule, ctx);
 				} else if (ctx) {
 					for (j = 0; j < ctx->name_count; j++) {
-						if (selinux_audit_rule_match(
+						if (security_audit_rule_match(
 						      ctx->names[j].osid,
 						      f->type, f->op,
 						      f->se_rule, ctx)) {
@@ -570,7 +569,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 					     aux = aux->next) {
 						if (aux->type == AUDIT_IPC) {
 							struct audit_aux_data_ipcctl *axi = (void *)aux;
-							if (selinux_audit_rule_match(axi->osid, f->type, f->op, f->se_rule, ctx)) {
+							if (security_audit_rule_match(axi->osid, f->type, f->op, f->se_rule, ctx)) {
 								++result;
 								break;
 							}

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 63%]

* [PATCH 8/9] SELinux: use new audit hooks, remove redundant exports
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
                   ` (6 preceding siblings ...)
  2008-03-01 20:01 63% ` [PATCH 7/9] Audit: internally use the new LSM audit hooks Ahmed S. Darwish
@ 2008-03-01 20:03 57% ` Ahmed S. Darwish
  2008-03-01 20:05 71% ` [PATCH 9/9] Audit: Final renamings and cleanup Ahmed S. Darwish
  8 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 20:03 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Setup the new Audit LSM hooks for SELinux.
Remove the now redundant exported SELinux Audit interface.

Audit: Export 'audit_krule' and 'audit_field' to the public 
since their internals are needed by the implementation of the
new LSM hook 'audit_rule_known'.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 include/linux/audit.h            |   29 +++++++++++++++
 include/linux/selinux.h          |   72 ---------------------------------------
 kernel/audit.h                   |   25 -------------
 security/selinux/hooks.c         |    8 ++++
 security/selinux/include/audit.h |   65 +++++++++++++++++++++++++++++++++++
 security/selinux/ss/services.c   |   44 +++++++++++++++++------
 6 files changed, 135 insertions(+), 108 deletions(-)

diff --git a/include/linux/selinux.h b/include/linux/selinux.h
index 24b0af1..20f965d 100644
--- a/include/linux/selinux.h
+++ b/include/linux/selinux.h
@@ -21,54 +21,6 @@ struct kern_ipc_perm;
 #ifdef CONFIG_SECURITY_SELINUX
 
 /**
- *	selinux_audit_rule_init - alloc/init an selinux audit rule structure.
- *	@field: the field this rule refers to
- *	@op: the operater the rule uses
- *	@rulestr: the text "target" of the rule
- *	@rule: pointer to the new rule structure returned via this
- *
- *	Returns 0 if successful, -errno if not.  On success, the rule structure
- *	will be allocated internally.  The caller must free this structure with
- *	selinux_audit_rule_free() after use.
- */
-int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
-                            struct selinux_audit_rule **rule);
-
-/**
- *	selinux_audit_rule_free - free an selinux audit rule structure.
- *	@rule: pointer to the audit rule to be freed
- *
- *	This will free all memory associated with the given rule.
- *	If @rule is NULL, no operation is performed.
- */
-void selinux_audit_rule_free(struct selinux_audit_rule *rule);
-
-/**
- *	selinux_audit_rule_match - determine if a context ID matches a rule.
- *	@sid: the context ID to check
- *	@field: the field this rule refers to
- *	@op: the operater the rule uses
- *	@rule: pointer to the audit rule to check against
- *	@actx: the audit context (can be NULL) associated with the check
- *
- *	Returns 1 if the context id matches the rule, 0 if it does not, and
- *	-errno on failure.
- */
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
-                             struct selinux_audit_rule *rule,
-                             struct audit_context *actx);
-
-/**
- *	selinux_audit_set_callback - set the callback for policy reloads.
- *	@callback: the function to call when the policy is reloaded
- *
- *	This sets the function callback function that will update the rules
- *	upon policy reloads.  This callback should rebuild all existing rules
- *	using selinux_audit_rule_init().
- */
-void selinux_audit_set_callback(int (*callback)(void));
-
-/**
  *     selinux_string_to_sid - map a security context string to a security ID
  *     @str: the security context string to be mapped
  *     @sid: ID value returned via this.
@@ -111,30 +63,6 @@ void selinux_secmark_refcount_inc(void);
 void selinux_secmark_refcount_dec(void);
 #else
 
-static inline int selinux_audit_rule_init(u32 field, u32 op,
-                                          char *rulestr,
-                                          struct selinux_audit_rule **rule)
-{
-	return -EOPNOTSUPP;
-}
-
-static inline void selinux_audit_rule_free(struct selinux_audit_rule *rule)
-{
-	return;
-}
-
-static inline int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
-                                           struct selinux_audit_rule *rule,
-                                           struct audit_context *actx)
-{
-	return 0;
-}
-
-static inline void selinux_audit_set_callback(int (*callback)(void))
-{
-	return;
-}
-
 static inline int selinux_string_to_sid(const char *str, u32 *sid)
 {
        *sid = 0;
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
new file mode 100644
index 0000000..6c8b9ef
--- /dev/null
+++ b/security/selinux/include/audit.h
@@ -0,0 +1,65 @@
+/*
+ * SELinux support for the Audit LSM hooks
+ *
+ * Most of below header was moved from include/linux/selinux.h which 
+ * is released under below copyrights:
+ *
+ * Author: James Morris <jmorris@redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef _SELINUX_AUDIT_H
+#define _SELINUX_AUDIT_H
+
+/**
+ *	selinux_audit_rule_init - alloc/init an selinux audit rule structure.
+ *	@field: the field this rule refers to
+ *	@op: the operater the rule uses
+ *	@rulestr: the text "target" of the rule
+ *	@rule: pointer to the new rule structure returned via this
+ *
+ *	Returns 0 if successful, -errno if not.  On success, the rule structure
+ *	will be allocated internally.  The caller must free this structure with
+ *	selinux_audit_rule_free() after use.
+ */
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule);
+
+/**
+ *	selinux_audit_rule_free - free an selinux audit rule structure.
+ *	@rule: pointer to the audit rule to be freed
+ *
+ *	This will free all memory associated with the given rule.
+ *	If @rule is NULL, no operation is performed.
+ */
+void selinux_audit_rule_free(void *rule);
+
+/**
+ *	selinux_audit_rule_match - determine if a context ID matches a rule.
+ *	@sid: the context ID to check
+ *	@field: the field this rule refers to
+ *	@op: the operater the rule uses
+ *	@rule: pointer to the audit rule to check against
+ *	@actx: the audit context (can be NULL) associated with the check
+ *
+ *	Returns 1 if the context id matches the rule, 0 if it does not, and
+ *	-errno on failure.
+ */
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule,
+                             struct audit_context *actx);
+
+/**
+ *	selinux_audit_rule_known - check to see if rule contains selinux fields.
+ *	@rule: rule to be checked
+ *	Returns 1 if there are selinux fields specified in the rule, 0 otherwise.
+ */
+int selinux_audit_rule_known(struct audit_krule *krule);
+
+#endif /* _SELINUX_AUDIT_H */
+
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 06597d7..bef1834 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -82,6 +82,7 @@
 #include "netnode.h"
 #include "xfrm.h"
 #include "netlabel.h"
+#include "audit.h"
 
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
@@ -5429,6 +5430,13 @@ static struct security_operations selinux_ops = {
 	.key_permission =		selinux_key_permission,
 	.key_getsecurity =		selinux_key_getsecurity,
 #endif
+
+#ifdef CONFIG_AUDIT
+	.audit_rule_init =		selinux_audit_rule_init,
+	.audit_rule_known =		selinux_audit_rule_known,
+	.audit_rule_match =		selinux_audit_rule_match,
+	.audit_rule_free =		selinux_audit_rule_free,
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index f374186..7094623 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -56,6 +56,7 @@
 #include "netlabel.h"
 #include "xfrm.h"
 #include "ebitmap.h"
+#include "audit.h"
 
 extern void selnl_notify_policyload(u32 seqno);
 unsigned int policydb_loaded_version;
@@ -2271,21 +2272,23 @@ struct selinux_audit_rule {
 	struct context au_ctxt;
 };
 
-void selinux_audit_rule_free(struct selinux_audit_rule *rule)
+void selinux_audit_rule_free(void *vrule)
 {
+	struct selinux_audit_rule *rule = vrule;
+
 	if (rule) {
 		context_destroy(&rule->au_ctxt);
 		kfree(rule);
 	}
 }
 
-int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
-                            struct selinux_audit_rule **rule)
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
 {
 	struct selinux_audit_rule *tmprule;
 	struct role_datum *roledatum;
 	struct type_datum *typedatum;
 	struct user_datum *userdatum;
+	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
 	int rc = 0;
 
 	*rule = NULL;
@@ -2372,12 +2375,37 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
 	return rc;
 }
 
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
-                             struct selinux_audit_rule *rule,
+/* Check to see if the rule contains any selinux fields */
+int selinux_audit_rule_known(struct audit_krule *rule)
+{
+	int i;
+
+	for (i = 0; i < rule->field_count; i++) {
+		struct audit_field *f = &rule->fields[i];
+		switch (f->type) {
+		case AUDIT_SUBJ_USER:
+		case AUDIT_SUBJ_ROLE:
+		case AUDIT_SUBJ_TYPE:
+		case AUDIT_SUBJ_SEN:
+		case AUDIT_SUBJ_CLR:
+		case AUDIT_OBJ_USER:
+		case AUDIT_OBJ_ROLE:
+		case AUDIT_OBJ_TYPE:
+		case AUDIT_OBJ_LEV_LOW:
+		case AUDIT_OBJ_LEV_HIGH:
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
                              struct audit_context *actx)
 {
 	struct context *ctxt;
 	struct mls_level *level;
+	struct selinux_audit_rule *rule = vrule;
 	int match = 0;
 
 	if (!rule) {
@@ -2484,7 +2512,7 @@ out:
 	return match;
 }
 
-static int (*aurule_callback)(void) = NULL;
+static int (*aurule_callback)(void) = audit_update_lsm_rules;
 
 static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
                                u16 class, u32 perms, u32 *retained)
@@ -2509,11 +2537,6 @@ static int __init aurule_init(void)
 }
 __initcall(aurule_init);
 
-void selinux_audit_set_callback(int (*callback)(void))
-{
-	aurule_callback = callback;
-}
-
 #ifdef CONFIG_NETLABEL
 /**
  * security_netlbl_cache_add - Add an entry to the NetLabel cache
diff --git a/kernel/audit.h b/kernel/audit.h
index 2554bd5..3cfc54e 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -65,34 +65,9 @@ struct audit_watch {
 	struct list_head	rules;	/* associated rules */
 };
 
-struct audit_field {
-	u32				type;
-	u32				val;
-	u32				op;
-	char				*se_str;
-	struct selinux_audit_rule	*se_rule;
-};
-
 struct audit_tree;
 struct audit_chunk;
 
-struct audit_krule {
-	int			vers_ops;
-	u32			flags;
-	u32			listnr;
-	u32			action;
-	u32			mask[AUDIT_BITMASK_SIZE];
-	u32			buflen; /* for data alloc on list rules */
-	u32			field_count;
-	char			*filterkey; /* ties events to rules */
-	struct audit_field	*fields;
-	struct audit_field	*arch_f; /* quick access to arch field */
-	struct audit_field	*inode_f; /* quick access to an inode field */
-	struct audit_watch	*watch;	/* associated watch */
-	struct audit_tree	*tree;	/* associated watched tree */
-	struct list_head	rlist;	/* entry in audit_{watch,tree}.rules list */
-};
-
 struct audit_entry {
 	struct list_head	list;
 	struct rcu_head		rcu;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 2af9ec0..3367c80 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -353,6 +353,33 @@ struct netlink_skb_parms;
 struct linux_binprm;
 struct mq_attr;
 struct mqstat;
+struct audit_watch;
+struct audit_tree;
+
+struct audit_krule {
+	int			vers_ops;
+	u32			flags;
+	u32			listnr;
+	u32			action;
+	u32			mask[AUDIT_BITMASK_SIZE];
+	u32			buflen; /* for data alloc on list rules */
+	u32			field_count;
+	char			*filterkey; /* ties events to rules */
+	struct audit_field	*fields;
+	struct audit_field	*arch_f; /* quick access to arch field */
+	struct audit_field	*inode_f; /* quick access to an inode field */
+	struct audit_watch	*watch;	/* associated watch */
+	struct audit_tree	*tree;	/* associated watched tree */
+	struct list_head	rlist;	/* entry in audit_{watch,tree}.rules list */
+};
+
+struct audit_field {
+	u32				type;
+	u32				val;
+	u32				op;
+	char				*se_str;
+	void				*se_rule;
+};
 
 #define AUDITSC_INVALID 0
 #define AUDITSC_SUCCESS 1
@@ -536,6 +563,8 @@ extern void		    audit_log_d_path(struct audit_buffer *ab,
 					     const char *prefix,
 					     struct path *path);
 extern void		    audit_log_lost(const char *message);
+extern int		    audit_update_lsm_rules(void);
+		    
 				/* Private API (for audit.c only) */
 extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
 extern int audit_filter_type(int type);

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 57%]

* [PATCH 9/9] Audit: Final renamings and cleanup
  2008-03-01 19:47 95% [PATCH-v2 -mm 0/9] LSM-neutral Audit (SELinux audit separation) Ahmed S. Darwish
                   ` (7 preceding siblings ...)
  2008-03-01 20:03 57% ` [PATCH 8/9] SELinux: use new audit hooks, remove redundant exports Ahmed S. Darwish
@ 2008-03-01 20:05 71% ` Ahmed S. Darwish
  8 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 20:05 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Paul Moore, Andrew Morton
  Cc: LKML, Audit-ML, LSM-ML

Rename the se_str and se_rule audit fields elements to
lsm_str and lsm_rule to avoid confusion.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 include/linux/audit.h |    4 ++--
 kernel/auditfilter.c  |   40 ++++++++++++++++++++--------------------
 kernel/auditsc.c      |   12 ++++++------
 3 files changed, 28 insertions(+), 28 deletions(-)

Woo, hooo .. That was fun ;)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 3367c80..a35678e 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -377,8 +377,8 @@ struct audit_field {
 	u32				type;
 	u32				val;
 	u32				op;
-	char				*se_str;
-	void				*se_rule;
+	char				*lsm_str;
+	void				*lsm_rule;
 };
 
 #define AUDITSC_INVALID 0
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 7c69cb5..28fef6b 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -139,8 +139,8 @@ static inline void audit_free_rule(struct audit_entry *e)
 	if (e->rule.fields)
 		for (i = 0; i < e->rule.field_count; i++) {
 			struct audit_field *f = &e->rule.fields[i];
-			kfree(f->se_str);
-			security_audit_rule_free(f->se_rule);
+			kfree(f->lsm_str);
+			security_audit_rule_free(f->lsm_rule);
 		}
 	kfree(e->rule.fields);
 	kfree(e->rule.filterkey);
@@ -554,8 +554,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 		f->op = data->fieldflags[i] & AUDIT_OPERATORS;
 		f->type = data->fields[i];
 		f->val = data->values[i];
-		f->se_str = NULL;
-		f->se_rule = NULL;
+		f->lsm_str = NULL;
+		f->lsm_rule = NULL;
 		switch(f->type) {
 		case AUDIT_PID:
 		case AUDIT_UID:
@@ -598,7 +598,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 			entry->rule.buflen += f->val;
 
 			err = security_audit_rule_init(f->type, f->op, str,
-						       (void **)&f->se_rule);
+						       (void **)&f->lsm_rule);
 			/* Keep currently invalid fields around in case they
 			 * become valid after a policy reload. */
 			if (err == -EINVAL) {
@@ -610,7 +610,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 				kfree(str);
 				goto exit_free;
 			} else
-				f->se_str = str;
+				f->lsm_str = str;
 			break;
 		case AUDIT_WATCH:
 			str = audit_unpack_string(&bufp, &remain, f->val);
@@ -754,7 +754,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
 		case AUDIT_OBJ_LEV_LOW:
 		case AUDIT_OBJ_LEV_HIGH:
 			data->buflen += data->values[i] =
-				audit_pack_string(&bufp, f->se_str);
+				audit_pack_string(&bufp, f->lsm_str);
 			break;
 		case AUDIT_WATCH:
 			data->buflen += data->values[i] =
@@ -806,7 +806,7 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
 		case AUDIT_OBJ_TYPE:
 		case AUDIT_OBJ_LEV_LOW:
 		case AUDIT_OBJ_LEV_HIGH:
-			if (strcmp(a->fields[i].se_str, b->fields[i].se_str))
+			if (strcmp(a->fields[i].lsm_str, b->fields[i].lsm_str))
 				return 1;
 			break;
 		case AUDIT_WATCH:
@@ -862,28 +862,28 @@ out:
 	return new;
 }
 
-/* Duplicate LSM field information.  The se_rule is opaque, so must be
+/* Duplicate LSM field information.  The lsm_rule is opaque, so must be
  * re-initialized. */
 static inline int audit_dupe_lsm_field(struct audit_field *df,
 					   struct audit_field *sf)
 {
 	int ret = 0;
-	char *se_str;
+	char *lsm_str;
 
-	/* our own copy of se_str */
-	se_str = kstrdup(sf->se_str, GFP_KERNEL);
-	if (unlikely(!se_str))
+	/* our own copy of lsm_str */
+	lsm_str = kstrdup(sf->lsm_str, GFP_KERNEL);
+	if (unlikely(!lsm_str))
 		return -ENOMEM;
-	df->se_str = se_str;
+	df->lsm_str = lsm_str;
 
-	/* our own (refreshed) copy of se_rule */
-	ret = security_audit_rule_init(df->type, df->op, df->se_str,
-				       (void **)&df->se_rule);
+	/* our own (refreshed) copy of lsm_rule */
+	ret = security_audit_rule_init(df->type, df->op, df->lsm_str,
+				       (void **)&df->lsm_rule);
 	/* Keep currently invalid fields around in case they
 	 * become valid after a policy reload. */
 	if (ret == -EINVAL) {
 		printk(KERN_WARNING "audit rule for LSM \'%s\' is "
-		       "invalid\n", df->se_str);
+		       "invalid\n", df->lsm_str);
 		ret = 0;
 	}
 
@@ -930,7 +930,7 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
 	new->tree = old->tree;
 	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
 
-	/* deep copy this information, updating the se_rule fields, because
+	/* deep copy this information, updating the lsm_rule fields, because
 	 * the originals will all be freed when the old rule is freed. */
 	for (i = 0; i < fcount; i++) {
 		switch (new->fields[i].type) {
@@ -1762,7 +1762,7 @@ unlock_and_return:
 	return result;
 }
 
-/* This function will re-initialize the se_rule field of all applicable rules.
+/* This function will re-initialize the lsm_rule field of all applicable rules.
  * It will traverse the filter lists serarching for rules that contain LSM
  * specific filter fields.  When such a rule is found, it is copied, the
  * LSM field is re-initialized, and the old rule is replaced with the
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 8afd349..6ac71bb 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -527,14 +527,14 @@ static int audit_filter_rules(struct task_struct *tsk,
 			   match for now to avoid losing information that
 			   may be wanted.   An error message will also be
 			   logged upon error */
-			if (f->se_rule) {
+			if (f->lsm_rule) {
 				if (need_sid) {
 					security_task_getsecid(tsk, &sid);
 					need_sid = 0;
 				}
 				result = security_audit_rule_match(sid, f->type,
 				                                  f->op,
-				                                  f->se_rule,
+				                                  f->lsm_rule,
 				                                  ctx);
 			}
 			break;
@@ -545,18 +545,18 @@ static int audit_filter_rules(struct task_struct *tsk,
 		case AUDIT_OBJ_LEV_HIGH:
 			/* The above note for AUDIT_SUBJ_USER...AUDIT_SUBJ_CLR
 			   also applies here */
-			if (f->se_rule) {
+			if (f->lsm_rule) {
 				/* Find files that match */
 				if (name) {
 					result = security_audit_rule_match(
 					           name->osid, f->type, f->op,
-					           f->se_rule, ctx);
+					           f->lsm_rule, ctx);
 				} else if (ctx) {
 					for (j = 0; j < ctx->name_count; j++) {
 						if (security_audit_rule_match(
 						      ctx->names[j].osid,
 						      f->type, f->op,
-						      f->se_rule, ctx)) {
+						      f->lsm_rule, ctx)) {
 							++result;
 							break;
 						}
@@ -569,7 +569,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 					     aux = aux->next) {
 						if (aux->type == AUDIT_IPC) {
 							struct audit_aux_data_ipcctl *axi = (void *)aux;
-							if (security_audit_rule_match(axi->osid, f->type, f->op, f->se_rule, ctx)) {
+							if (security_audit_rule_match(axi->osid, f->type, f->op, f->lsm_rule, ctx)) {
 								++result;
 								break;
 							}

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 71%]

* [PATCH -v2 -mm] LSM: Add security= boot parameter
  @ 2008-03-01 23:27 70%   ` Ahmed S. Darwish
    2008-03-02  7:49 99%     ` Ahmed S. Darwish
  0 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-01 23:27 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Adrian Bunk, Chris Wright, Stephen Smalley, James Morris,
	Eric Paris, Alexey Dobriyan, LKML, LSM-ML, Anrew Morton

Hi!,

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

I'll send a similar patch for 2.6.25 if no more concerns for
the patch exist. 

Adrian, Casey, Does this one have any more issues ?

 Documentation/kernel-parameters.txt |    6 ++++
 include/linux/security.h            |   12 +++++++++
 security/dummy.c                    |    3 +-
 security/security.c                 |   47 +++++++++++++++++++++++++++++++++++-
 security/selinux/hooks.c            |    5 +++
 security/smack/smack_lsm.c          |    7 +++++

 6 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c64dfd7..85044e8 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index a33fd03..416afcf 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 
 /*
@@ -117,6 +120,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as  unique identifeir for the LSM with max number 
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1218,6 +1227,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1477,6 +1488,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 6a0056b..7cb999c 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -986,7 +986,7 @@ static int dummy_key_getsecurity(struct key *key, char **_buffer)
 
 #endif /* CONFIG_KEYS */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { "dummy" };
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
@@ -999,6 +999,7 @@ struct security_operations dummy_security_ops;
 
 void security_fixup_ops (struct security_operations *ops)
 {
+	BUG_ON(!ops->name);
 	set_to_dummy_if_null(ops, ptrace);
 	set_to_dummy_if_null(ops, capget);
 	set_to_dummy_if_null(ops, capset_check);
diff --git a/security/security.c b/security/security.c
index 3e75b90..261d2e4 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static char chosen_lsm[SECURITY_NAME_MAX + 1];
+static atomic_t security_ops_registered = ATOMIC_INIT(0);
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -67,13 +70,54 @@ int __init security_init(void)
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	if (strlen(str) > SECURITY_NAME_MAX) {
+		printk(KERN_INFO "Security: LSM name length extends possible"
+		       "limit.\n");
+		printk(KERN_INFO "Security: Ignoring passed security= "
+		       "parameter.\n");
+		return 0;
+	}
+
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin.
+ * Otherwise, return false.
+ */
+int security_module_enable(struct security_operations *ops)
+{
+	if (!ops || !ops->name)
+		return 0;
+
+	if (!*chosen_lsm && !atomic_read(&security_ops_registered))
+		return 1;
+
+	if (!strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		return 1;
+	
+	return 0;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
@@ -90,6 +134,7 @@ int register_security(struct security_operations *ops)
 		return -EAGAIN;
 
 	security_ops = ops;
+	atomic_inc(&security_ops_registered);
 
 	return 0;
 }
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f42ebfc..fe30d2b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5233,6 +5233,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5420,7 +5422,8 @@ static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
-	if (!selinux_enabled) {
+	if (!selinux_enabled || !security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
 	}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 2b5d6f7..3fc8c6e 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2358,6 +2358,8 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 }
 
 static struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2485,6 +2487,11 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops)) {
+		printk(KERN_INFO "Smack: Disabled at boot.\n");
+		return 0;
+	}
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 70%]

* Re: [PATCH -v2 -mm] LSM: Add security= boot parameter
  2008-03-01 23:27 70%   ` [PATCH -v2 -mm] LSM: Add security= " Ahmed S. Darwish
  @ 2008-03-02  7:49 99%     ` Ahmed S. Darwish
  2008-03-02 10:59 67%       ` [PATCH -v3 " Ahmed S. Darwish
  1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-02  7:49 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Adrian Bunk, Chris Wright, Stephen Smalley, James Morris,
	Eric Paris, Alexey Dobriyan, LKML, LSM-ML, Anrew Morton

On Sun, Mar 02, 2008 at 01:27:08AM +0200, Ahmed S. Darwish wrote:
> Hi!,
> 
... 
> LSM modules must check now if they are allowed to register
> by calling security_module_enable(ops) first. Modify SELinux 
> and SMACK to do so.
> 
...
>  
> +/* Boot-time LSM user choice */
> +static char chosen_lsm[SECURITY_NAME_MAX + 1];
> +static atomic_t security_ops_registered = ATOMIC_INIT(0);
>  
...
> +int security_module_enable(struct security_operations *ops)
> +{
> +	if (!ops || !ops->name)
> +		return 0;
> +
> +	if (!*chosen_lsm && !atomic_read(&security_ops_registered))
> +		return 1;
> +
...
> @@ -90,6 +134,7 @@ int register_security(struct security_operations *ops)
>  		return -EAGAIN;
>  
>  	security_ops = ops;
> +	atomic_inc(&security_ops_registered);
>  

I'm worried about an implementation detail here. Must the LSM
init calls sequence:
asmlinkage void __init start_kernel(void)
{
	preempt_disable();
	...
	security_init();
	...

int __init security_init(void)
{
	...
	do_security_initcalls();
}
static void __init do_security_initcalls(void)
{
	initcall_t *call;
	call = __security_initcall_start;
	while (call < __security_initcall_end) {
		(*call) ();
		call++;
	}
}
be SMP safe ?

In other words, can the two LSMs 'security_initcall()'s 
(i.e. smack_init() and selinux_init()) be executed concurrently ?

If so, this patch won't be safe.
I'll send a modified one once I know the answer.

Thanks everybody,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH -v2 -mm] LSM: Add security= boot parameter
  @ 2008-03-02  7:55 99%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-02  7:55 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Adrian Bunk, Chris Wright, Stephen Smalley, James Morris,
	Eric Paris, Alexey Dobriyan, LKML, LSM-ML, Anrew Morton

On Sat, Mar 01, 2008 at 07:41:04PM -0800, Casey Schaufler wrote:
> 
> --- "Ahmed S. Darwish" <darwish.07@gmail.com> wrote:
> >
...
> > 
> >  
> >  static struct security_operations selinux_ops = {
> > +	.name =				"selinux",
> > +
> >  	.ptrace =			selinux_ptrace,
> >  	.capget =			selinux_capget,
> >  	.capset_check =			selinux_capset_check,
> > @@ -5420,7 +5422,8 @@ static __init int selinux_init(void)
> >  {
> >  	struct task_security_struct *tsec;
> >  
> > -	if (!selinux_enabled) {
> > +	if (!selinux_enabled || !security_module_enable(&selinux_ops)) {
> > +		selinux_enabled = 0;
> >  		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
> 
> How about "SELinux: Not enabled because LSM %s is already enabled.\n"
> 

Looks better. I'll resend the patch once I know the answer of the SMP
point I asked about in the same thread.

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [PATCH -v3 -mm] LSM: Add security= boot parameter
  2008-03-02  7:49 99%     ` Ahmed S. Darwish
@ 2008-03-02 10:59 67%       ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-02 10:59 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Adrian Bunk, Chris Wright, Stephen Smalley, James Morris,
	Eric Paris, Alexey Dobriyan, LKML, LSM-ML, Anrew Morton

Hi!,

[
Fixed two bugs:
       - concurrency: incrementing and testing atomic_t in different places.
       - overflow: not ending string with NULL after using strncpy().
       - I'll never write a patch when I'm asleep, sorry :(

Added more verbose messages to SMACK and SELinux if they were not 
chosen on boot.

Casey: Failing to take permission to register an LSM does not mean that 
       the other has registered its security_ops yet. It just means that
       the other asked for allowance to call register_security(). It's 
       not yet guraranteed that this registration succeeded.

       This means that adding "SELinux: failed to load, LSM %s is loaded"
       may lead to %s = "dummy" in case of a highly concurrent SMP system.
]

-->

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 Documentation/kernel-parameters.txt |    6 ++++
 include/linux/security.h            |   12 +++++++++
 security/dummy.c                    |    2 -
 security/security.c                 |   46 +++++++++++++++++++++++++++++++++---
 security/selinux/hooks.c            |   12 +++++++++
 security/smack/smack_lsm.c          |   11 ++++++++

 6 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c64dfd7..85044e8 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index a33fd03..601318a 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 
 /*
@@ -117,6 +120,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as a unique identifeir for the LSM with max number 
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1218,6 +1227,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1477,6 +1488,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 6a0056b..d0910f2 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -986,7 +986,7 @@ static int dummy_key_getsecurity(struct key *key, char **_buffer)
 
 #endif /* CONFIG_KEYS */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { "dummy" };
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
diff --git a/security/security.c b/security/security.c
index 3e75b90..6f2df1a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static char chosen_lsm[SECURITY_NAME_MAX + 1];
+static atomic_t security_ops_enabled = ATOMIC_INIT(-1);
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -30,7 +33,7 @@ unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR;
 static inline int verify(struct security_operations *ops)
 {
 	/* verify the security_operations structure exists */
-	if (!ops)
+	if (!ops || !ops->name)
 		return -EINVAL;
 	security_fixup_ops(ops);
 	return 0;
@@ -67,13 +70,51 @@ int __init security_init(void)
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	chosen_lsm[SECURITY_NAME_MAX] = NULL;
+
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Each LSM must pass this method before registering its own operations
+ * to avoid security registration races.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin.
+ * Otherwise, return false.
+ */
+int security_module_enable(struct security_operations *ops)
+{
+	if (!ops || !ops->name)
+		return 0;
+
+	if (!*chosen_lsm && atomic_inc_and_test(&security_ops_enabled))
+		return 1;
+
+	if (!strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		return 1;
+	
+	return 0;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f42ebfc..b507977 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5233,6 +5233,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5425,6 +5427,15 @@ static __init int selinux_init(void)
 		return 0;
 	}
 
+	if (!security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
+		printk(KERN_INFO "SELinux:  Security registration was not allowed.\n");
+		printk(KERN_INFO "SELinux:  Another security module was chosen.\n");
+		printk(KERN_INFO "SELinux:  Use security=%s to force choosing "
+		       "SELinux on boot.\n", selinux_ops.name);
+		return 0;
+	}
+
 	printk(KERN_INFO "SELinux:  Initializing.\n");
 
 	/* Set the security state for the initial task. */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 2b5d6f7..2e1adbb 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2358,6 +2358,8 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 }
 
 static struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2485,6 +2487,14 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops)) {
+		printk(KERN_INFO "Smack:  Security registration was not allowed.\n");
+		printk(KERN_INFO "Smack:  Another security module was chosen.\n");
+		printk(KERN_INFO "Smack:  Use security=%s to force choosing "
+		       "Smack on boot.\n", smack_ops.name);
+		return 0;
+	}
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*

---
"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 67%]

* Re: [PATCH -v3 -mm] LSM: Add security= boot parameter
  @ 2008-03-03 15:35 98%           ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-03 15:35 UTC (permalink / raw)
  To: James Morris
  Cc: Casey Schaufler, Adrian Bunk, Chris Wright, Stephen Smalley,
	Eric Paris, Alexey Dobriyan, LKML, LSM-ML, Anrew Morton

Hi James,

On Mon, Mar 03, 2008 at 07:29:22PM +1100, James Morris wrote:
> On Sun, 2 Mar 2008, Ahmed S. Darwish wrote:
> 
> > Add the security= boot parameter. This is done to avoid LSM 
> > registration clashes in case of more than one bult-in module.
> > 
> > User can choose a security module to enable at boot. If no 
> > security= boot parameter is specified, only the first LSM 
> > asking for registration will be loaded. An invalid security 
> > module name will be treated as if no module has been chosen.
> > 
> > LSM modules must check now if they are allowed to register
> > by calling security_module_enable(ops) first. Modify SELinux 
> > and SMACK to do so.
> 
> I think this can be simplified by folding the logic into 
> register_security(), rather than having a two-stage LSM registration 
> process.
> 
> So, this function would now look like
> 
> 	int register_security(ops, *status);
> 
> and set *status to LSM_WAS_CHOSEN (or similar) if the module being 
> registered was also chosen via the security= parameter.  If there is no 
> value for the parameter, the first module to register is automatically 
> chosen, to preserve existing behavior.
> 
> The calling code can then decide what to do, e.g. not panic if 
> registration failed and the LSM was not chosen; panic on failure when it 
> was chosen.
> 

I liked to do it like that at first, but I faced two problems:

SElinux (As you already know ;)) does the security setup of the initial 
task before calling register_security. Would it be safe to do this
setup after registeration ?

Same case occurs for Smack, it does some locking initializations and
setup initial task's security before registration.

Personally, I feel that it's nicer to let the LSM know if it's
OK to initialize itself before hitting _the point of no return_ (registration).

Anyway, I have no problem to implement it using *status if my 
concerns are wrong.

> > +static atomic_t security_ops_enabled = ATOMIC_INIT(-1);
> 
> I'd suggest getting rid of this atomic and using a spinlock to protect the 
> global chosen_lsm string, which is always filled when an LSM registers.
> 
> >  
> > +/* Save user chosen LSM */
> > +static int __init choose_lsm(char *str)
> > +{
> > +	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
> > +	chosen_lsm[SECURITY_NAME_MAX] = NULL;
> 
> You should never need to set the last byte to NULL -- it's initialized to 
> that and by definition should never be overwritten.
> 
> > +int security_module_enable(struct security_operations *ops)
> > +{
> > +	if (!ops || !ops->name)
> > +		return 0;
> 
> Lack of ops->name during registration needs to be a BUG_ON.
> 

You'll find above three points fixed the next send. Thank you.

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 98%]

* [PATCH -v4 -mm] LSM: Add security= boot parameter
  @ 2008-03-03 21:24 67%               ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-03 21:24 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: James Morris, Casey Schaufler, Adrian Bunk, Chris Wright,
	Eric Paris, Alexey Dobriyan, LKML, LSM-ML, Anrew Morton

Hi!,

On Mon, Mar 03, 2008 at 10:54:02AM -0500, Stephen Smalley wrote:
> 
> On Mon, 2008-03-03 at 17:35 +0200, Ahmed S. Darwish wrote:
> > Hi James,
> > 
....
> > 
> > SElinux (As you already know ;)) does the security setup of the initial 
> > task before calling register_security. Would it be safe to do this
> > setup after registeration ?
> 
> I wouldn't recommend it - the hook functions presume that the initial
> task security blob has been set up already, and that other dependencies
> like the inode security cache and access vector cache have been created
> and can be used.  We have to assume that the security hooks can start
> being invoked as soon as we call register_security(), even if in
> practice it won't happen until after the init function completes.
>

OK, the patch will stick with the two-stage registration model to give
a safe initialization time for LSMs.

james: Could you please make it OK to use the atomic counter instead of
       the spinlock ? It'll just add unneeded complexity. We only set
       `chosen_lsm' once at the parameters parsing time. 

Changes (per James suggestions):
- Added a BUG_ON(!ops->name).
- Removed a redundant setting of last string character to NULL.

Sample Output:
[    0.065487] SELinux:  Initializing.
[    0.067115] SELinux:  Starting in permissive mode
[    0.067186] Smack:  Another security module was chosen.
[    0.067345] Smack:  Use security=smack to force loading Smack on boot.

-->

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 Documentation/kernel-parameters.txt |    6 ++++
 include/linux/security.h            |   12 +++++++++
 security/dummy.c                    |    2 -+
 security/security.c                 |   45 ++++++++++++++++++++++++++++++++++--
 security/selinux/hooks.c            |   10 ++++++++
 security/smack/smack_lsm.c          |    9 +++++++

 6 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c64dfd7..85044e8 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index eb663e5..3db2819 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 struct audit_krule;
 
@@ -118,6 +121,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as a unique identifeir for the LSM with max number
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1262,6 +1271,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1530,6 +1541,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 241ab20..d081699 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -1022,7 +1022,7 @@ static inline void dummy_audit_rule_free(void *lsmrule)
 
 #endif /* CONFIG_AUDIT */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { "dummy" };
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
diff --git a/security/security.c b/security/security.c
index 1bf2ee4..5419fec 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static char chosen_lsm[SECURITY_NAME_MAX + 1];
+static atomic_t security_ops_enabled = ATOMIC_INIT(-1);
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -30,7 +33,7 @@ unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR;
 static inline int verify(struct security_operations *ops)
 {
 	/* verify the security_operations structure exists */
-	if (!ops)
+	if (!ops || !ops->name)
 		return -EINVAL;
 	security_fixup_ops(ops);
 	return 0;
@@ -67,13 +70,51 @@ int __init security_init(void)
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Each LSM must pass this method before registering its own operations
+ * to avoid security registration races.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin.
+ * Otherwise, return false.
+ */
+int security_module_enable(struct security_operations *ops)
+{
+	if (!ops || !ops->name) {
+		BUG();
+		return 0;
+	}
+
+	if (!*chosen_lsm && atomic_inc_and_test(&security_ops_enabled))
+		return 1;
+
+	if (!strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		return 1;
+
+	return 0;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index bef1834..c3a52a8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5247,6 +5247,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5448,6 +5450,14 @@ static __init int selinux_init(void)
 		return 0;
 	}
 
+	if (!security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
+		printk(KERN_INFO "SELinux:  Another security module was chosen.\n");
+		printk(KERN_INFO "SELinux:  Use security=%s to force loading "
+		       "SELinux on boot.\n", selinux_ops.name);
+		return 0;
+	}
+
 	printk(KERN_INFO "SELinux:  Initializing.\n");
 
 	/* Set the security state for the initial task. */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 2b5d6f7..ad31819 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2358,6 +2358,8 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 }
 
 static struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2485,6 +2487,13 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops)) {
+		printk(KERN_INFO "Smack:  Another security module was chosen.\n");
+		printk(KERN_INFO "Smack:  Use security=%s to force loading "
+		       "Smack on boot.\n", smack_ops.name);
+		return 0;
+	}
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 67%]

* [PATCH -v5 -mm] LSM: Add security= boot parameter
  @ 2008-03-04  3:04 71%                   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-04  3:04 UTC (permalink / raw)
  To: James Morris
  Cc: Stephen Smalley, Casey Schaufler, Adrian Bunk, Chris Wright,
	Eric Paris, Alexey Dobriyan, LKML, LSM-ML, Anrew Morton

Hi!,

[ 
Fix stuff mentioned by James in parent mail:
- use spinlocks instead of atomic counter (yes, this is clearer).
- remove redundant BUG_ON
- don't let LSMs loudly complain when they aren't chosen.
]

-->

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 Documentation/kernel-parameters.txt |    6 ++++
 include/linux/security.h            |   12 +++++++++
 security/dummy.c                    |    2 -
 security/security.c                 |   46 +++++++++++++++++++++++++++++++++++-
 security/selinux/hooks.c            |    7 +++++
 security/smack/smack_lsm.c          |    5 +++

 6 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c64dfd7..85044e8 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index eb663e5..3db2819 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 struct audit_krule;
 
@@ -118,6 +121,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as a unique identifeir for the LSM with max number
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1262,6 +1271,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1530,6 +1541,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 241ab20..d081699 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -1022,7 +1022,7 @@ static inline void dummy_audit_rule_free(void *lsmrule)
 
 #endif /* CONFIG_AUDIT */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { "dummy" };
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
diff --git a/security/security.c b/security/security.c
index 1bf2ee4..def9fc0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static spinlock_t chosen_lsm_lock;
+static char chosen_lsm[SECURITY_NAME_MAX + 1];
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -62,18 +65,59 @@ int __init security_init(void)
 	}
 
 	security_ops = &dummy_security_ops;
+	spin_lock_init(&chosen_lsm_lock);
 	do_security_initcalls();
 
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Each LSM must pass this method before registering its own operations
+ * to avoid security registration races.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin.
+ * Otherwise, return false.
+ */
+int security_module_enable(struct security_operations *ops)
+{
+	int rc = 1;
+
+	spin_lock(&chosen_lsm_lock);
+	if (!*chosen_lsm)
+		strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
+	else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		rc = 0;
+	spin_unlock(&chosen_lsm_lock);
+
+	if (rc)
+		printk(KERN_INFO "Security: Loading '%s' security module.\n",
+		       ops->name);
+
+	return rc;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index bef1834..52aaf10 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5247,6 +5247,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5443,6 +5445,11 @@ static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
+	if (!security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
+		return 0;
+	}
+
 	if (!selinux_enabled) {
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 2b5d6f7..9464185 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2358,6 +2358,8 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 }
 
 static struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2485,6 +2487,9 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 71%]

* Re: [PATCH 7/9] Audit: internally use the new LSM audit hooks
  @ 2008-03-04  3:31 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-04  3:31 UTC (permalink / raw)
  To: Paul Moore
  Cc: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, David Woodhouse, Andrew Morton, LKML, Audit-ML,
	LSM-ML

On Mon, Mar 03, 2008 at 06:51:41PM -0500, Paul Moore wrote:
> On Saturday 01 March 2008 3:01:11 pm Ahmed S. Darwish wrote:
...
> >
> >  audit.c       |    7 ------
> >  auditfilter.c |   61
> > ++++++++++++++++------------------------------------------ auditsc.c 
> >    |    9 +++-----
> >  3 files changed, 22 insertions(+), 55 deletions(-)
> 
> For some reason some of your patches are not coming through with correct 
> diffstats (notice the lack of a path relative to the kernel base?).  
> Don't worry too much about it as it's not grounds to reject the patch 
> (at least in my mind) but it's worth looking into on your end for the 
> next time you submit patches.
> 

Yes, it's something weird. I've generated all of those diffstats (including
the right ones) in the same way. Luckily the problem is reproduceable,
I'll check the latest upstream diffstat version and see what happens.

> > Andrew, please atomically merge patch #7 and patch #8. Although
> > a system with patch7 and without patch8 will be compiled fine,
> > the SELinux Audit hooks are not set up yet. This means below
> > audit hooks will point to the dummy hooks instead of SELinux
> > ones even if SELinux is enabled.
> >
> > I could not setup the SELinux hooks first cause they have
> > the same name of the old exported SELinux interface with a
> > difference of one parameter.
> 
> In cases like this where you need patches applied atomically to ensure 
> correct operation you can always combine the two patches into one 
> (assuming they are still small enough to be posted, which shouldn't be 
> a problem here).  Small patches are nice and easy to review, but that 
> doesn't mean you have to break everything up if it is awkward.
> 

I'll keep that in mind.

> I've looked over patches #7, #8, and #9 and they look okay to me, but 
> I'm not tagging them 'Reviewed-by' because they go beyond areas of the 
> kernel that I feel comfortable reviewing at this point.  Rest assured 
> there are other on the To/CC line that can help you out (I see James 
> Morris already Ack'd your entire patch set).
> 
> Thanks for all your work on this, it's a nice improvement.
> 

I'm also very thankful for such a nice review and caring explanations!.

Best,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [PATCH BUGFIX -rc3] Smack: Don't register smackfs if we're not loaded
@ 2008-03-04 13:10 91% Ahmed S. Darwish
  2008-03-04 13:58 69% ` [PATCH -rc3] Security: Introduce security= boot parameter Ahmed S. Darwish
    0 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-04 13:10 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: LKML, Linus

Hi all,

Smackfs initialization without an enabled Smack leads to
an early Oops that renders the system unusable.

Introduce a global smack_enabled variable that will be used
to make sure that no smack components will be registered 
(ala smackfs) if we are not already enabled.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

The Oops is triggered by the security= patch that will be sent
soon.

I can't imagine an SELinux guru finding /smackfs instead of 
his usual /selinuxfs when he hits a tab completion after 's' ;).
As a bonus, this patch will handle that case too.

 smack.h     |    9 +++++++++
 smack_lsm.c |    8 ++++++++
 smackfs.c   |    3 +++

 3 files changed, 20 insertions(+)

diff --git a/security/smack/smack.h b/security/smack/smack.h
index a21a0e9..17c55ad 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -18,6 +18,15 @@
 #include <net/netlabel.h>
 
 /*
+ * We must not bother the rest of the kernel by exporting our
+ * own stuff if we are not already enabled. We may not be loaded
+ * if another or no LSM was chosen on boot.
+ * Smackfs is currently the only exported component, but this
+ * may change in the future.
+ */
+extern int smack_enabled;
+
+/*
  * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
  * bigger than can be used, and 24 is the next lower multiple
  * of 8, and there are too many issues if there isn't space set
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 770eb06..6fe7869 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -36,6 +36,8 @@
 #define SOCKFS_MAGIC		0x534F434B
 #define TMPFS_MAGIC		0x01021994
 
+int smack_enabled;
+
 /**
  * smk_fetch - Fetch the smack label from a file.
  * @ip: a pointer to the inode
@@ -2589,6 +2591,12 @@ static __init int smack_init(void)
 	if (register_security(&smack_ops))
 		panic("smack: Unable to register with kernel.\n");
 
+	/*
+	 * Notify other Smack components that it's now safe to
+	 * to register themselves.
+	 */
+	smack_enabled = 1;
+
 	return 0;
 }
 
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 358c92c..e1687c0 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -992,6 +992,9 @@ static int __init init_smk_fs(void)
 {
 	int err;
 
+	if (!smack_enabled)
+		return 0;
+
 	err = register_filesystem(&smk_fs_type);
 	if (!err) {
 		smackfs_mount = kern_mount(&smk_fs_type);

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 91%]

* [PATCH -rc3] Security: Introduce security= boot parameter
  2008-03-04 13:10 91% [PATCH BUGFIX -rc3] Smack: Don't register smackfs if we're not loaded Ahmed S. Darwish
@ 2008-03-04 13:58 69% ` Ahmed S. Darwish
  2008-03-05 15:29 66%   ` [PATCH -v7 " Ahmed S. Darwish
  2008-03-05 18:46 63%   ` [PATCH -v7b " Ahmed S. Darwish
    1 sibling, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-04 13:58 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, Paul Moore, Alexey Dobriyan, Andrew Morton,
	Linus
  Cc: LKML, LSM-ML

Hi all,

[
    Sending as a reply to the above Smack bugfix cause the bug 
    is triggered by this patch.

    Please merge the bugfix before this.

    IMHO this patch (or similar) is needed before the release
    to avoid useless panics. Also as noted by Alexey, current
    allyesconfig kernels panics cause of the same problem which
    means less testing before hitting 2.6.25 .

    Thanks!
]

-->

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Acked-by: James Morris <jmorris@namei.org>
Reported-by: Alexey Dobriyan <adobriyan@sw.ru>
---

[James ACKed the -mm version, but this patch is exactly the same]

 Documentation/kernel-parameters.txt |    6 ++++
 include/linux/security.h            |   12 +++++++++
 security/dummy.c                    |    2 -
 security/security.c                 |   46 +++++++++++++++++++++++++++++++++++-
 security/selinux/hooks.c            |    7 +++++
 security/smack/smack_lsm.c          |    5 +++
 6 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a5b665..64efbdc 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index fe52cde..801c9ad 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 
 /*
@@ -117,6 +120,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as a unique identifeir for the LSM with max number
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1207,6 +1216,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1466,6 +1477,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 649326b..96d196f 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -979,7 +979,7 @@ static inline int dummy_key_permission(key_ref_t key_ref,
 }
 #endif /* CONFIG_KEYS */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { "dummy" };
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
diff --git a/security/security.c b/security/security.c
index d15e56c..f188672 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static spinlock_t chosen_lsm_lock;
+static char chosen_lsm[SECURITY_NAME_MAX + 1];
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -62,18 +65,59 @@ int __init security_init(void)
 	}
 
 	security_ops = &dummy_security_ops;
+	spin_lock_init(&chosen_lsm_lock);
 	do_security_initcalls();
 
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Each LSM must pass this method before registering its own operations
+ * to avoid security registration races.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin.
+ * Otherwise, return false.
+ */
+int security_module_enable(struct security_operations *ops)
+{
+	int rc = 1;
+
+	spin_lock(&chosen_lsm_lock);
+	if (!*chosen_lsm)
+		strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
+	else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		rc = 0;
+	spin_unlock(&chosen_lsm_lock);
+
+	if (rc)
+		printk(KERN_INFO "Security: Loading '%s' security module.\n",
+		       ops->name);
+
+	return rc;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 75c2e99..49709a4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5219,6 +5219,8 @@ static int selinux_key_permission(key_ref_t key_ref,
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5405,6 +5407,11 @@ static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
+	if (!security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
+		return 0;
+	}
+
 	if (!selinux_enabled) {
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 6fe7869..ecf1d16 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2436,6 +2436,8 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 }
 
 static struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2568,6 +2570,9 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*


If you read till here, Thank you for the review ;)
Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 69%]

* Re: [BUG + PATCH/Bugfix] x86/lguest: fix pgdir pmd index calculation
  @ 2008-03-04 15:11 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-04 15:11 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, LKML, lguest, akpm

On Tue, Mar 04, 2008 at 11:55:10PM +1100, Rusty Russell wrote:
> On Monday 25 February 2008 02:55:15 Ahmed S. Darwish wrote:
> > Hi all,
> >
> > Beginning from commits close to v2.6.25-rc2, running lguest always oopses
> > the host kernel. Oops is at [1].
> 
> OK, whatever the guest does should not break the host.  So your patch can't be
> the whole solution.
> 
> > static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
> > {
> > 	*pmdp = pmdval;
> > 	lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
> > 		   (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
> > }
> >
> > The first hcall parameter is global pgdir which looks fine. The second
> > parameter is the pmd index in the pgdir which is suspectful.
> >
> > AFAIK, calculating the index of pmd does not need a divisoin over four.
> > Removing the division made lguest work fine again . Patch is at [2].
> 
> Each pmd is 4 bytes long, so the divide by 4 gives the index into the (top
> level) page. ie. a number in the range 0 to 1023.
> 

aha, now it's clear. 

>
> Indeed, here's the correct fix.  Does it work for you?
> 

Yes it does (after removing the unrelated TSC-if-pentium+ checks). 

Thank you

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH BUGFIX -rc3] Smack: Don't register smackfs if we're not loaded
  @ 2008-03-04 18:24 92%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-04 18:24 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Casey Schaufler, LKML, Stephen Smalley, James Morris, Eric Paris

Hi Linus,

[Adding SELinux devs to CC list, please follow to the SELinux point.]

On Tue, Mar 04, 2008 at 09:21:19AM -0800, Linus Torvalds wrote:
> 
> 
> On Tue, 4 Mar 2008, Ahmed S. Darwish wrote:
> > 
> > Smackfs initialization without an enabled Smack leads to
> > an early Oops that renders the system unusable.
> 
> I really think this is bogus. Global enables like this are just wrong, and 
> a sign that something else bad is going on.
> 
> What is the oops? Why does it happen?
> 

The problem occurs when Smack is built-in the kernel but not chosen
to register itself on boot. Smack was not chosen on boot cause either
security=AnotherLSM or security=NonExistentLSM.

In all cases, init_smk_fs() ,which registers smackfs, got called
cause it's an __initcall(init_smack_fs). 
This include the cases where smack __was not__ chosen on boot.

Making smackfs mountable when Smack is not registered leads to:

1- an Oops by dereferncing the NULL security pointer: current->security (*)

2- Smackfs code got executed though naturally all the code assumes
   that smack is already registered with the security system leading
   to several problems.

3- The bogus idea of having a subsystem interface available when the
   subsystem itself is not available!

So the global is used in init_smk_fs to not register smackfs if
Smack wasn't enabled on boot.

---- SELinux:

I think the SELinux folks faced the same problem too. In my first 
local iteration of the security= parameter patch, I forgot to set 
`selinux_disable = 1' if SELinux wasn't chosen on boot.

This led to dozen of SELinux Udev events and also led to selinuxfs 
being available even though SELinux hooks _weren't_ registered.

Regards,

(*) 
    Could not save the oops cause it occured too early, but
    it was like this:

    __init_call
    init_smk_fs(void)
    smk_unlbl_ambient(NULL)
    /* 
     * Here: current->security = NULL, cause SMACK initial setup
     * was not executed.
     */
    smack_to_secid(current->security) 
    strncmp(.., current->security, ..) 
    
-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 92%]

* Re: [PATCH BUGFIX -rc3] Smack: Don't register smackfs if we're not loaded
  @ 2008-03-05 12:12 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-05 12:12 UTC (permalink / raw)
  To: James Morris; +Cc: Casey Schaufler, Linus Torvalds, LKML

On Wed, Mar 05, 2008 at 11:58:08AM +1100, James Morris wrote:
> On Tue, 4 Mar 2008, Linus Torvalds wrote:
> 
> > 
> > 
> > On Tue, 4 Mar 2008, Casey Schaufler wrote:
> > > 
> > > One solution would be to tighten the smackfs code so that it
> > > handles the uninitialized LSM case properly.
> > 
> > I really would tend to prefer that.
> 
> Can you simply call init_smk_fs() from smack_init() prior to 
> register_security() ?
> 

After analysing below oops:

[    0.072989] Call Trace:
[    0.072989]  [<c017d4a4>] alloc_vfsmnt+0x24/0xd0
[    0.072989]  [<c0168ee1>] vfs_kern_mount+0x31/0x120
[    0.072989]  [<c0168fe2>] kern_mount_data+0x12/0x20
[    0.072989]  [<c038a73c>] init_smk_fs+0x4c/0x80
[    0.072989]  [<c038a6ce>] smack_init+0xae/0xd0
[    0.072989]  [<c038a192>] security_init+0x52/0x70
[    0.072989]  [<c037aaa5>] start_kernel+0x1e5/0x290
[    0.072989]  [<c037a380>] unknown_bootoption+0x0/0x1f0
[    0.072989]  =======================

I've found that vfs_caches_init() got called after calling 
security_init() in the main kernel init path. 

This leads to kern_mount() Oopsing cause of Null dereferencing 
of mnt_cache  in the alloc_vfsmnt(mnt_cache, GFP_KERNEL) step.

I was thinking about exporting the current chosen_lsm[] string,
but I don't know if this maybe seen by Linus as another global
that arises from bad design. It may not also scale well if the
LSM needs to check if it's enabled in various places (lots of
strcmp()s).

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH BUGFIX -rc3] Smack: Don't register smackfs if we're not loaded
    @ 2008-03-05 12:44 99% ` Ahmed S. Darwish
  2008-03-05 12:51 99%   ` Ahmed S. Darwish
  1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-05 12:44 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Linus Torvalds, Stephen Smalley, James Morris, Eric Paris, LKML

On Tue, Mar 04, 2008 at 09:45:04AM -0800, Casey Schaufler wrote:
> ----- Original Message ----
> > From: Linus Torvalds <torvalds@linux-foundation.org>
> > To: Ahmed S. Darwish <darwish.07@gmail.com>
> > Cc: Casey Schaufler <casey@schaufler-ca.com>; LKML <linux-kernel@vger.kernel.org>
> > Sent: Tuesday, March 4, 2008 9:21:19 AM
> > Subject: Re: [PATCH BUGFIX -rc3] Smack: Don't register smackfs if we're not loaded
> > 
> > 
> > 
> > On Tue, 4 Mar 2008, Ahmed S. Darwish wrote:
> > > 
> > > Smackfs initialization without an enabled Smack leads to
> > > an early Oops that renders the system unusable.
> > 
> > I really think this is bogus. Global enables like this are just wrong, and 
> > a sign that something else bad is going on.
> > 
> > What is the oops? Why does it happen?
...
> 
> One solution would be to tighten the smackfs code so that it
> handles the uninitialized LSM case properly.
> 

IMHO no smackfs code should ever execute if smack isn't loaded.

This means catching it from the very fist step where it registers
itself in init_smk_fs instead of doing several if(we're enabled) cases
in the code path.

The solution should be a _general_ solution, _not_ a SMACK one cause 
SELinux sufferes from exactly the same problem.

a.k.a:

LSMs need a scalable way to know if they're enabled that makes 
everyone happy ( especially Linus ;) ).

Regads to all,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: [PATCH BUGFIX -rc3] Smack: Don't register smackfs if we're not loaded
  2008-03-05 12:44 99% ` Ahmed S. Darwish
@ 2008-03-05 12:51 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-05 12:51 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Linus Torvalds, Stephen Smalley, James Morris, Eric Paris, LKML

On Wed, Mar 05, 2008 at 02:44:45PM +0200, Ahmed S. Darwish wrote:
> On Tue, Mar 04, 2008 at 09:45:04AM -0800, Casey Schaufler wrote:
> > > From: Linus Torvalds <torvalds@linux-foundation.org>
...
> > > 
> > > What is the oops? Why does it happen?
> ...
> > 
> > One solution would be to tighten the smackfs code so that it
> > handles the uninitialized LSM case properly.
> > 
> 
> IMHO no smackfs code should ever execute if smack isn't loaded.
> 
> This means catching it from the very fist step where it registers
> itself in init_smk_fs instead of doing several if(we're enabled) cases
> in the code path.
> 
> The solution should be a _general_ solution, _not_ a SMACK one cause 
> SELinux sufferes from exactly the same problem.
> 

Not to be misunderstood here, I'm used to writing SMACK in capitals.
I ,ofcourse, don't mean shouting (never will).

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [PATCH -v7 -rc3] Security: Introduce security= boot parameter
  2008-03-04 13:58 69% ` [PATCH -rc3] Security: Introduce security= boot parameter Ahmed S. Darwish
@ 2008-03-05 15:29 66%   ` Ahmed S. Darwish
    2008-03-05 18:46 63%   ` [PATCH -v7b " Ahmed S. Darwish
  1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-05 15:29 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, Paul Moore, Alexey Dobriyan, Andrew Morton,
	Linus
  Cc: LKML, LSM-ML

Hi!,

[
    Our usual changelog:

    - Fold the SMACK bugfix here cause now it depends on the
      new introduced security_ symbol.
    - Do not register smackfs if Smack was not loaded
    - Do not use a global to check if Smack was enabled, use 
      security_module_enable(ops) instead.
    - Export smack_ops security operations to the rest of
      SMACK code to satisfy above point.
    - Remove James ACK cause patch semantics changed (could you
      please reACK ?).
]

-->

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Do not let SMACK register smackfs if it was not chosen on
boot. Smackfs assumes that smack hooks are registered and
the initial task security setup (swapper->security) is done.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Reported-by: Alexey Dobriyan <adobriyan@sw.ru>
---

 Documentation/kernel-parameters.txt |    6 ++++
 include/linux/security.h            |   12 +++++++++
 security/dummy.c                    |    2 -
 security/security.c                 |   46 +++++++++++++++++++++++++++++++++++-
 security/selinux/hooks.c            |    7 +++++
 security/smack/smack.h              |    2 +
 security/smack/smack_lsm.c          |    7 ++++-
 security/smack/smackfs.c            |    9 ++++++-

 8 files changed, 87 insertions(+), 4 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a5b665..64efbdc 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index fe52cde..801c9ad 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 
 /*
@@ -117,6 +120,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as a unique identifeir for the LSM with max number
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1207,6 +1216,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1466,6 +1477,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 649326b..96d196f 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -979,7 +979,7 @@ static inline int dummy_key_permission(key_ref_t key_ref,
 }
 #endif /* CONFIG_KEYS */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { "dummy" };
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
diff --git a/security/security.c b/security/security.c
index d15e56c..f188672 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static spinlock_t chosen_lsm_lock;
+static char chosen_lsm[SECURITY_NAME_MAX + 1];
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -62,18 +65,59 @@ int __init security_init(void)
 	}
 
 	security_ops = &dummy_security_ops;
+	spin_lock_init(&chosen_lsm_lock);
 	do_security_initcalls();
 
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Each LSM must pass this method before registering its own operations
+ * to avoid security registration races.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin.
+ * Otherwise, return false.
+ */
+int security_module_enable(struct security_operations *ops)
+{
+	int rc = 1;
+
+	spin_lock(&chosen_lsm_lock);
+	if (!*chosen_lsm)
+		strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
+	else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		rc = 0;
+	spin_unlock(&chosen_lsm_lock);
+
+	if (rc)
+		printk(KERN_INFO "Security: Loading '%s' security module.\n",
+		       ops->name);
+
+	return rc;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 75c2e99..49709a4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5219,6 +5219,8 @@ static int selinux_key_permission(key_ref_t key_ref,
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5405,6 +5407,11 @@ static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
+	if (!security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
+		return 0;
+	}
+
 	if (!selinux_enabled) {
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index a21a0e9..c444f48 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -15,6 +15,7 @@
 
 #include <linux/capability.h>
 #include <linux/spinlock.h>
+#include <linux/security.h>
 #include <net/netlabel.h>
 
 /*
@@ -195,6 +196,7 @@ extern struct smack_known smack_known_star;
 extern struct smack_known smack_known_unset;
 
 extern struct smk_list_entry *smack_list;
+extern struct security_operations smack_ops;
 
 /*
  * Stricly for CIPSO level manipulation.
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 770eb06..afa7967 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2433,7 +2433,9 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 {
 }
 
-static struct security_operations smack_ops = {
+struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2566,6 +2568,9 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 358c92c..769da9a 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -986,12 +986,19 @@ static struct vfsmount *smackfs_mount;
  *
  * register the smackfs
  *
- * Returns 0 unless the registration fails.
+ * Do not register smackfs if Smack wasn't enabled
+ * on boot.
+ *
+ * Returns true if we were not chosen on boot or if
+ * we were chosen and filesystem registration succeeded.
  */
 static int __init init_smk_fs(void)
 {
 	int err;
 
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	err = register_filesystem(&smk_fs_type);
 	if (!err) {
 		smackfs_mount = kern_mount(&smk_fs_type);

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 66%]

* Re: [PATCH -v7 -rc3] Security: Introduce security= boot parameter
  @ 2008-03-05 16:55 97%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-05 16:55 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Paul Moore, Alexey Dobriyan, Andrew Morton, Linus, LKML, LSM-ML

Hi Casey,

On Wed, Mar 05, 2008 at 08:33:34AM -0800, Casey Schaufler wrote:
> 
> --- "Ahmed S. Darwish" <darwish.07@gmail.com> wrote:
> 
...
> > 
> > Do not let SMACK register smackfs if it was not chosen on
> > boot. Smackfs assumes that smack hooks are registered and
> > the initial task security setup (swapper->security) is done.
> 
> If the problem with initializing smackfs is because the
> locks aren't initialized why not leave the lock initializations
> in smack_init, and have them done before the check to see if the
> smack LSM is going to get used? Really, we're only talking
> about the case where a kernel is configured for testing or
> development purposes, and the lock initialization can't
> be considered a major impact in any case.
> 

Beside the locking initialization issue, there's the current->security
issue. smackfs init code code access current->security in 
smk_unlbl_ambient().

As you know current->security may equal Null (Oops), or point to 
another LSM structure that preceeded us in registration. 

The locking argument can't be applied here since we may override
the other LSM tsk->security pointer this time.

Ofcourse all of the above points can be handleded by various
if(current->security) checks + rechecking the read/write methods
of each smackfs inode, but below only two lines will fix the 
problem from its roots ;):

+	if (!security_module_enable(&smack_ops))
+		return 0;

Is there a problem in the current approach that I'm not aware of ?

You have your veto in this issue at the end ;)

Thank you,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 97%]

* [PATCH -v7b -rc3] Security: Introduce security= boot parameter
  2008-03-04 13:58 69% ` [PATCH -rc3] Security: Introduce security= boot parameter Ahmed S. Darwish
  2008-03-05 15:29 66%   ` [PATCH -v7 " Ahmed S. Darwish
@ 2008-03-05 18:46 63%   ` Ahmed S. Darwish
  1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-05 18:46 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, Paul Moore, Alexey Dobriyan, Andrew Morton,
	Linus
  Cc: LKML, LSM-ML

Hi!,

[
v7 log:
    - Fold the SMACK bugfix here cause now it depends on the
      new introduced security_ symbol.
    - Do not register smackfs if Smack was not loaded
    - Do not use a global to check if Smack was enabled, use 
      security_module_enable(ops) instead.
    - Export smack_ops security operations to the rest of
      SMACK code to satisfy above point.
    - Remove James ACK cause patch semantics changed (could you
      please reACK ?).      

++:
    - Add in security_module_enable() comments that it may also
      be used to check if our LSM is enabled on boot.
    - Remove the message `Security: %s is loaded, &lsm' from 
      security_module_enable cause of its new usage in above
      point.
    - Smack: Add a comment above init_smk_fs explaining why we
      can't initialize smackfs under the security_init context.
    - mmm, Will we reach v10 ?
]

-->

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Do not let SMACK register smackfs if it was not chosen on
boot. Smackfs assumes that smack hooks are registered and
the initial task security setup (swapper->security) is done.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Reported-by: Alexey Dobriyan <adobriyan@sw.ru>
--- 

 Documentation/kernel-parameters.txt |    6 ++++
 include/linux/security.h            |   12 +++++++++
 security/dummy.c                    |    2 -
 security/security.c                 |   46 +++++++++++++++++++++++++++++++++++-
 security/selinux/hooks.c            |    7 +++++
 security/smack/smack.h              |    2 +
 security/smack/smack_lsm.c          |    7 ++++-
 security/smack/smackfs.c            |   11 +++++++-

 8 files changed, 89 insertions(+), 4 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a5b665..64efbdc 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index fe52cde..801c9ad 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 
 /*
@@ -117,6 +120,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as a unique identifeir for the LSM with max number
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1207,6 +1216,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1466,6 +1477,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 649326b..96d196f 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -979,7 +979,7 @@ static inline int dummy_key_permission(key_ref_t key_ref,
 }
 #endif /* CONFIG_KEYS */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { "dummy" };
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
diff --git a/security/security.c b/security/security.c
index d15e56c..deb7e00 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static spinlock_t chosen_lsm_lock;
+static char chosen_lsm[SECURITY_NAME_MAX + 1];
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -62,18 +65,59 @@ int __init security_init(void)
 	}
 
 	security_ops = &dummy_security_ops;
+	spin_lock_init(&chosen_lsm_lock);
 	do_security_initcalls();
 
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Each LSM must pass this method before registering its own operations
+ * to avoid security registration races. This method may also be used
+ * to check if your LSM is currently loaded.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin,
+ *	-or the passed LSM is currently loaded.
+ * Otherwise, return false.
+ */
+int security_module_enable(struct security_operations *ops)
+{
+	int rc = 1;
+
+	spin_lock(&chosen_lsm_lock);
+
+	if (!*chosen_lsm)
+		strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
+	else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		rc = 0;
+
+	spin_unlock(&chosen_lsm_lock);
+
+	return rc;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 75c2e99..49709a4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5219,6 +5219,8 @@ static int selinux_key_permission(key_ref_t key_ref,
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5405,6 +5407,11 @@ static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
+	if (!security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
+		return 0;
+	}
+
 	if (!selinux_enabled) {
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index a21a0e9..c444f48 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -15,6 +15,7 @@
 
 #include <linux/capability.h>
 #include <linux/spinlock.h>
+#include <linux/security.h>
 #include <net/netlabel.h>
 
 /*
@@ -195,6 +196,7 @@ extern struct smack_known smack_known_star;
 extern struct smack_known smack_known_unset;
 
 extern struct smk_list_entry *smack_list;
+extern struct security_operations smack_ops;
 
 /*
  * Stricly for CIPSO level manipulation.
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 770eb06..afa7967 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2433,7 +2433,9 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 {
 }
 
-static struct security_operations smack_ops = {
+struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2566,6 +2568,9 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 358c92c..effd3de 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -986,12 +986,21 @@ static struct vfsmount *smackfs_mount;
  *
  * register the smackfs
  *
- * Returns 0 unless the registration fails.
+ * Do not register smackfs if Smack wasn't enabled
+ * on boot. We can not put this method normally under the
+ * smack_init() code path since the security subsystem get
+ * initialized before the vfs caches.
+ *
+ * Returns true if we were not chosen on boot or if
+ * we were chosen and filesystem registration succeeded.
  */
 static int __init init_smk_fs(void)
 {
 	int err;
 
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	err = register_filesystem(&smk_fs_type);
 	if (!err) {
 		smackfs_mount = kern_mount(&smk_fs_type);

--
"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 63%]

* Re: [PATCH -v5 -mm] LSM: Add security= boot parameter
  @ 2008-03-05 22:56 96%                       ` Ahmed S. Darwish
  2008-03-05 23:06 99%                         ` Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-05 22:56 UTC (permalink / raw)
  To: Andrew Morton
  Cc: jmorris, sds, casey, bunk, chrisw, eparis, adobriyan,
	linux-kernel, linux-security-module

On Wed, Mar 05, 2008 at 02:29:48PM -0800, Andrew Morton wrote:
> On Tue, 4 Mar 2008 05:04:07 +0200
> "Ahmed S. Darwish" <darwish.07@gmail.com> wrote:
> 
...
> > ...
> >  
> > +/* Maximum number of letters for an LSM name string */
> > +#define SECURITY_NAME_MAX	10
> 
> Is this long enough?
> 

I've judged from the four common applicants (selinux, smack,
apparmor, tomoyo) that 10 would be enough. Anyway this will be
easy to fix when something longer appears.

> >  struct ctl_table;
> >  struct audit_krule;
> >  
> >  ...
> >
> > -struct security_operations dummy_security_ops;
> > +struct security_operations dummy_security_ops = { "dummy" };
> 
> Please don't rely upon the layout of data structures in this manner.  Use
> ".name = ".
> 

Will do.

> >  
> >  #define set_to_dummy_if_null(ops, function)				\
> >  	do {								\
> > diff --git a/security/security.c b/security/security.c
> > index 1bf2ee4..def9fc0 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -17,6 +17,9 @@
> >  #include <linux/kernel.h>
> >  #include <linux/security.h>
> >  
> > +/* Boot-time LSM user choice */
> > +static spinlock_t chosen_lsm_lock;
> > +static char chosen_lsm[SECURITY_NAME_MAX + 1];
> >  
> >  /* things that live in dummy.c */
> >  extern struct security_operations dummy_security_ops;
> > @@ -62,18 +65,59 @@ int __init security_init(void)
> >  	}
> >  
> >  	security_ops = &dummy_security_ops;
> > +	spin_lock_init(&chosen_lsm_lock);
> 
> Please remove this and use compile-time initialisation with DEFINE_SPINLOCK.
> 

Ooh I thought the dynamic one was better cause I remember I read it
somewhere on LWN that this is nicer for the RT-patches. I'll modify
it, no problem.

> Do we actually need the lock?  This code is only called at boot-time if I
> understand it correctly?
> 

In the latest version (-v7b, in another thread, CCed), security_module_enable()
is also used to let an LSM know if it's currently loaded or not. This
was done to avoid using a `smack_enabled' global.

I'll resend the v7b for -mm once the LSM devs give their ACKs for the
-rc3 one.

> Can chosen_lsm[] be __initdata?
> 

You're the expert ;), I don't really understand the difference.

...
> >
> > +/**
> > + * security_module_enable - Load given security module on boot ?
> > + * @ops: a pointer to the struct security_operations that is to be checked.
> > + *
> > + * Each LSM must pass this method before registering its own operations
> > + * to avoid security registration races.
> > + *
> > + * Return true if:
> > + *	-The passed LSM is the one chosen by user at boot time,
> > + *	-or user didsn't specify a specific LSM and we're the first to ask
> > + *	 for registeration permissoin.
> > + * Otherwise, return false.
> > + */
> > +int security_module_enable(struct security_operations *ops)
> > +{
> > +	int rc = 1;
> > +
> > +	spin_lock(&chosen_lsm_lock);
> > +	if (!*chosen_lsm)
> > +		strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
> > +	else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
> > +		rc = 0;
> > +	spin_unlock(&chosen_lsm_lock);
> > +
> > +	if (rc)
> > +		printk(KERN_INFO "Security: Loading '%s' security module.\n",
> > +		       ops->name);
> > +
> > +	return rc;
> > +}
> 
> I believe this can be __init.
> 

Will do.

> > +	if (!security_module_enable(&selinux_ops)) {
> > +		selinux_enabled = 0;
> > +		return 0;
> > +	}
> > +
> >
> > ...
> >
> >  static __init int smack_init(void)
> >  {
> > +	if (!security_module_enable(&smack_ops))
> > +		return 0;
> > +
> >  	printk(KERN_INFO "Smack:  Initializing.\n");
> >  
> >  	/*
> 
> hm.  selinux has a global selinux_enabled knob, but smack seems to be able
> to get by without one.  +1 for smack ;)
> 

Thanks to Linus ;). 

I've sent a patch that added a similar global yesterday and it was 
knocked-down by Linus after exactly 2 minutes. 
The situation is handled now without a global in v7/v7b.

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 96%]

* Re: [PATCH -v5 -mm] LSM: Add security= boot parameter
  2008-03-05 22:56 96%                       ` Ahmed S. Darwish
@ 2008-03-05 23:06 99%                         ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-05 23:06 UTC (permalink / raw)
  To: Andrew Morton
  Cc: jmorris, sds, casey, bunk, chrisw, eparis, adobriyan,
	linux-kernel, linux-security-module

On Thu, Mar 06, 2008 at 12:56:28AM +0200, Ahmed S. Darwish wrote:
> On Wed, Mar 05, 2008 at 02:29:48PM -0800, Andrew Morton wrote:
> > On Tue, 4 Mar 2008 05:04:07 +0200
> > "Ahmed S. Darwish" <darwish.07@gmail.com> wrote:
> > 
> > Can chosen_lsm[] be __initdata?
> > 
> 
> You're the expert ;), I don't really understand the difference.
> 

After being a good citizen and reading the comments in init.h, I think
yes it should be marked so. even though we use it from init_smk_fs
since init_smk_fs is also marked as __init.

Thank you,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [PATCH -v8 -rc3] Security: Introduce security= boot parameter
@ 2008-03-06 12:19 66% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-06 12:19 UTC (permalink / raw)
  To: Chris Wright, Stephen Smalley, James Morris, Eric Paris,
	Casey Schaufler, Paul Moore, Alexey Dobriyan, Andrew Morton,
	Linus
  Cc: LKML, LSM-ML

Hi!,

[
    Handle Andrew's concerns:
    - Use __init and __initdata in appropriate places.
    - Do not rely upon dummy_ops layout, use C99 initializations.
    - Use DEFINE_SPINLOCK instead of dynamic initialization.

    Create a new thread cause the original became hard to follow.
]

-->

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Do not let SMACK register smackfs if it was not chosen on
boot. Smackfs assumes that smack hooks are registered and
the initial task security setup (swapper->security) is done.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
--- 

 Documentation/kernel-parameters.txt |    6 ++++
 include/linux/security.h            |   12 +++++++++
 security/dummy.c                    |    4 ++-
 security/security.c                 |   45 +++++++++++++++++++++++++++++++++++-
 security/selinux/hooks.c            |    7 +++++
 security/smack/smack.h              |    2 +
 security/smack/smack_lsm.c          |    7 ++++-
 security/smack/smackfs.c            |   11 ++++++++

 8 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a5b665..64efbdc 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index fe52cde..801c9ad 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 
 /*
@@ -117,6 +120,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as a unique identifeir for the LSM with max number
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1207,6 +1216,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1466,6 +1477,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 649326b..b668fda 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -979,7 +979,9 @@ static inline int dummy_key_permission(key_ref_t key_ref,
 }
 #endif /* CONFIG_KEYS */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { 
+	.name = "dummy", 
+};
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
diff --git a/security/security.c b/security/security.c
index d15e56c..768f171 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static __initdata DEFINE_SPINLOCK(chosen_lsm_lock);
+static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -67,13 +70,53 @@ int __init security_init(void)
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Each LSM must pass this method before registering its own operations
+ * to avoid security registration races. This method may also be used
+ * to check if your LSM is currently loaded.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin,
+ *	-or the passed LSM is currently loaded.
+ * Otherwise, return false.
+ */
+int __init security_module_enable(struct security_operations *ops)
+{
+	int rc = 1;
+
+	spin_lock(&chosen_lsm_lock);
+
+	if (!*chosen_lsm)
+		strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
+	else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		rc = 0;
+
+	spin_unlock(&chosen_lsm_lock);
+
+	return rc;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 75c2e99..49709a4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5219,6 +5219,8 @@ static int selinux_key_permission(key_ref_t key_ref,
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5405,6 +5407,11 @@ static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
+	if (!security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
+		return 0;
+	}
+
 	if (!selinux_enabled) {
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index a21a0e9..c444f48 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -15,6 +15,7 @@
 
 #include <linux/capability.h>
 #include <linux/spinlock.h>
+#include <linux/security.h>
 #include <net/netlabel.h>
 
 /*
@@ -195,6 +196,7 @@ extern struct smack_known smack_known_star;
 extern struct smack_known smack_known_unset;
 
 extern struct smk_list_entry *smack_list;
+extern struct security_operations smack_ops;
 
 /*
  * Stricly for CIPSO level manipulation.
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 770eb06..afa7967 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2433,7 +2433,9 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 {
 }
 
-static struct security_operations smack_ops = {
+struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2566,6 +2568,9 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 358c92c..effd3de 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -986,12 +986,21 @@ static struct vfsmount *smackfs_mount;
  *
  * register the smackfs
  *
- * Returns 0 unless the registration fails.
+ * Do not register smackfs if Smack wasn't enabled
+ * on boot. We can not put this method normally under the
+ * smack_init() code path since the security subsystem get
+ * initialized before the vfs caches.
+ *
+ * Returns true if we were not chosen on boot or if
+ * we were chosen and filesystem registration succeeded.
  */
 static int __init init_smk_fs(void)
 {
 	int err;
 
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	err = register_filesystem(&smk_fs_type);
 	if (!err) {
 		smackfs_mount = kern_mount(&smk_fs_type);


-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 66%]

* Re: [PATCH -v8 -rc3] Security: Introduce security= boot parameter
  @ 2008-03-06 14:32 99%   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-06 14:32 UTC (permalink / raw)
  To: James Morris
  Cc: Chris Wright, Stephen Smalley, Eric Paris, Casey Schaufler,
	Paul Moore, Alexey Dobriyan, Andrew Morton, Linus, LKML, LSM-ML

Hi James,

On Thu, Mar 6, 2008, James Morris <jmorris@namei.org> wrote:
> On Thu, 6 Mar 2008, Ahmed S. Darwish wrote:
>
>  >     Handle Andrew's concerns:
>  >     - Use __init and __initdata in appropriate places.
>  >     - Do not rely upon dummy_ops layout, use C99 initializations.
>  >     - Use DEFINE_SPINLOCK instead of dynamic initialization.
>
>  The spinlock is not needed now, if security_module_enable() can only be
>  called during boot via an initcall.
>

Will do.

Would you mind answering my confusions below so I can do the change
with good understanding ?

I see preempt_disable() before calling security and vfs_caches init,
but what will prevent two processors/cores from executing
security_module_enable() concurrently (thus possibly corrupting
chosen_lsm) ?
security_module_enable() is also now used in __init init_smk_fs().

Or the init path got executed serially ?

Thank you,

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH -v8b -rc3] Security: Introduce security= boot parameter
  @ 2008-03-06 16:09 66%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-06 16:09 UTC (permalink / raw)
  To: James Morris
  Cc: Chris Wright, Stephen Smalley, Eric Paris, Casey Schaufler,
	Paul Moore, Alexey Dobriyan, Andrew Morton, Linus, LKML, LSM-ML

Hi,

[ 
    Thanks James for all those helpful comments since patch-v1!.

    - Remove spinlocks since we've dictated to use security_module_enable()
      under kernel init path only (__init).
]

-->

Add the security= boot parameter. This is done to avoid LSM 
registration clashes in case of more than one bult-in module.

User can choose a security module to enable at boot. If no 
security= boot parameter is specified, only the first LSM 
asking for registration will be loaded. An invalid security 
module name will be treated as if no module has been chosen.

LSM modules must check now if they are allowed to register
by calling security_module_enable(ops) first. Modify SELinux 
and SMACK to do so.

Do not let SMACK register smackfs if it was not chosen on
boot. Smackfs assumes that smack hooks are registered and
the initial task security setup (swapper->security) is done.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
--- 

 Documentation/kernel-parameters.txt |    6 +++++
 include/linux/security.h            |   12 +++++++++++
 security/dummy.c                    |    4 ++-
 security/security.c                 |   38 +++++++++++++++++++++++++++++++++++-
 security/selinux/hooks.c            |    7 ++++++
 security/smack/smack.h              |    2 +
 security/smack/smack_lsm.c          |    7 +++++-
 security/smack/smackfs.c            |   11 +++++++++-

 8 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a5b665..64efbdc 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -374,6 +374,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 
+	security=	[SECURITY] Choose a security module to enable at boot. 
+			If this boot parameter is not specified, only the first 
+			security module asking for security registration will be
+			loaded. An invalid security module name will be treated
+			as if no module has been chosen.
+
 	capability.disable=
 			[SECURITY] Disable capabilities.  This would normally
 			be used only if an alternative security model is to be
diff --git a/include/linux/security.h b/include/linux/security.h
index fe52cde..801c9ad 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -42,6 +42,9 @@
 
 extern unsigned securebits;
 
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX	10
+
 struct ctl_table;
 
 /*
@@ -117,6 +120,12 @@ struct request_sock;
 /**
  * struct security_operations - main security structure
  *
+ * Security module identifier.
+ *
+ * @name:
+ *	A string that acts as a unique identifeir for the LSM with max number
+ *	of characters = SECURITY_NAME_MAX.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
@@ -1207,6 +1216,8 @@ struct request_sock;
  * This is the main security structure.
  */
 struct security_operations {
+	char name[SECURITY_NAME_MAX + 1];
+
 	int (*ptrace) (struct task_struct * parent, struct task_struct * child);
 	int (*capget) (struct task_struct * target,
 		       kernel_cap_t * effective,
@@ -1466,6 +1477,7 @@ struct security_operations {
 
 /* prototypes */
 extern int security_init	(void);
+extern int security_module_enable(struct security_operations *ops);
 extern int register_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
diff --git a/security/dummy.c b/security/dummy.c
index 649326b..b668fda 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -979,7 +979,9 @@ static inline int dummy_key_permission(key_ref_t key_ref,
 }
 #endif /* CONFIG_KEYS */
 
-struct security_operations dummy_security_ops;
+struct security_operations dummy_security_ops = { 
+	.name = "dummy", 
+};
 
 #define set_to_dummy_if_null(ops, function)				\
 	do {								\
diff --git a/security/security.c b/security/security.c
index d15e56c..8d67e73 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,8 @@
 #include <linux/kernel.h>
 #include <linux/security.h>
 
+/* Boot-time LSM user choice */
+static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
@@ -67,13 +69,47 @@ int __init security_init(void)
 	return 0;
 }
 
+/* Save user chosen LSM */
+static int __init choose_lsm(char *str)
+{
+	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	return 1;
+}
+__setup("security=", choose_lsm);
+
+/**
+ * security_module_enable - Load given security module on boot ?
+ * @ops: a pointer to the struct security_operations that is to be checked.
+ *
+ * Each LSM must pass this method before registering its own operations
+ * to avoid security registration races. This method may also be used
+ * to check if your LSM is currently loaded.
+ *
+ * Return true if:
+ *	-The passed LSM is the one chosen by user at boot time,
+ *	-or user didsn't specify a specific LSM and we're the first to ask
+ *	 for registeration permissoin,
+ *	-or the passed LSM is currently loaded.
+ * Otherwise, return false.
+ */
+int __init security_module_enable(struct security_operations *ops)
+{
+	if (!*chosen_lsm)
+		strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
+	else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
+		return 0;
+
+	return 1;
+}
+
 /**
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function is to allow a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
- * value passed to this function.
+ * value passed to this function. You'll need to check first if your LSM
+ * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 75c2e99..49709a4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5219,6 +5219,8 @@ static int selinux_key_permission(key_ref_t key_ref,
 #endif
 
 static struct security_operations selinux_ops = {
+	.name =				"selinux",
+
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -5405,6 +5407,11 @@ static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
+	if (!security_module_enable(&selinux_ops)) {
+		selinux_enabled = 0;
+		return 0;
+	}
+
 	if (!selinux_enabled) {
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index a21a0e9..c444f48 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -15,6 +15,7 @@
 
 #include <linux/capability.h>
 #include <linux/spinlock.h>
+#include <linux/security.h>
 #include <net/netlabel.h>
 
 /*
@@ -195,6 +196,7 @@ extern struct smack_known smack_known_star;
 extern struct smack_known smack_known_unset;
 
 extern struct smk_list_entry *smack_list;
+extern struct security_operations smack_ops;
 
 /*
  * Stricly for CIPSO level manipulation.
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 770eb06..afa7967 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2433,7 +2433,9 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 {
 }
 
-static struct security_operations smack_ops = {
+struct security_operations smack_ops = {
+	.name =				"smack",
+
 	.ptrace = 			smack_ptrace,
 	.capget = 			cap_capget,
 	.capset_check = 		cap_capset_check,
@@ -2566,6 +2568,9 @@ static struct security_operations smack_ops = {
  */
 static __init int smack_init(void)
 {
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	printk(KERN_INFO "Smack:  Initializing.\n");
 
 	/*
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 358c92c..effd3de 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -986,12 +986,21 @@ static struct vfsmount *smackfs_mount;
  *
  * register the smackfs
  *
- * Returns 0 unless the registration fails.
+ * Do not register smackfs if Smack wasn't enabled
+ * on boot. We can not put this method normally under the
+ * smack_init() code path since the security subsystem get
+ * initialized before the vfs caches.
+ *
+ * Returns true if we were not chosen on boot or if
+ * we were chosen and filesystem registration succeeded.
  */
 static int __init init_smk_fs(void)
 {
 	int err;
 
+	if (!security_module_enable(&smack_ops))
+		return 0;
+
 	err = register_filesystem(&smk_fs_type);
 	if (!err) {
 		smackfs_mount = kern_mount(&smk_fs_type);

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 66%]

* [PATCH BUGFIX -rc4] Smackfs: Do not trust `count' in inodes write()s
@ 2008-03-08 21:38 85% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-08 21:38 UTC (permalink / raw)
  To: Casey Schaufler, akpm; +Cc: LKML, Linus

Hi all,

Smackfs write() implementation does not put a higher bound on the 
number of bytes to copy from user-space. This may lead to a DOS
attack if a malicious `count' field is given. 

Assure that given `count' is exactly the length needed for a 
/smack/load rule. In case of /smack/cipso where the length is 
relative, assure that `count' does not exceed the size needed for 
a buffer representing maximum possible number of CIPSO 2.2 
categories.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 smack.h   |    8 --------
 smackfs.c |   31 ++++++++++++++++++++-----------
 2 files changed, 20 insertions(+), 19 deletions(-)

Smack user-space utilities (smackload, smackcipso) still work 
fine after below change.

[
  Who's responsible for forwarding Smack patches to Linus ?
  I've CCed Andrew and Linus just in case.
]

diff --git a/security/smack/smack.h b/security/smack/smack.h
index c444f48..4a4477f 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -27,14 +27,6 @@
 #define SMK_MAXLEN	23
 #define SMK_LABELLEN	(SMK_MAXLEN+1)
 
-/*
- * How many kinds of access are there?
- * Here's your answer.
- */
-#define SMK_ACCESSDASH	'-'
-#define SMK_ACCESSLOW	"rwxa"
-#define SMK_ACCESSKINDS	(sizeof(SMK_ACCESSLOW) - 1)
-
 struct superblock_smack {
 	char		*smk_root;
 	char		*smk_floor;
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index effd3de..3fc3a07 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -81,10 +81,23 @@ static struct semaphore smack_write_sem;
 /*
  * Values for parsing cipso rules
  * SMK_DIGITLEN: Length of a digit field in a rule.
- * SMK_CIPSOMEN: Minimum possible cipso rule length.
+ * SMK_CIPSOMIN: Minimum possible cipso rule length.
+ * SMK_CIPSOMAX: Maximum possible cipso rule length.
  */
 #define SMK_DIGITLEN 4
-#define SMK_CIPSOMIN (SMK_MAXLEN + 2 * SMK_DIGITLEN)
+#define SMK_CIPSOMIN (SMK_LABELLEN + 2 * SMK_DIGITLEN)
+#define SMK_CIPSOMAX (SMK_CIPSOMIN + SMACK_CIPSO_MAXCATNUM * SMK_DIGITLEN)
+
+/*
+ * Values for parsing MAC rules
+ * SMK_ACCESS: Maximum possible combination of access permissions
+ * SMK_ACCESSLEN: Maximum length for a rule access field
+ * SMK_LOADLEN: Smack rule length
+ */
+#define SMK_ACCESS    "rwxa"
+#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
+#define SMK_LOADLEN   (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
+
 
 /*
  * Seq_file read operations for /smack/load
@@ -229,14 +242,10 @@ static void smk_set_access(struct smack_rule *srp)
  * The format is exactly:
  *     char subject[SMK_LABELLEN]
  *     char object[SMK_LABELLEN]
- *     char access[SMK_ACCESSKINDS]
- *
- *     Anything following is commentary and ignored.
+ *     char access[SMK_ACCESSLEN]
  *
- * writes must be SMK_LABELLEN+SMK_LABELLEN+4 bytes.
+ * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes.
  */
-#define MINIMUM_LOAD (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSKINDS)
-
 static ssize_t smk_write_load(struct file *file, const char __user *buf,
 			      size_t count, loff_t *ppos)
 {
@@ -253,7 +262,7 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
 		return -EPERM;
 	if (*ppos != 0)
 		return -EINVAL;
-	if (count < MINIMUM_LOAD)
+	if (count != SMK_LOADLEN)
 		return -EINVAL;
 
 	data = kzalloc(count, GFP_KERNEL);
@@ -513,7 +522,7 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
 		return -EPERM;
 	if (*ppos != 0)
 		return -EINVAL;
-	if (count <= SMK_CIPSOMIN)
+	if (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX)
 		return -EINVAL;
 
 	data = kzalloc(count + 1, GFP_KERNEL);
@@ -547,7 +556,7 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
 	if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM)
 		goto out;
 
-	if (count <= (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
+	if (count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
 		goto out;
 
 	memset(mapcatset, 0, sizeof(mapcatset));

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 85%]

* [RFC][PATCH] Smack<->Audit integration
@ 2008-03-10 12:49 58% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-10 12:49 UTC (permalink / raw)
  To: Casey Schaufler, Andrew Morton, James Morris
  Cc: Paul Moore, LKML, LSM-ML, Audit-ML

Hi all,

This is the second step of integrating Audit with Smack. 

The AUDIT_SUBJ_USER and AUDIT_OBJ_USER SELinux flags are recycled
for Smack to avoid `auditd' userspace modifications. Smack only
needs auditing on subject/object bases, so those flags were enough.

Patch below setups the new Audit LSM hooks and add a secid field in 
smack inode and ipc security structures. The secid field was needed
cause it's the main Audit way of distinguishing kernel objects to
be audited from the remaining ones.

Possibly the last steps would be to:
1- report smack access grants and denials through Audit (like AVC)
2- Letting Audit send an OBJ_USER event in case of a process that 
   recieved a signal without affecting SELinux.

Thank you for your reviews.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 smack.h     |    9 ++
 smack_lsm.c |  211 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----

 2 files changed, 200 insertions(+), 17 deletions(-)

Patch is generated over James security/next branch cause it's the 
only tree that currently has the Audit hooks merged:
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git#next

diff --git a/security/smack/smack.h b/security/smack/smack.h
index c444f48..2c8bb4c 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -57,6 +57,15 @@ struct inode_smack {
 	char		*smk_inode;	/* label of the fso */
 	struct mutex	smk_lock;	/* initialization lock */
 	int		smk_flags;	/* smack inode flags */
+	int		secid;		/* security identifier */
+};
+
+/*
+ * IPC smack data
+ */
+struct ipc_smack {
+	char		*smk_ipc;	/* ipc object label */
+	int		secid;		/* security identifier */
 };
 
 #define	SMK_INODE_INSTANT	0x01	/* inode is instantiated */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index afa7967..5b5e1fd 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -6,6 +6,9 @@
  *  Author:
  *	Casey Schaufler <casey@schaufler-ca.com>
  *
+ *  Audit integration by:
+ *	Ahmed S. Darwish <darwish.07@gmail.com>
+ *
  *  Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -24,6 +27,7 @@
 #include <linux/udp.h>
 #include <linux/mutex.h>
 #include <linux/pipe_fs_i.h>
+#include <linux/audit.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 
@@ -75,6 +79,7 @@ struct inode_smack *new_inode_smack(char *smack)
 
 	isp->smk_inode = smack;
 	isp->smk_flags = 0;
+	isp->secid = smack_to_secid(smack);
 	mutex_init(&isp->smk_lock);
 
 	return isp;
@@ -638,6 +643,8 @@ static void smack_inode_post_setxattr(struct dentry *dentry, char *name,
 	else
 		isp->smk_inode = smack_known_invalid.smk_known;
 
+	isp->secid = smack_to_secid(isp->smk_inode);
+
 	return;
 }
 
@@ -759,6 +766,17 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
 	return -EINVAL;
 }
 
+/**
+ * smack_inode_getsecid - Extract inode's security id
+ * @inode: inode to extract the info from
+ * @secid: where the result will be saved
+ */
+static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	struct inode_smack *isp = inode->i_security;
+	*secid = isp->secid;
+}
+
 /*
  * File Hooks
  */
@@ -1344,6 +1362,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
 				   const void *value, size_t size, int flags)
 {
 	char *sp;
+	struct smack_known *skp;
 	struct inode_smack *nsp = inode->i_security;
 	struct socket_smack *ssp;
 	struct socket *sock;
@@ -1352,12 +1371,14 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
 	if (value == NULL || size > SMK_LABELLEN)
 		return -EACCES;
 
-	sp = smk_import(value, size);
-	if (sp == NULL)
+	skp = smk_import_entry(value, size);
+	if (skp == NULL)
 		return -EINVAL;
 
+	sp = skp->smk_known;
 	if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
 		nsp->smk_inode = sp;
+		nsp->secid = skp->smk_secid;
 		return 0;
 	}
 	/*
@@ -1471,9 +1492,16 @@ static char *smack_of_shm(struct shmid_kernel *shp)
  */
 static int smack_shm_alloc_security(struct shmid_kernel *shp)
 {
-	struct kern_ipc_perm *isp = &shp->shm_perm;
+	struct ipc_smack *isp;
+	struct kern_ipc_perm *ipcp = &shp->shm_perm;
 
-	isp->security = current->security;
+	isp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL);
+	if (isp == NULL)
+		return -ENOMEM;
+
+	isp->smk_ipc = current->security;
+	isp->secid = smack_to_secid(isp->smk_ipc);
+	ipcp->security = isp;
 	return 0;
 }
 
@@ -1485,9 +1513,9 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
  */
 static void smack_shm_free_security(struct shmid_kernel *shp)
 {
-	struct kern_ipc_perm *isp = &shp->shm_perm;
+	struct kern_ipc_perm *ipcp = &shp->shm_perm;
 
-	isp->security = NULL;
+	kfree(ipcp->security);
 }
 
 /**
@@ -1579,9 +1607,16 @@ static char *smack_of_sem(struct sem_array *sma)
  */
 static int smack_sem_alloc_security(struct sem_array *sma)
 {
-	struct kern_ipc_perm *isp = &sma->sem_perm;
+	struct ipc_smack *isp;
+	struct kern_ipc_perm *ipcp = &sma->sem_perm;
+
+	isp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL);
+	if (isp == NULL)
+		return -ENOMEM;
 
-	isp->security = current->security;
+	isp->smk_ipc = current->security;
+	isp->secid = smack_to_secid(isp->smk_ipc);
+	ipcp->security = isp;
 	return 0;
 }
 
@@ -1595,7 +1630,7 @@ static void smack_sem_free_security(struct sem_array *sma)
 {
 	struct kern_ipc_perm *isp = &sma->sem_perm;
 
-	isp->security = NULL;
+	kfree(isp->security);
 }
 
 /**
@@ -1682,9 +1717,16 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
  */
 static int smack_msg_queue_alloc_security(struct msg_queue *msq)
 {
-	struct kern_ipc_perm *kisp = &msq->q_perm;
+	struct ipc_smack *isp;
+	struct kern_ipc_perm *ipcp = &msq->q_perm;
 
-	kisp->security = current->security;
+	isp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL);
+	if (isp == NULL)
+		return -ENOMEM;
+
+	isp->smk_ipc = current->security;
+	isp->secid = smack_to_secid(isp->smk_ipc);
+	ipcp->security = isp;
 	return 0;
 }
 
@@ -1696,9 +1738,9 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
  */
 static void smack_msg_queue_free_security(struct msg_queue *msq)
 {
-	struct kern_ipc_perm *kisp = &msq->q_perm;
+	struct kern_ipc_perm *ipcp = &msq->q_perm;
 
-	kisp->security = NULL;
+	kfree(ipcp->security);
 }
 
 /**
@@ -1800,18 +1842,30 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 
 /**
  * smack_ipc_permission - Smack access for ipc_permission()
- * @ipp: the object permissions
+ * @ipcp: the object permissions
  * @flag: access requested
  *
  * Returns 0 if current has read and write access, error code otherwise
  */
-static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
+static int smack_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 {
-	char *isp = ipp->security;
 	int may;
+	struct ipc_smack *isp = ipcp->security;
 
 	may = smack_flags_to_may(flag);
-	return smk_curacc(isp, may);
+	return smk_curacc(isp->smk_ipc, may);
+}
+
+/**
+ * smack_ipc_getsecid - extract Smack security id
+ * @ipcp: the object permissions
+ * @secid: where result will be saved
+ */
+static void smack_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+	struct inode_smack *isp = ipcp->security;
+
+	*secid = isp->secid;
 }
 
 /* module stacking operations */
@@ -1967,6 +2021,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
 	else
 		isp->smk_inode = final;
 
+	isp->secid = smack_to_secid(isp->smk_inode);
 	isp->smk_flags |= SMK_INODE_INSTANT;
 
 unlockandout:
@@ -2391,6 +2446,116 @@ static int smack_key_permission(key_ref_t key_ref,
 #endif /* CONFIG_KEYS */
 
 /*
+ * Smack Audit hooks
+ *
+ * Audit requires an internal representation of each Smack specific
+ * rule which works as a glue between the audit hooks. Since smack_known
+ * repository entries are added but never deleted, we'll use the
+ * smack_known entry related to the given audit rule as the needed
+ * smack representation.
+ *
+ * This will also save us from searching the smack labels repository
+ * each time the audit_rule_match hook get called.
+ */
+#ifdef CONFIG_AUDIT
+
+/**
+ * smack_audit_rule_init - Initialize a smack audit rule
+ * @field: Message flags given from user-space (audit.h)
+ * @op: Required operation (Only equality testing is allowed)
+ * @rulestr: Given user-space rule
+ * @vrule: Where we'll save our own audit rule representation
+ *
+ * The label to be audited (rulestr) is created if necessay
+ */
+static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+{
+	struct smack_known **smk_rule = (struct smack_known **)vrule;
+	*smk_rule = NULL;
+
+	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+		return -EINVAL;
+
+	if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+		return -EINVAL;
+
+	*smk_rule = smk_import_entry(rulestr, 0);
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_known - Distinguish smack audit rules from others
+ * @krule: rule of interest, in internal kernel representation format
+ *
+ * This is used to filter rules related to Smack from other saved
+ * Audit rules. If it's proved that this rule belongs to us, the
+ * audit_rule_match hook will be used to check a specific kernel
+ * object against its smack audit rule.
+ */
+static int smack_audit_rule_known(struct audit_krule *krule)
+{
+	struct audit_field *f;
+	int i;
+
+	for (i = 0; i < krule->field_count; i++) {
+		f = &krule->fields[i];
+
+		if (f->type == AUDIT_SUBJ_USER || f->type == AUDIT_OBJ_USER)
+			return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_match - Audit given secid identified object ?
+ * @secid: Security id to test
+ * @field: Message flags given from user-space
+ * @op: Required operation (only equality is allowed)
+ * @vrule: Smack audit rule that will be checked against the secid object
+ * @actx: audit context associated with the check (used for Audit logging)
+ *
+ * This is the core Audit hook. It's used to identify objects like 
+ * syscalls and inodes requested from user-space to be audited from 
+ * remaining kernel objects.
+ */
+static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
+				  struct audit_context *actx)
+{
+	struct smack_known *smk_rule = vrule;
+
+	if (!smk_rule) {
+		audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR,
+			  "Smack: missing rule\n");
+		return -ENOENT;
+	}
+
+	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+		return 0;
+
+	if (op == AUDIT_EQUAL)
+		return (smk_rule->smk_secid == secid);
+	if (op == AUDIT_NOT_EQUAL)
+		return (smk_rule->smk_secid != secid);
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_free - free internal audit rule representation
+ * @vrule: rule to be freed.
+ *
+ * No memory was allocated in audit_rule_init.
+ */
+static void smack_audit_rule_free(void *vrule)
+{
+	/* No-op */
+}
+
+#endif /* CONFIG_AUDIT */
+
+/*
  * smack_secid_to_secctx - return the smack label for a secid
  * @secid: incoming integer
  * @secdata: destination
@@ -2476,6 +2641,7 @@ struct security_operations smack_ops = {
 	.inode_getsecurity = 		smack_inode_getsecurity,
 	.inode_setsecurity = 		smack_inode_setsecurity,
 	.inode_listsecurity = 		smack_inode_listsecurity,
+	.inode_getsecid =		smack_inode_getsecid,
 
 	.file_permission = 		smack_file_permission,
 	.file_alloc_security = 		smack_file_alloc_security,
@@ -2506,6 +2672,7 @@ struct security_operations smack_ops = {
 	.task_to_inode = 		smack_task_to_inode,
 
 	.ipc_permission = 		smack_ipc_permission,
+	.ipc_getsecid =			smack_ipc_getsecid,
 
 	.msg_msg_alloc_security = 	smack_msg_msg_alloc_security,
 	.msg_msg_free_security = 	smack_msg_msg_free_security,
@@ -2550,12 +2717,22 @@ struct security_operations smack_ops = {
 	.sk_free_security = 		smack_sk_free_security,
 	.sock_graft = 			smack_sock_graft,
 	.inet_conn_request = 		smack_inet_conn_request,
+
  /* key management security hooks */
 #ifdef CONFIG_KEYS
 	.key_alloc = 			smack_key_alloc,
 	.key_free = 			smack_key_free,
 	.key_permission = 		smack_key_permission,
 #endif /* CONFIG_KEYS */
+
+ /* Audit hooks */
+#ifdef CONFIG_AUDIT
+	.audit_rule_init =		smack_audit_rule_init,
+	.audit_rule_known =		smack_audit_rule_known,
+	.audit_rule_match =		smack_audit_rule_match,
+	.audit_rule_free =		smack_audit_rule_free,
+#endif /* CONFIG_AUDIT */
+
 	.secid_to_secctx = 		smack_secid_to_secctx,
 	.secctx_to_secid = 		smack_secctx_to_secid,
 	.release_secctx = 		smack_release_secctx,

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 58%]

* Re: [RFC][PATCH] Smack<->Audit integration
  @ 2008-03-10 18:26 99%   ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-10 18:26 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Andrew Morton, James Morris, Paul Moore, LKML, LSM-ML, Audit-ML

On Mon, Mar 10, 2008 at 09:07:08AM -0700, Casey Schaufler wrote:
> 
> --- "Ahmed S. Darwish" <darwish.07@gmail.com> wrote:
> 
...
> > 
> > diff --git a/security/smack/smack.h b/security/smack/smack.h
> > index c444f48..2c8bb4c 100644
> > --- a/security/smack/smack.h
> > +++ b/security/smack/smack.h
> > @@ -57,6 +57,15 @@ struct inode_smack {
> >  	char		*smk_inode;	/* label of the fso */
> >  	struct mutex	smk_lock;	/* initialization lock */
> >  	int		smk_flags;	/* smack inode flags */
> > +	int		secid;		/* security identifier */
> 
> No.
> 
> Secid's are horrid things and every effort should be made to
> expunge them from the known universe. Under no circumstances
> should thier use be expanded. The only reason Smack has them
> at all is because certain interfaces that in my mind should
> have known better use them. If you must deal with secids,
> and for this round of audit I think that's a given, use
> smack_to_secid(sp->smk_inode) where you need to. If there's a
> real performance issue apply intelligence to smack_to_secid
> instead of storing the secid. There ought to be a way to
> use container_of to do smack_to_secid, but I had trouble with
> that and moved along without figuring out what I had done
> wrong.
> 

mm .. I should have remembered the un-official Smack motto:
"Everything is a label, and whenever possible, this label is allocated
 once through system lifetime"

About performance, yes there'll be issues searching labels espicially
in audit_rule_match() which got called at the end of every system call.
I'll try it using container_of (it should work at the end).

...
>
> > @@ -1696,9 +1738,9 @@ static int smack_msg_queue_alloc_security(struct
> > msg_queue *msq)
> >   */
> >  static void smack_msg_queue_free_security(struct msg_queue *msq)
> >  {
> > -	struct kern_ipc_perm *kisp = &msq->q_perm;
> > +	struct kern_ipc_perm *ipcp = &msq->q_perm;
> >  
> > -	kisp->security = NULL;
> > +	kfree(ipcp->security);
> >  }
> 
> Don't you just hate repetative reviewers?
>

Probably hating secids with passion :) ?

Admittedly, after some thinking I felt now that they don't fit with
the Smack model very well.

...
> > +
> > +/**
> > + * smack_audit_rule_match - Audit given secid identified object ?
> > + * @secid: Security id to test
> > + * @field: Message flags given from user-space
> > + * @op: Required operation (only equality is allowed)
> > + * @vrule: Smack audit rule that will be checked against the secid object
> > + * @actx: audit context associated with the check (used for Audit logging)
> > + *
> > + * This is the core Audit hook. It's used to identify objects like 
> > + * syscalls and inodes requested from user-space to be audited from 
> > + * remaining kernel objects.
> > + */
> > +static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
> > +				  struct audit_context *actx)
> > +{
> > +	struct smack_known *smk_rule = vrule;
> 
>         char *smack;
> 

More of "everything is a label".

> > +
> > +	if (!smk_rule) {
> > +		audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR,
> > +			  "Smack: missing rule\n");
> > +		return -ENOENT;
> > +	}
> > +
> > +	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
> > +		return 0;
> > +
> 
>         smack = smack_from_secid(secid);
> 
> > +	if (op == AUDIT_EQUAL)
> > +		return (smk_rule->smk_secid == secid);
> > +	if (op == AUDIT_NOT_EQUAL)
> > +		return (smk_rule->smk_secid != secid);
> 
>  	if (op == AUDIT_EQUAL)
> 		return (smk_rule->smk_smack == smack);
> 	if (op == AUDIT_NOT_EQUAL)
> 		return (smk_rule->smk_smack == smack);
> 

You've meant using the short-circuit:
	 smk_rule->smk_smack == smack || strnmp(smack, ..., ..)
Right ?

...
> > +
> > +/**
> > + * smack_audit_rule_free - free internal audit rule representation
> > + * @vrule: rule to be freed.
> > + *
> > + * No memory was allocated in audit_rule_init.
> > + */
> > +static void smack_audit_rule_free(void *vrule)
> > +{
> > +	/* No-op */
> > +}

This little no-op was the only thing that was agreed upon ;)

...
> 
> Casey Schaufler
> casey@schaufler-ca.com

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [RFC][PATCH -v2] Smack: Integrate with Audit
  @ 2008-03-12  2:44 75%       ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-03-12  2:44 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Andrew Morton, James Morris, Paul Moore, LKML, LSM-ML, Audit-ML

Hi!,

Setup the new Audit hooks for Smack. The AUDIT_SUBJ_USER and 
AUDIT_OBJ_USER SELinux flags are recycled to avoid `auditd' 
userspace modifications. Smack only needs auditing on 
a subject/object bases, so those flags were enough.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 smack_lsm.c |  153 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 153 insertions(+)

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index afa7967..d471839 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -26,6 +26,7 @@
 #include <linux/pipe_fs_i.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
+#include <linux/audit.h>
 
 #include "smack.h"
 
@@ -759,6 +760,17 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
 	return -EINVAL;
 }
 
+/**
+ * smack_inode_getsecid - Extract inode's security id
+ * @inode: inode to extract the info from
+ * @secid: where result will be saved
+ */
+static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	struct inode_smack *isp = inode->i_security;
+	*secid = smack_to_secid(isp->smk_inode);
+}
+
 /*
  * File Hooks
  */
@@ -1814,6 +1826,17 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
 	return smk_curacc(isp, may);
 }
 
+/**
+ * smack_ipc_getsecid - Extract ipc object security id
+ * @ipp: the object permissions
+ * @secid: where result will be saved
+ */
+static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
+{
+	char *smack = ipp->security;
+	*secid = smack_to_secid(smack);
+}
+
 /* module stacking operations */
 
 /**
@@ -2391,6 +2414,124 @@ static int smack_key_permission(key_ref_t key_ref,
 #endif /* CONFIG_KEYS */
 
 /*
+ * Smack Audit hooks
+ *
+ * Audit requires a unique representation of each Smack specific
+ * rule. This unique representation is used to distinguish the
+ * object to be audited from remaining kernel objects and also
+ * works as a glue between the audit hooks.
+ *
+ * Since repository entries are added but never deleted, we'll use
+ * the smack_known label address related to the given audit rule as
+ * the needed unique representation. This also better fits the smack
+ * model where nearly everything is a label.
+ */
+#ifdef CONFIG_AUDIT
+
+/**
+ * smack_audit_rule_init - Initialize a smack audit rule
+ * @field: audit rule fields given from user-space (audit.h)
+ * @op: required testing operator (=, !=, >, <, ...)
+ * @rulestr: smack label to be audited
+ * @vrule: pointer to save our own audit rule representation
+ *
+ * Prepare to audit cases where (@field @op @rulestr) is true.
+ * The label to be audited is created if necessay.
+ */
+static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+{
+	char **rule = (char **)vrule;
+	*rule = NULL;
+
+	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+		return -EINVAL;
+
+	if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+		return -EINVAL;
+
+	*rule = smk_import(rulestr, 0);
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_known - Distinguish Smack audit rules
+ * @krule: rule of interest, in Audit kernel representation format
+ *
+ * This is used to filter Smack rules from remaining Audit ones.
+ * If it's proved that this rule belongs to us, the
+ * audit_rule_match hook will be called to do the final judgement.
+ */
+static int smack_audit_rule_known(struct audit_krule *krule)
+{
+	struct audit_field *f;
+	int i;
+
+	for (i = 0; i < krule->field_count; i++) {
+		f = &krule->fields[i];
+
+		if (f->type == AUDIT_SUBJ_USER || f->type == AUDIT_OBJ_USER)
+			return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_match - Audit given object ?
+ * @secid: security id for identifying the object to test
+ * @field: audit rule flags given from user-space
+ * @op: required testing operator
+ * @vrule: smack internal rule presentation
+ * @actx: audit context associated with the check
+ *
+ * The core Audit hook. It's used to take the decision of
+ * whether to audit or not to audit a given object.
+ */
+static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
+				  struct audit_context *actx)
+{
+	char *smack;
+	char *rule = vrule;
+
+	if (!rule) {
+		audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR,
+			  "Smack: missing rule\n");
+		return -ENOENT;
+	}
+
+	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+		return 0;
+
+	smack = smack_from_secid(secid);
+
+	/*
+	 * No need to do string comparisons since we're sure
+	 * that if a match occurs, both pointers will point
+	 * to the same smack_konwn label.
+	 */
+	if (op == AUDIT_EQUAL)
+		return (rule == smack);
+	if (op == AUDIT_NOT_EQUAL)
+		return (rule != smack);
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_free - free smack rule representation
+ * @vrule: rule to be freed.
+ *
+ * No memory was allocated.
+ */
+static void smack_audit_rule_free(void *vrule)
+{
+	/* No-op */
+}
+
+#endif /* CONFIG_AUDIT */
+
+/*
  * smack_secid_to_secctx - return the smack label for a secid
  * @secid: incoming integer
  * @secdata: destination
@@ -2476,6 +2617,7 @@ struct security_operations smack_ops = {
 	.inode_getsecurity = 		smack_inode_getsecurity,
 	.inode_setsecurity = 		smack_inode_setsecurity,
 	.inode_listsecurity = 		smack_inode_listsecurity,
+	.inode_getsecid =		smack_inode_getsecid,
 
 	.file_permission = 		smack_file_permission,
 	.file_alloc_security = 		smack_file_alloc_security,
@@ -2506,6 +2648,7 @@ struct security_operations smack_ops = {
 	.task_to_inode = 		smack_task_to_inode,
 
 	.ipc_permission = 		smack_ipc_permission,
+	.ipc_getsecid =			smack_ipc_getsecid,
 
 	.msg_msg_alloc_security = 	smack_msg_msg_alloc_security,
 	.msg_msg_free_security = 	smack_msg_msg_free_security,
@@ -2550,12 +2693,22 @@ struct security_operations smack_ops = {
 	.sk_free_security = 		smack_sk_free_security,
 	.sock_graft = 			smack_sock_graft,
 	.inet_conn_request = 		smack_inet_conn_request,
+
  /* key management security hooks */
 #ifdef CONFIG_KEYS
 	.key_alloc = 			smack_key_alloc,
 	.key_free = 			smack_key_free,
 	.key_permission = 		smack_key_permission,
 #endif /* CONFIG_KEYS */
+
+ /* Audit hooks */
+#ifdef CONFIG_AUDIT
+	.audit_rule_init =		smack_audit_rule_init,
+	.audit_rule_known =		smack_audit_rule_known,
+	.audit_rule_match =		smack_audit_rule_match,
+	.audit_rule_free =		smack_audit_rule_free,
+#endif /* CONFIG_AUDIT */
+
 	.secid_to_secctx = 		smack_secid_to_secctx,
 	.secctx_to_secid = 		smack_secctx_to_secid,
 	.release_secctx = 		smack_release_secctx,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 75%]

* [PATCH -v2b] Smack: Integrate with Audit
  @ 2008-03-12 12:18 75%           ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-12 12:18 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Andrew Morton, James Morris, Paul Moore, LKML, LSM-ML, Audit-ML

Hi!,

[ Minor styling fixes ]

-->

Setup the new Audit hooks for Smack. SELinux Audit rule fields 
are recycled to avoid `auditd' userspace modifications.
Currently only equality testing is supported on labels acting 
as a subject (AUDIT_SUBJ_USER) or as an object (AUDIT_OBJ_USER).

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index afa7967..f999ab5 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -26,6 +26,7 @@
 #include <linux/pipe_fs_i.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
+#include <linux/audit.h>
 
 #include "smack.h"
 
@@ -759,6 +760,18 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
 	return -EINVAL;
 }
 
+/**
+ * smack_inode_getsecid - Extract inode's security id
+ * @inode: inode to extract the info from
+ * @secid: where result will be saved
+ */
+static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	struct inode_smack *isp = inode->i_security;
+
+	*secid = smack_to_secid(isp->smk_inode);
+}
+
 /*
  * File Hooks
  */
@@ -1814,6 +1827,18 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
 	return smk_curacc(isp, may);
 }
 
+/**
+ * smack_ipc_getsecid - Extract smack security id
+ * @ipcp: the object permissions
+ * @secid: where result will be saved
+ */
+static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
+{
+	char *smack = ipp->security;
+
+	*secid = smack_to_secid(smack);
+}
+
 /* module stacking operations */
 
 /**
@@ -2391,6 +2416,124 @@ static int smack_key_permission(key_ref_t key_ref,
 #endif /* CONFIG_KEYS */
 
 /*
+ * Smack Audit hooks
+ *
+ * Audit requires a unique representation of each Smack specific
+ * rule. This unique representation is used to distinguish the
+ * object to be audited from remaining kernel objects and also
+ * works as a glue between the audit hooks.
+ *
+ * Since repository entries are added but never deleted, we'll use
+ * the smack_known label address related to the given audit rule as
+ * the needed unique representation. This also better fits the smack
+ * model where nearly everything is a label.
+ */
+#ifdef CONFIG_AUDIT
+
+/**
+ * smack_audit_rule_init - Initialize a smack audit rule
+ * @field: audit rule fields given from user-space (audit.h)
+ * @op: required testing operator (=, !=, >, <, ...)
+ * @rulestr: smack label to be audited
+ * @vrule: pointer to save our own audit rule representation
+ *
+ * Prepare to audit cases where (@field @op @rulestr) is true.
+ * The label to be audited is created if necessay.
+ */
+static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+{
+	char **rule = (char **)vrule;
+	*rule = NULL;
+
+	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+		return -EINVAL;
+
+	if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+		return -EINVAL;
+
+	*rule = smk_import(rulestr, 0);
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_known - Distinguish Smack audit rules
+ * @krule: rule of interest, in Audit kernel representation format
+ *
+ * This is used to filter Smack rules from remaining Audit ones.
+ * If it's proved that this rule belongs to us, the
+ * audit_rule_match hook will be called to do the final judgement.
+ */
+static int smack_audit_rule_known(struct audit_krule *krule)
+{
+	struct audit_field *f;
+	int i;
+
+	for (i = 0; i < krule->field_count; i++) {
+		f = &krule->fields[i];
+
+		if (f->type == AUDIT_SUBJ_USER || f->type == AUDIT_OBJ_USER)
+			return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_match - Audit given object ?
+ * @secid: security id for identifying the object to test
+ * @field: audit rule flags given from user-space
+ * @op: required testing operator
+ * @vrule: smack internal rule presentation
+ * @actx: audit context associated with the check
+ *
+ * The core Audit hook. It's used to take the decision of
+ * whether to audit or not to audit a given object.
+ */
+static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
+				  struct audit_context *actx)
+{
+	char *smack;
+	char *rule = vrule;
+
+	if (!rule) {
+		audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR,
+			  "Smack: missing rule\n");
+		return -ENOENT;
+	}
+
+	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+		return 0;
+
+	smack = smack_from_secid(secid);
+
+	/*
+	 * No need to do string comparisons. If a match occurs,
+	 * both pointers will point to the same smack_known
+	 * label.
+	 */
+	if (op == AUDIT_EQUAL)
+		return (rule == smack);
+	if (op == AUDIT_NOT_EQUAL)
+		return (rule != smack);
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_free - free smack rule representation
+ * @vrule: rule to be freed.
+ *
+ * No memory was allocated.
+ */
+static void smack_audit_rule_free(void *vrule)
+{
+	/* No-op */
+}
+
+#endif /* CONFIG_AUDIT */
+
+/*
  * smack_secid_to_secctx - return the smack label for a secid
  * @secid: incoming integer
  * @secdata: destination
@@ -2476,6 +2619,7 @@ struct security_operations smack_ops = {
 	.inode_getsecurity = 		smack_inode_getsecurity,
 	.inode_setsecurity = 		smack_inode_setsecurity,
 	.inode_listsecurity = 		smack_inode_listsecurity,
+	.inode_getsecid =		smack_inode_getsecid,
 
 	.file_permission = 		smack_file_permission,
 	.file_alloc_security = 		smack_file_alloc_security,
@@ -2506,6 +2650,7 @@ struct security_operations smack_ops = {
 	.task_to_inode = 		smack_task_to_inode,
 
 	.ipc_permission = 		smack_ipc_permission,
+	.ipc_getsecid =			smack_ipc_getsecid,
 
 	.msg_msg_alloc_security = 	smack_msg_msg_alloc_security,
 	.msg_msg_free_security = 	smack_msg_msg_free_security,
@@ -2550,12 +2695,22 @@ struct security_operations smack_ops = {
 	.sk_free_security = 		smack_sk_free_security,
 	.sock_graft = 			smack_sock_graft,
 	.inet_conn_request = 		smack_inet_conn_request,
+
  /* key management security hooks */
 #ifdef CONFIG_KEYS
 	.key_alloc = 			smack_key_alloc,
 	.key_free = 			smack_key_free,
 	.key_permission = 		smack_key_permission,
 #endif /* CONFIG_KEYS */
+
+ /* Audit hooks */
+#ifdef CONFIG_AUDIT
+	.audit_rule_init =		smack_audit_rule_init,
+	.audit_rule_known =		smack_audit_rule_known,
+	.audit_rule_match =		smack_audit_rule_match,
+	.audit_rule_free =		smack_audit_rule_free,
+#endif /* CONFIG_AUDIT */
+
 	.secid_to_secctx = 		smack_secid_to_secctx,
 	.secctx_to_secid = 		smack_secctx_to_secid,
 	.release_secctx = 		smack_release_secctx,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 75%]

* Re: [RFC][PATCH -v2] Smack: Integrate with Audit
  @ 2008-03-12 16:43 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-12 16:43 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: casey, Andrew Morton, James Morris, Paul Moore, LKML, LSM-ML,
	Audit-ML, Steve Grubb

On Wed, Mar 12, 2008 at 11:48:17AM -0400, Stephen Smalley wrote:
> 
> On Wed, 2008-03-12 at 08:40 -0700, Casey Schaufler wrote:
> > --- Stephen Smalley <sds@tycho.nsa.gov> wrote:
> > 
> > > 
> > > On Wed, 2008-03-12 at 04:44 +0200, Ahmed S. Darwish wrote:
> > > > Hi!,
> > > > 
> > > > Setup the new Audit hooks for Smack. The AUDIT_SUBJ_USER and 
> > > > AUDIT_OBJ_USER SELinux flags are recycled to avoid `auditd' 
> > > > userspace modifications. Smack only needs auditing on 
> > > > a subject/object bases, so those flags were enough.
> > > 
> > > Only question I have is whether audit folks are ok with reuse of the
> > > flags in this manner, and whether the _USER flag is best suited for this
> > > purpose if you are going to reuse an existing flag (since Smack label
> > > seems more like a SELinux type than a SELinux user).
> > 
> > To-mate-o toe-maht-o.
> > 
> > There really doesn't seem to be any real reason to create a new
> > flag just because the granularity is different. The choice between
> > _USER and _TYPE (and _ROLE for that matter) is arbitrary from a
> > functional point of view. I say that since Smack has users, but
> > not types or roles, _USER makes the most sense.
> 
> Perhaps I misunderstand, but Smack labels don't represent users (i.e.
> user identity) in any way, so it seemed like a mismatch to use the _USER
> flag there.  Whereas types in SELinux bear some similarity to Smack
> labels - simple unstructured names whose meaning is only defined by the
> policy rules.
> 

I think Casey meant the common use of Smack where a login program
(openssh, bin/login, ..) sets a label for each user that logs in, thus
letting each label effectively representing a user.

In a sense, smack labels share a bit of _USER and _TYPE.

> Regardless, it seems like the audit maintainers ought to weigh in on the
> matter.
> 

Indeed.

Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [PATCH BUGFIX -rc5] Smack: Do not dereference NULL ipc object
@ 2008-03-14 23:10 95% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-14 23:10 UTC (permalink / raw)
  To: Casey Schaufler, akpm; +Cc: LKML

Hi all,

In the SYSV ipc msgctl(),semctl(),shmctl() family, if the user passed
*_INFO as the desired operation, no specific object is meant to be 
controlled and only system-wide information is returned. This leads
to a NULL IPC object in the LSM hooks if the _INFO flag is given.

Avoid dereferencing this NULL pointer in Smack ipc *ctl() methods.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 smack_lsm.c |    9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 0241fd3..38d7075 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1508,7 +1508,7 @@ static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
  */
 static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
 {
-	char *ssp = smack_of_shm(shp);
+	char *ssp;
 	int may;
 
 	switch (cmd) {
@@ -1532,6 +1532,7 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
 		return -EINVAL;
 	}
 
+	ssp = smack_of_shm(shp);
 	return smk_curacc(ssp, may);
 }
 
@@ -1616,7 +1617,7 @@ static int smack_sem_associate(struct sem_array *sma, int semflg)
  */
 static int smack_sem_semctl(struct sem_array *sma, int cmd)
 {
-	char *ssp = smack_of_sem(sma);
+	char *ssp;
 	int may;
 
 	switch (cmd) {
@@ -1645,6 +1646,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd)
 		return -EINVAL;
 	}
 
+	ssp = smack_of_sem(sma);
 	return smk_curacc(ssp, may);
 }
 
@@ -1730,7 +1732,7 @@ static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
  */
 static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
 {
-	char *msp = smack_of_msq(msq);
+	char *msp;
 	int may;
 
 	switch (cmd) {
@@ -1752,6 +1754,7 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
 		return -EINVAL;
 	}
 
+	msp = smack_of_msq(msq);
 	return smk_curacc(msp, may);
 }
 
Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 95%]

* Re: [PATCH] de-semaphorize smackfs
  @ 2008-03-18 12:01 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-18 12:01 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Jonathan Corbet, linux-kernel, Casey Schaufler

Hi!,

On Tue, Mar 18, 2008 at 9:35 AM, Christoph Hellwig <hch@infradead.org> wrote:
> On Mon, Mar 17, 2008 at 05:14:40PM -0600, Jonathan Corbet wrote:
>  > While looking at the generic semaphore patch, I came to wonder what the
>  > remaining semaphore users in the kernel were actually doing.  After a
>  > quick grep for down_interruptible(), smackfs remained at the bottom of
>  > my screen.  It seems like a straightforward mutex case - low-hanging
>  > fruit.  So here's a conversion patch; compile-tested only, but what
>  > could go wrong?
>

I have a feeling that a very nice LWN article is under the way :).

>
>  The lock is kept while returning to userspace and could potentially
>  be release by another process.  This is not allowed for mutexes.
>

Yes, this was an artifact of an old design where different processes
write _sessions_ were not allowed to interleave, thus locking them in
the very beginning (open).

Since now those sessions can be interleaved safely, I'll modify this
issue today to move the locking to each write() call instead.

Thanks Jonathan/Cristoph

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* [PATCH BUGFIX -rc6] Smackfs: remove redundant lock, fix open(,O_RDWR)
@ 2008-03-21 15:05 92% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-03-21 15:05 UTC (permalink / raw)
  To: Jonathan Corbet, Casey Schaufler, Andrew Morton
  Cc: LKML, Christoph Hellwig, Daniel Walker

Hi all,

Older smackfs was parsing MAC rules by characters, thus a need of
locking write sessions on open() was needed. This lock is no longer
useful now since each rule is handled by a single write() call.

This is also a bugfix since seq_open() was not called if an open()
O_RDWR flag was given, leading to a seq_read() without an initialized
seq_file, thus an Oops.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Reported-by: Jonathan Corbet <corbet@lwn.net>
--

 security/smack/smackfs.c |   35 ++---------------------------------
 1 file changed, 2 insertions(+), 33 deletions(-)

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index afe7c9b..cfae8af 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -74,11 +74,6 @@ struct smk_list_entry *smack_list;
 #define	SEQ_READ_FINISHED	1
 
 /*
- * Disable concurrent writing open() operations
- */
-static struct semaphore smack_write_sem;
-
-/*
  * Values for parsing cipso rules
  * SMK_DIGITLEN: Length of a digit field in a rule.
  * SMK_CIPSOMIN: Minimum possible cipso rule length.
@@ -168,32 +163,7 @@ static struct seq_operations load_seq_ops = {
  */
 static int smk_open_load(struct inode *inode, struct file *file)
 {
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-		return seq_open(file, &load_seq_ops);
-
-	if (down_interruptible(&smack_write_sem))
-		return -ERESTARTSYS;
-
-	return 0;
-}
-
-/**
- * smk_release_load - release() for /smack/load
- * @inode: inode structure representing file
- * @file: "load" file pointer
- *
- * For a reading session, use the seq_file release
- * implementation.
- * Otherwise, we are at the end of a writing session so
- * clean everything up.
- */
-static int smk_release_load(struct inode *inode, struct file *file)
-{
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-		return seq_release(inode, file);
-
-	up(&smack_write_sem);
-	return 0;
+	return seq_open(file, &load_seq_ops);
 }
 
 /**
@@ -341,7 +311,7 @@ static const struct file_operations smk_load_ops = {
 	.read		= seq_read,
 	.llseek         = seq_lseek,
 	.write		= smk_write_load,
-	.release        = smk_release_load,
+	.release        = seq_release,
 };
 
 /**
@@ -1011,7 +981,6 @@ static int __init init_smk_fs(void)
 		}
 	}
 
-	sema_init(&smack_write_sem, 1);
 	smk_cipso_doi();
 	smk_unlbl_ambient(NULL);
 
Regards,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 92%]

* Re: [patch] SLQB v2
  @ 2008-04-15  3:44 92% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-04-15  3:44 UTC (permalink / raw)
  To: Nick Piggin, Christoph Lameter
  Cc: Linux Memory Management List, Linux Kernel Mailing List

Hi!,

On Thu, Apr 10, 2008 at 09:31:38PM +0200, Nick Piggin wrote:
...
> +
> +/*
> + * We use struct slqb_page fields to manage some slob allocation aspects,
> + * however to avoid the horrible mess in include/linux/mm_types.h, we'll
> + * just define our own struct slqb_page type variant here.
> + */
> +struct slqb_page {
> +	union {
> +		struct {
> +			unsigned long flags;	/* mandatory */
> +			atomic_t _count;	/* mandatory */
> +			unsigned int inuse;	/* Nr of objects */
> +		   	struct kmem_cache_list *list; /* Pointer to list */
> +			void **freelist;	/* freelist req. slab lock */
> +			union {
> +				struct list_head lru; /* misc. list */
> +				struct rcu_head rcu_head; /* for rcu freeing */
> +			};
> +		};
> +		struct page page;
> +	};
> +};

A small question for SLUB devs, would you accept a patch that does
a similar thing by creating 'slub_page' instead of stuffing slub 
elements (freelist, inuse, ..) in 'mm_types::struct page' unions ?

Maybe cause I'm new to MM, but I felt I could understand the code 
much more better the SLQB slqb_page way.

...
> +/*
> + * Kmalloc subsystem.
> + */
> +#if defined(ARCH_KMALLOC_MINALIGN) && ARCH_KMALLOC_MINALIGN > 8
> +#define KMALLOC_MIN_SIZE ARCH_KMALLOC_MINALIGN
> +#else
> +#define KMALLOC_MIN_SIZE 8
> +#endif
> +
> +#define KMALLOC_SHIFT_LOW ilog2(KMALLOC_MIN_SIZE)
> +#define KMALLOC_SHIFT_SLQB_HIGH (PAGE_SHIFT + 5)
> +
> +/*
> + * We keep the general caches in an array of slab caches that are used for
> + * 2^x bytes of allocations.
> + */
> +extern struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_SLQB_HIGH + 1];
> +

So AFAIK in an x86 where PAGE_SHIFT = 12, KMALLOC_SHIFT_SLQB_HIGH+1 will
equal= 18.

> +/*
> + * Sorry that the following has to be that ugly but some versions of GCC
> + * have trouble with constant propagation and loops.
> + */
> +static __always_inline int kmalloc_index(size_t size)
> +{
> +	if (!size)
> +		return 0;
> +
> +	if (size <= KMALLOC_MIN_SIZE)
> +		return KMALLOC_SHIFT_LOW;
> +
> +	if (size > 64 && size <= 96)
> +		return 1;
> +	if (size > 128 && size <= 192)
> +		return 2;
> +	if (size <=          8) return 3;
> +	if (size <=         16) return 4;
> +	if (size <=         32) return 5;
> +	if (size <=         64) return 6;
> +	if (size <=        128) return 7;
> +	if (size <=        256) return 8;
> +	if (size <=        512) return 9;
> +	if (size <=       1024) return 10;
> +	if (size <=   2 * 1024) return 11;
> +/*
> + * The following is only needed to support architectures with a larger page
> + * size than 4k.
> + */
> +	if (size <=   4 * 1024) return 12;
> +	if (size <=   8 * 1024) return 13;
> +	if (size <=  16 * 1024) return 14;
> +	if (size <=  32 * 1024) return 15;
> +	if (size <=  64 * 1024) return 16;
> +	if (size <= 128 * 1024) return 17;
> +	if (size <= 256 * 1024) return 18;
> +	if (size <= 512 * 1024) return 19;

I'm sure there's something utterly wrong in my understanding, but how this
is designed to not overflow kmalloc_caches[18] in an x86-32 machine ?

I can not see this possible-only-in-my-mind overflow happens in SLUB as it 
just delegate the work to the page allocator if size > PAGE_SIZE.

> +	if (size <= 1024 * 1024) return 20;
> +	if (size <=  2 * 1024 * 1024) return 21;
> +	return -1;
> +
> +/*
> + * What we really wanted to do and cannot do because of compiler issues is:
> + *	int i;
> + *	for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++)
> + *		if (size <= (1 << i))
> + *			return i;
> + */
> +}
> +
> +/*
> + * Find the slab cache for a given combination of allocation flags and size.
> + *
> + * This ought to end up with a global pointer to the right cache
> + * in kmalloc_caches.
> + */
> +static __always_inline struct kmem_cache *kmalloc_slab(size_t size)
> +{
> +	int index = kmalloc_index(size);
> +
> +	if (index == 0)
> +		return NULL;
> +
> +	return &kmalloc_caches[index];
> +}
> +
> +#ifdef CONFIG_ZONE_DMA
> +#define SLQB_DMA __GFP_DMA
> +#else
> +/* Disable DMA functionality */
> +#define SLQB_DMA (__force gfp_t)0
> +#endif
> +
> +void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
> +void *__kmalloc(size_t size, gfp_t flags);
> +
> +static __always_inline void *kmalloc(size_t size, gfp_t flags)
> +{
> +	if (__builtin_constant_p(size)) {
> +		if (likely(!(flags & SLQB_DMA))) {
> +			struct kmem_cache *s = kmalloc_slab(size);
> +			if (!s)
> +				return ZERO_SIZE_PTR;
> +			return kmem_cache_alloc(s, flags);
> +		}
> +	}
> +	return __kmalloc(size, flags);
> +}
> +
> +#ifdef CONFIG_NUMA
> +void *__kmalloc_node(size_t size, gfp_t flags, int node);
> +void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
> +
> +static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
> +{
> +	if (__builtin_constant_p(size)) {
> +		if (likely(!(flags & SLQB_DMA))) {
> +			struct kmem_cache *s = kmalloc_slab(size);
> +			if (!s)
> +				return ZERO_SIZE_PTR;
> +			return kmem_cache_alloc_node(s, flags, node);
> +		}
> +	}
> +	return __kmalloc_node(size, flags, node);
> +}

Why this compile-time/run-time divide although both kmem_cache_alloc{,_node}
and __kmalloc{,_node} call slab_alloc() at the end ?

> +#endif
> +
> +#endif /* _LINUX_SLQB_DEF_H */
> Index: linux-2.6/init/Kconfig
> ===================================================================
> --- linux-2.6.orig/init/Kconfig
> +++ linux-2.6/init/Kconfig
> @@ -701,6 +701,11 @@ config SLUB_DEBUG
>  	  SLUB sysfs support. /sys/slab will not exist and there will be
>  	  no support for cache validation etc.
>  
> +config SLQB_DEBUG
> +	default y
> +	bool "Enable SLQB debugging support"
> +	depends on SLQB
> +

Maybe if SLQB got merged it can just be easier to have a general SLAB_DEBUG
option that is recognized by the current 4 slab allocators ?

>  choice
>  	prompt "Choose SLAB allocator"
>  	default SLUB
> @@ -724,6 +729,9 @@ config SLUB
>  	   of queues of objects. SLUB can use memory efficiently
>  	   and has enhanced diagnostics.
>  
> +config SLQB
> +	bool "SLQB (Qeued allocator)"
> +
>  config SLOB
>  	depends on EMBEDDED
>  	bool "SLOB (Simple Allocator)"
> @@ -763,7 +771,7 @@ endmenu		# General setup
>  config SLABINFO
>  	bool
>  	depends on PROC_FS
> -	depends on SLAB || SLUB
> +	depends on SLAB || SLUB || SLQB
>  	default y
>  
>  config RT_MUTEXES
> Index: linux-2.6/lib/Kconfig.debug
> ===================================================================
> --- linux-2.6.orig/lib/Kconfig.debug
> +++ linux-2.6/lib/Kconfig.debug
> @@ -221,6 +221,16 @@ config SLUB_STATS
>  	  out which slabs are relevant to a particular load.
>  	  Try running: slabinfo -DA
>  
> +config SLQB_DEBUG_ON
> +	bool "SLQB debugging on by default"
> +	depends on SLQB_DEBUG
> +	default n
> +
> +config SLQB_STATS
> +	default n
> +	bool "Enable SLQB performance statistics"
> +	depends on SLQB
> +
>  config DEBUG_PREEMPT
>  	bool "Debug preemptible kernel"
>  	depends on DEBUG_KERNEL && PREEMPT && (TRACE_IRQFLAGS_SUPPORT || PPC64)
> Index: linux-2.6/mm/slqb.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6/mm/slqb.c
> @@ -0,0 +1,4027 @@
> +/*
> + * SLQB: A slab allocator that focuses on per-CPU scaling, and good performance
> + * with order-0 allocations. Fastpaths emphasis is placed on local allocaiton
> + * and freeing, and remote freeing (freeing on another CPU from that which
> + * allocated).
> + *
> + * Using ideas from mm/slab.c, mm/slob.c, and mm/slub.c,
> + *
> + * And parts of code from mm/slub.c
> + * (C) 2007 SGI, Christoph Lameter <clameter@sgi.com>
> + */
> +
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/bit_spinlock.h>
> +#include <linux/interrupt.h>
> +#include <linux/bitops.h>
> +#include <linux/slab.h>
> +#include <linux/seq_file.h>
> +#include <linux/cpu.h>
> +#include <linux/cpuset.h>
> +#include <linux/mempolicy.h>
> +#include <linux/ctype.h>
> +#include <linux/kallsyms.h>
> +#include <linux/memory.h>
> +
> +/*
> + * Lock order:
> + *   1. kmem_cache_node->list_lock
> + *    2. kmem_cache_remote_free->lock
> + *
> + *   Interrupts are disabled during allocation and deallocation in order to
> + *   make the slab allocator safe to use in the context of an irq. In addition
> + *   interrupts are disabled to ensure that the processor does not change
> + *   while handling per_cpu slabs, due to kernel preemption.
> + *
> + * SLIB assigns one slab for allocation to each processor.
> + * Allocations only occur from these slabs called cpu slabs.
> + *

SLQB is a much more better name than SLIB :).

> + * Slabs with free elements are kept on a partial list and during regular
> + * operations no list for full slabs is used. If an object in a full slab is
> + * freed then the slab will show up again on the partial lists.
> + * We track full slabs for debugging purposes though because otherwise we
> + * cannot scan all objects.
> + *
> + * Slabs are freed when they become empty. Teardown and setup is
> + * minimal so we rely on the page allocators per cpu caches for
> + * fast frees and allocs.
> + */
> +

Ok, I admit I didn't do my homework yet of fully understanding the
diff between SLUB and SLQB except in the kmalloc(> PAGE_SIZE) case.
I hope my understanding will get better soon.

...
> +/*
> + * Slow path. The lockless freelist is empty or we need to perform
> + * debugging duties.
> + *
> + * Interrupts are disabled.
> + *
> + * Processing is still very fast if new objects have been freed to the
> + * regular freelist. In that case we simply take over the regular freelist
> + * as the lockless freelist and zap the regular freelist.
> + *
> + * If that is not working then we fall back to the partial lists. We take the
> + * first element of the freelist as the object to allocate now and move the
> + * rest of the freelist to the lockless freelist.
> + *
> + * And if we were unable to get a new slab from the partial slab lists then
> + * we need to allocate a new slab. This is slowest path since we may sleep.
> + */
> +static __always_inline void *__slab_alloc(struct kmem_cache *s,
> +		gfp_t gfpflags, int node, void *addr)
> +{

__slab_alloc istelf is not the slow-path, but the slow path begins 
from the alloc_new: label, right ? 

If so, then IMHO the comment is a bit misleading since it gives 
the impression that the whole __slab_alloc() is the slow path.

> +	void *object;
> +	struct slqb_page *page;
> +	struct kmem_cache_cpu *c;
> +	struct kmem_cache_list *l;
> +#ifdef CONFIG_NUMA
> +	struct kmem_cache_node *n;
> +
> +	if (unlikely(node != -1) && unlikely(node != numa_node_id())) {
> +		n = s->node[node];
> +		VM_BUG_ON(!n);
> +		l = &n->list;
> +
> +		if (unlikely(!l->nr_partial && !l->nr_free && !l->remote_free_check))
> +			goto alloc_new;
> +
> +		spin_lock(&n->list_lock);
> +remote_list_have_object:
> +		page = __cache_list_get_page(s, l);
> +		if (unlikely(!page)) {
> +			spin_unlock(&n->list_lock);
> +			goto alloc_new;
> +		}
> +		VM_BUG_ON(node != -1 && node != slqb_page_to_nid(page));
> +
> +remote_found:
> +		object = page->freelist;
> +		page->freelist = get_freepointer(s, object);
> +		//prefetch(((void *)page->freelist) + s->offset);
> +		page->inuse++;
> +		VM_BUG_ON((page->inuse == s->objects) != (page->freelist == NULL));
> +		spin_unlock(&n->list_lock);
> +
> +		return object;
> +	}
> +#endif
> +
> +	c = get_cpu_slab(s, smp_processor_id());
> +	VM_BUG_ON(!c);
> +	l = &c->list;
> +	page = __cache_list_get_page(s, l);
> +	if (unlikely(!page))
> +		goto alloc_new;
> +	VM_BUG_ON(node != -1 && node != slqb_page_to_nid(page));
> +
> +local_found:
> +	object = page->freelist;
> +	page->freelist = get_freepointer(s, object);
> +	//prefetch(((void *)page->freelist) + s->offset);
> +	page->inuse++;
> +	VM_BUG_ON((page->inuse == s->objects) != (page->freelist == NULL));
> +
> +	return object;
> +
> +alloc_new:
> +#if 0
> +	/* XXX: load any partial? */
> +#endif
> +
> +	/* Caller handles __GFP_ZERO */
> +	gfpflags &= ~__GFP_ZERO;
> +
> +	if (gfpflags & __GFP_WAIT)
> +		local_irq_enable();
> +	page = new_slab_page(s, gfpflags, node);
> +	if (gfpflags & __GFP_WAIT)
> +		local_irq_disable();
> +	if (unlikely(!page))
> +		return NULL;
> +
> +	if (!NUMA_BUILD || likely(slqb_page_to_nid(page) == numa_node_id())) {
> +		c = get_cpu_slab(s, smp_processor_id());
> +		l = &c->list;
> +		page->list = l;
> +		l->nr_slabs++;
> +		if (page->inuse + 1 < s->objects) {
> +			list_add(&page->lru, &l->partial);
> +			l->nr_partial++;
> +		} else {
> +/*XXX			list_add(&page->lru, &l->full); */
> +		}
> +		goto local_found;
> +	} else {
> +#ifdef CONFIG_NUMA
> +		n = s->node[slqb_page_to_nid(page)];
> +		spin_lock(&n->list_lock);
> +		l = &n->list;
> +
> +		if (l->nr_free || l->nr_partial || l->remote_free_check) {
> +			__free_slab(s, page);
> +			goto remote_list_have_object;
> +		}
> +
> +		l->nr_slabs++;
> +		page->list = l;
> +		if (page->inuse + 1 < s->objects) {
> +			list_add(&page->lru, &l->partial);
> +			l->nr_partial++;
> +		} else {
> +/*XXX			list_add(&page->lru, &l->full); */
> +		}
> +		goto remote_found;
> +#endif
> +	}
> +
...

Thanks for helping me gaining a better understanding of SLQB!

Warm regards

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 92%]

* [PATCH 2.6.26 #repost] Smack: Integrate with Audit
  @ 2008-04-17 16:10 72% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-04-17 16:10 UTC (permalink / raw)
  To: James Morris, Casey Schaufler
  Cc: Stephen Smalley, Steve Grubb, Al Viro, linux-security-module,
	linux-audit, linux-kernel

Hi James/all,

On Thu, Apr 17, 2008 at 11:05:57AM +0000, James Morris wrote:
> 
> Please review the following security patches for 2.6.26, which have
> been undergoing testing in the "next" tree and affect multiple LSMs.
> 
> 

As a clarification, those new changes was added to the security tree 
to modularly integrate Smack with Audit. The final step is the
reposted below patch which setups the new Audit hooks for Smack.

The main concern against below patch was the reuse of SELinux Audit
fields. For such reuse, Stephen asked for an explicit ACK from the 
Audit devs. I've CCed Steve and Al as a kind request for the ACK.

Patch is re-based and re-tested over James's security/for-linus
branch.

Thanks all.

-->

Setup the new Audit hooks for Smack. SELinux Audit rule fields 
are recycled to avoid `auditd' userspace modifications.
Currently only equality testing is supported on labels acting 
as a subject (AUDIT_SUBJ_USER) or as an object (AUDIT_OBJ_USER).

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 904bdc0..70e4abc 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -26,6 +26,7 @@
 #include <linux/pipe_fs_i.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
+#include <linux/audit.h>
 
 #include "smack.h"
 
@@ -752,6 +753,18 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
 	return -EINVAL;
 }
 
+/**
+ * smack_inode_getsecid - Extract inode's security id
+ * @inode: inode to extract the info from
+ * @secid: where result will be saved
+ */
+static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+	struct inode_smack *isp = inode->i_security;
+
+	*secid = smack_to_secid(isp->smk_inode);
+}
+
 /*
  * File Hooks
  */
@@ -1805,6 +1818,18 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
 	return smk_curacc(isp, may);
 }
 
+/**
+ * smack_ipc_getsecid - Extract smack security id
+ * @ipcp: the object permissions
+ * @secid: where result will be saved
+ */
+static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
+{
+	char *smack = ipp->security;
+
+	*secid = smack_to_secid(smack);
+}
+
 /* module stacking operations */
 
 /**
@@ -2382,6 +2407,124 @@ static int smack_key_permission(key_ref_t key_ref,
 #endif /* CONFIG_KEYS */
 
 /*
+ * Smack Audit hooks
+ *
+ * Audit requires a unique representation of each Smack specific
+ * rule. This unique representation is used to distinguish the
+ * object to be audited from remaining kernel objects and also
+ * works as a glue between the audit hooks.
+ *
+ * Since repository entries are added but never deleted, we'll use
+ * the smack_known label address related to the given audit rule as
+ * the needed unique representation. This also better fits the smack
+ * model where nearly everything is a label.
+ */
+#ifdef CONFIG_AUDIT
+
+/**
+ * smack_audit_rule_init - Initialize a smack audit rule
+ * @field: audit rule fields given from user-space (audit.h)
+ * @op: required testing operator (=, !=, >, <, ...)
+ * @rulestr: smack label to be audited
+ * @vrule: pointer to save our own audit rule representation
+ *
+ * Prepare to audit cases where (@field @op @rulestr) is true.
+ * The label to be audited is created if necessay.
+ */
+static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+{
+	char **rule = (char **)vrule;
+	*rule = NULL;
+
+	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+		return -EINVAL;
+
+	if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+		return -EINVAL;
+
+	*rule = smk_import(rulestr, 0);
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_known - Distinguish Smack audit rules
+ * @krule: rule of interest, in Audit kernel representation format
+ *
+ * This is used to filter Smack rules from remaining Audit ones.
+ * If it's proved that this rule belongs to us, the
+ * audit_rule_match hook will be called to do the final judgement.
+ */
+static int smack_audit_rule_known(struct audit_krule *krule)
+{
+	struct audit_field *f;
+	int i;
+
+	for (i = 0; i < krule->field_count; i++) {
+		f = &krule->fields[i];
+
+		if (f->type == AUDIT_SUBJ_USER || f->type == AUDIT_OBJ_USER)
+			return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_match - Audit given object ?
+ * @secid: security id for identifying the object to test
+ * @field: audit rule flags given from user-space
+ * @op: required testing operator
+ * @vrule: smack internal rule presentation
+ * @actx: audit context associated with the check
+ *
+ * The core Audit hook. It's used to take the decision of
+ * whether to audit or not to audit a given object.
+ */
+static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
+				  struct audit_context *actx)
+{
+	char *smack;
+	char *rule = vrule;
+
+	if (!rule) {
+		audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR,
+			  "Smack: missing rule\n");
+		return -ENOENT;
+	}
+
+	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+		return 0;
+
+	smack = smack_from_secid(secid);
+
+	/*
+	 * No need to do string comparisons. If a match occurs,
+	 * both pointers will point to the same smack_known
+	 * label.
+	 */
+	if (op == AUDIT_EQUAL)
+		return (rule == smack);
+	if (op == AUDIT_NOT_EQUAL)
+		return (rule != smack);
+
+	return 0;
+}
+
+/**
+ * smack_audit_rule_free - free smack rule representation
+ * @vrule: rule to be freed.
+ *
+ * No memory was allocated.
+ */
+static void smack_audit_rule_free(void *vrule)
+{
+	/* No-op */
+}
+
+#endif /* CONFIG_AUDIT */
+
+/*
  * smack_secid_to_secctx - return the smack label for a secid
  * @secid: incoming integer
  * @secdata: destination
@@ -2467,6 +2610,7 @@ struct security_operations smack_ops = {
 	.inode_getsecurity = 		smack_inode_getsecurity,
 	.inode_setsecurity = 		smack_inode_setsecurity,
 	.inode_listsecurity = 		smack_inode_listsecurity,
+	.inode_getsecid =		smack_inode_getsecid,
 
 	.file_permission = 		smack_file_permission,
 	.file_alloc_security = 		smack_file_alloc_security,
@@ -2497,6 +2641,7 @@ struct security_operations smack_ops = {
 	.task_to_inode = 		smack_task_to_inode,
 
 	.ipc_permission = 		smack_ipc_permission,
+	.ipc_getsecid =			smack_ipc_getsecid,
 
 	.msg_msg_alloc_security = 	smack_msg_msg_alloc_security,
 	.msg_msg_free_security = 	smack_msg_msg_free_security,
@@ -2541,12 +2686,22 @@ struct security_operations smack_ops = {
 	.sk_free_security = 		smack_sk_free_security,
 	.sock_graft = 			smack_sock_graft,
 	.inet_conn_request = 		smack_inet_conn_request,
+
  /* key management security hooks */
 #ifdef CONFIG_KEYS
 	.key_alloc = 			smack_key_alloc,
 	.key_free = 			smack_key_free,
 	.key_permission = 		smack_key_permission,
 #endif /* CONFIG_KEYS */
+
+ /* Audit hooks */
+#ifdef CONFIG_AUDIT
+	.audit_rule_init =		smack_audit_rule_init,
+	.audit_rule_known =		smack_audit_rule_known,
+	.audit_rule_match =		smack_audit_rule_match,
+	.audit_rule_free =		smack_audit_rule_free,
+#endif /* CONFIG_AUDIT */
+
 	.secid_to_secctx = 		smack_secid_to_secctx,
 	.secctx_to_secid = 		smack_secctx_to_secid,
 	.release_secctx = 		smack_release_secctx,

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 72%]

* [PATCH BUGFIX -rc4] Smack: Respect 'unlabeled' netlabel mode
@ 2008-05-30 23:36 99% Ahmed S. Darwish
    2008-05-30 23:57 94% ` [PATCH BUGFIX -v2 " Ahmed S. Darwish
  0 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2008-05-30 23:36 UTC (permalink / raw)
  To: Casey Schaufler, Paul Moore
  Cc: linux-security-module, LKML, netdev, Andrew Morton

Hi all,

In case of Smack 'unlabeled' netlabel option, Smack passes a _zero_
initialized 'secattr' to label a packet/sock. This causes an 
[unfound domain label error]/-ENOENT by netlbl_sock_setattr().
Above Netlabel failure leads to Smack socket hooks failure causing 
an always-on socket() -EPERM error.

Such packets should have a netlabel domain agreed with netlabel to 
represent unlabeled packets. Fortunately Smack net ambient label 
packets are agreed with netlabel to be treated as unlabeled packets. 

Treat all packets coming out from a 'unlabeled' Smack system as
coming from the smack net ambient label.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b5c8f92..03735f4 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1292,6 +1292,8 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
 		}
 		break;
 	default:
+		nlsp->domain = kstrdup(smack_net_ambient, GFP_ATOMIC);
+		nlsp->flags = NETLBL_SECATTR_DOMAIN;
 		break;
 	}
 }

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* [PATCH BUGFIX -v2 -rc4] Smack: Respect 'unlabeled' netlabel mode
  2008-05-30 23:36 99% [PATCH BUGFIX -rc4] Smack: Respect 'unlabeled' netlabel mode Ahmed S. Darwish
  @ 2008-05-30 23:57 94% ` Ahmed S. Darwish
    1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2008-05-30 23:57 UTC (permalink / raw)
  To: Casey Schaufler, Paul Moore
  Cc: linux-security-module, LKML, netdev, Andrew Morton

Hi!,

[ Sorry, Fix: Acquire smack_ambient_lock before reading smack_net_ambient ]

-->

In case of Smack 'unlabeled' netlabel option, Smack passes a _zero_
initialized 'secattr' to label a packet/sock. This causes an 
[unfound domain label error]/-ENOENT by netlbl_sock_setattr().
Above Netlabel failure leads to Smack socket hooks failure causing 
an always-on socket() -EPERM error.

Such packets should have a netlabel domain agreed with netlabel to 
represent unlabeled packets. Fortunately Smack net ambient label 
packets are agreed with netlabel to be treated as unlabeled packets. 

Treat all packets coming out from a 'unlabeled' Smack system as
coming from the smack net ambient label.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/security/smack/smack.h b/security/smack/smack.h
index 4a4477f..81b94ba 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -16,6 +16,7 @@
 #include <linux/capability.h>
 #include <linux/spinlock.h>
 #include <linux/security.h>
+#include <linux/mutex.h>
 #include <net/netlabel.h>
 
 /*
@@ -178,6 +179,7 @@ u32 smack_to_secid(const char *);
 extern int smack_cipso_direct;
 extern int smack_net_nltype;
 extern char *smack_net_ambient;
+extern struct mutex smack_ambient_lock;
 
 extern struct smack_known *smack_known;
 extern struct smack_known smack_known_floor;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b5c8f92..0d9c7dc 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1292,6 +1292,11 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
 		}
 		break;
 	default:
+		mutex_lock(&smack_ambient_lock);
+		nlsp->domain = kstrdup(smack_net_ambient, GFP_ATOMIC);
+		mutex_unlock(&smack_ambient_lock);
+
+		nlsp->flags = NETLBL_SECATTR_DOMAIN;
 		break;
 	}
 }
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 271a835..cc357dc 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -46,7 +46,7 @@ enum smk_inos {
  */
 static DEFINE_MUTEX(smack_list_lock);
 static DEFINE_MUTEX(smack_cipso_lock);
-static DEFINE_MUTEX(smack_ambient_lock);
+DEFINE_MUTEX(smack_ambient_lock);
 
 /*
  * This is the "ambient" label for network traffic.

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 94%]

* Re: [PATCH BUGFIX -rc4] Smack: Respect 'unlabeled' netlabel mode
  @ 2008-05-31  0:58 93%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-05-31  0:58 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Paul Moore, linux-security-module, LKML, netdev, Andrew Morton

Hi Casey,

On Fri, May 30, 2008 at 04:10:37PM -0700, Casey Schaufler wrote:
> 
> 
> To date the behavior of a Smack system running with nltype
> unlabeled has been carefully undefined. 
>

In the early days (before the 'Smack: unlabeled outgoing ambient packets'
patch - 4bc87e62), I used '$ echo unlabeled > /smack/nltype' in my startup 
scripts to avoid sending cipso-affected packets. When I upgraded this 
machine's kernel, I faced the -EPERM problem mentiond above. 

> The way you're defining
> it will result in a system in which only processes running with
> the ambient label will be able to use sockets, unless I'm reading
> the code incorrectly. 

I've tried to see the relation but failed, any help?

I'm noticing the opposite though, without defining nltype=unlabeled, 
we're forcing every smack-labeled process to send cipso-affected 
packets (and usually no machine around understands cipso).

_Assuming_ the concept is accepted, depending on the ambient label
may actually lead to a race condition though:

- A packet is set with the ambient label domain
- Ambient label changes
  - old ambient-label netlabel domain is deleted
  - new ambient-label is set
  - new ambient-label netlabel domain is created
- call netlabel_sock_setattr(), uses the old ambient label, leads
  to the -EPERM problem.
  -- Rare, but can happen

There are two possible solutions in my mind:

- Using a predefined netlabel domain to denote to unlabeled packets.
  Defect: May collide with a user chosen label and used to break security.
  Solution: Use a domain name that can't become a label (Hackery ?)

- I've tried first to use what was done before the 'Smack: unlabeled outgoing 
  ambient packets' patch, which honored nltype=unlabeled, but ignored netlabel
  completely:
  i.e.

  int rc = 0;
  if (secattr.flags != NETLBL_SECATTR_NONE)
       rc = netlbl_sock_setattr(sk, &secattr);
  return rc

  Paul, would this be right from a netlabel perspective ?

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 93%]

* Re: [PATCH BUGFIX -v2 -rc4] Smack: Respect 'unlabeled' netlabel mode
  @ 2008-05-31  1:12 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-05-31  1:12 UTC (permalink / raw)
  To: Andrew Morton
  Cc: casey, paul.moore, linux-security-module, linux-kernel, netdev,
	Tetsuo Handa

On Fri, May 30, 2008 at 04:25:00PM -0700, Andrew Morton wrote:
> On Sat, 31 May 2008 02:57:51 +0300
> "Ahmed S. Darwish" <darwish.07@gmail.com> wrote:
> 
> > +		mutex_lock(&smack_ambient_lock);
> > +		nlsp->domain = kstrdup(smack_net_ambient, GFP_ATOMIC);
> > +		mutex_unlock(&smack_ambient_lock);
> 
> no no no no no.  And no.
> 
> GFP_ATOMIC is *unreliable*.  Using it in a "security" feature is a bug
> - if it fails, the feature isn't secure any more.
> 
> Failing to check the kmalloc() return value might be a bug.
> 
> If we _need_ GFP_ATOMIC here then taking a mutex in a cannot-sleep
> context is a bug.
> 
> The patch adds a kmalloc but doesn't add a kfree.  Is it leaky?
> 
> Finally, why is there a need to take a lock around a single store
> instruction?

Possibly the worst three lines written ever. GFP_ATOMIC line
was cut-and-paste forgetting to change it to GFP_KERNEL and the lock
is already useless. 

-- 

"Better to light a candle, than curse the darkness"

Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com


^ permalink raw reply	[relevance 99%]

* Re: SMACK netfilter smacklabel socket match
  @ 2008-10-06 23:05 99%                   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2008-10-06 23:05 UTC (permalink / raw)
  To: Tilman Baumann; +Cc: Casey Schaufler, Linux-Kernel, linux-security-module

Hi Tilman,

On Mon, Oct 6, 2008 at 2:57 PM, Tilman Baumann
<tilman.baumann@collax.com> wrote:
> If I set /smack/nltype to 'unlabeled' I have effectively shut off the
>  network.
...
> This might work well in trusted networks.
> But Internet is untrusted and needs to work too. At least in the most real
> world scenarios. :)
>
> If i set /smack/nltype to 'unlabled' i don't even get SYN packets out.
> (operation not permitted)
>
> That's probably a bug, but I think the "fix" is to disable the ability to
> set the nltype to anything other than CIPSO at least for the time being.

Check this patch:
http://article.gmane.org/gmane.linux.network/95294/match=

As far as I can remember, it does exactly what you're asking for.
There have been some arguments against it, but at least you can get
the idea and _try_ to discuss/enhance it further.

Regards

-- 
Ahmed S. Darwish
Homepage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com

^ permalink raw reply	[relevance 99%]

* x86: Is 'volatile' necessary for readb/writeb and friends?
@ 2009-12-04  9:21 97% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2009-12-04  9:21 UTC (permalink / raw)
  To: x86; +Cc: Rusty Russell, Ingo Molnar, H. Peter Anvin, linux-kernel

Hi all,

x86 memory-mapped IO register accessors cast the memory mapped address
parameter to a one with the 'volatile' type qualifier. For example, here
is readb() after cpp processing

--> arch/x86/include/asm/io.h:

static inline unsigned char readb(const volatile void __iomem *addr) {
	unsigned char ret;
	asm volatile("movb %1, %0"
		     :"=q" (ret)
		     :"m" (*(volatile unsigned char __force *)addr)
		     :"memory");
        return ret;
}

I wonder if the volatile qualifiers in the parameter above and at the asm
statement operand were strictly necessary, or just added for extra safety.

AFAIK, the asm statement already functions as a compiler barrier, and the
compiler won't 'optimize' the statement away due to the 'asm volatile' part,
so shouldn't things be safe without those volatile qualifiers?

The only red-herring I found in the gcc manual was the fact that the
"volatile asm instruction can be moved relative to other code, including
across jump instructions."

I wonder if this was the reason a volatile-type data dependency was added
to the mov{b,w,l,q} asm statements; not to reorder the asm instruction
around non-memory-accessing instructions (we already have a barrier).

Thank you!

-- 
Darwish

^ permalink raw reply	[relevance 97%]

* Re: Linux 2.6.37-rc7
  @ 2010-12-22 18:18 99% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2010-12-22 18:18 UTC (permalink / raw)
  To: Jochen Voss; +Cc: Linus Torvalds, Dave Airlie, Chris Wilson, Jesse Barnes, LKML

Hi,

On Tue, 21 Dec 2010 23:30:30 +0000, Jochen Voss wrote:
> On Tue, Dec 21, 2010 at 11:52:17AM -0800, Linus Torvalds wrote:
> > I'm still nervous about some of the regression reports for intel
> > graphics, so please keep testing and reporting. This is the last -rc
> > before xmas (or whatever your holiday may be), so now you all have a
> > few free days when you have nothing better to do than test out an -rc
> > release, right?
>
> For reference, the regression I reported yesterday
> (message id "20101220140615.GA3035@automatix",
> http://www.spinics.net/lists/kernel/msg1126718.html
> on the web) is still present: -rc7 only shows a blank
> screen on my system, -rc7 with 541cc966 reverted works
> without problems.
>

I can confirm the regression: a completely-blank screen right after the
grub prompt.

Printing kernel output using early_printk() all along ('earlyprintk=
serial,keep') shows that the rest of the kernel internally goes on with
its booting process as usual.

Reverting the mentioned 541cc966 commit solves the problem; the bug is
reproducible in both qemu and real hardware.

regards,

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 99%]

* [PATCH, Bugfix] RAMOOPS: Don't overflow over non-allocated regions
@ 2010-12-25  9:57 96% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2010-12-25  9:57 UTC (permalink / raw)
  To: Marco Stornelli, LKML
  Cc: Kyungmin Park, David Woodhouse, Greg KH, Andrew Morton

Hi,

Current code mis-calculates the ramoops header size, leading to an
overflow over the next record at best, or over a non-allocated region
at worst. Fix that calculation.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
--

Shouldn't this be added to -stable too?

Happy New Year!

 drivers/char/ramoops.c |   12 +++++++-----
 1 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
index 73dcb0e..d3d63be 100644
--- a/drivers/char/ramoops.c
+++ b/drivers/char/ramoops.c
@@ -29,7 +29,6 @@
 #include <linux/ramoops.h>
 
 #define RAMOOPS_KERNMSG_HDR "===="
-#define RAMOOPS_HEADER_SIZE   (5 + sizeof(struct timeval))
 
 #define RECORD_SIZE 4096
 
@@ -65,8 +64,8 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper,
 			struct ramoops_context, dump);
 	unsigned long s1_start, s2_start;
 	unsigned long l1_cpy, l2_cpy;
-	int res;
-	char *buf;
+	int res, hdr_size;
+	char *buf, *buf_orig;
 	struct timeval timestamp;
 
 	/* Only dump oopses if dump_oops is set */
@@ -74,6 +73,8 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper,
 		return;
 
 	buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE));
+	buf_orig = buf;
+
 	memset(buf, '\0', RECORD_SIZE);
 	res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
 	buf += res;
@@ -81,8 +82,9 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper,
 	res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
 	buf += res;
 
-	l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE));
-	l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy);
+	hdr_size = buf - buf_orig;
+	l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - hdr_size));
+	l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - hdr_size) - l2_cpy);
 
 	s2_start = l2 - l2_cpy;
 	s1_start = l1 - l1_cpy;

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 96%]

* Re: [PATCH, Bugfix] RAMOOPS: Don't overflow over non-allocated regions
  @ 2010-12-27 21:33 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2010-12-27 21:33 UTC (permalink / raw)
  To: Marco Stornelli
  Cc: LKML, Kyungmin Park, David Woodhouse, Greg KH, Andrew Morton,
	Linus Torvalds

On Sat, Dec 25, 2010 at 12:19:35PM +0100, Marco Stornelli wrote:
> Il 25/12/2010 10:57, Ahmed S. Darwish ha scritto:
> > 
> > Current code mis-calculates the ramoops header size, leading to an
> > overflow over the next record at best, or over a non-allocated region
> > at worst. Fix that calculation.
> > 
> > Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
> > --
> 
> Acked-by: Marco Stornelli <marco.stornelli@gmail.com>
>

Someone to push this to Linus before -rc8? Andrew?

--
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 99%]

* Saving early panic() messages, to disk, using the BIOS
@ 2011-01-14 13:39 99% Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2011-01-14 13:39 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin; +Cc: Randy Dunlap, x86, LKML

Hi,

I'm facing some very early panics in latest -rc kernels. Vesafb is not
even working, so only the very bottom of the stack trace is available.

>From an overall-design perspective, would a patch that saves such early
panic messages to the hard-disk using real-mode BIOS calls be acceptable?

That seems to be the only path to _fully_ capture such panic; this is a
regular x86(-64) laptop with no serial ports or floppy disks. I'm in the
lmode->pmode->rmode part now, but I thought it might be wise to quickly
ask about such design mergeability before investing further effort.

(There is an old set of patches in Randy's homepage that does something
similar using floppy disks,[1] so it seems the basic idea is not that
strange. I also do something similar in a hobby kernel of mine.[2])

thanks,

[1] http://www.xenotime.net/linux/kmsgdump/
[1] http://gitorious.org/cute-os/cute/

-- 
Darwish

^ permalink raw reply	[relevance 99%]

* [PATCH 0/2][concept RFC] x86: BIOS-save kernel log to disk upon panic
@ 2011-01-25 13:47 82% Ahmed S. Darwish
  2011-01-25 13:51 52% ` [PATCH -next 1/2][RFC] x86: Saveoops: Switch to real-mode and call BIOS Ahmed S. Darwish
                   ` (3 more replies)
  0 siblings, 4 replies; 200+ results
From: Ahmed S. Darwish @ 2011-01-25 13:47 UTC (permalink / raw)
  To: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, X86-ML
  Cc: Tony Luck, Dave Jones, Andrew Morton, Randy Dunlap,
	Willy Tarreau, Willy Tarreau, Dirk Hohndel, Dirk.Hohndel, IDE-ML,
	LKML

Hi,

I've faced some very early panics in latest kernel. Being a run of the mill
x86 laptop, the machine is void of debugging aids like serial ports or
network boot.

As a possible solution, below patches prototypes the idea of persistently
storing the kernel log ring to a hard disk partition using the enhanced BIOS
0x13 services.

The used BIOS INT 0x13 functions are the same ones originally used by all
contemporary bootloaders to load the Linux kernel. If the kernel code is
already loaded to RAM and being executed, such parts of the BIOS should be
stable enough.

The basic idea is to switch from 64-bit long mode all the way down to 16-bit
real-mode. Once in real-mode, we reset the disk controller and write the log
buffer to disk using a user-supplied absolute disk block address (LBA).

Doing so, we can capture very early panics (along with earlier log messages)
reliably since the writing mechanism has minimal dependency on any Linux code.

Unfortunately, there are problems on some machines.

In my laptop, when calling the BIOS with the "Reset Disk Controllers" command
or even issuing a direct "Extend Write" without a controller reset, the BIOS
hangs for around __5 minutes__. Afterwards, it returns with a 'Timeout' error
code.

The main problem, it seems, is that the BIOS "Reset controller" command is not
enough to restore disk hardware to a state understandable by the BIOS code.

So:

 - Is it possible to re-initialize the disk hardware to its POST state (thus
   make the BIOS services work reliably) while keeping system RAM unmodified?
 - If not, can we do it manually by reprogramming the controllers?

The first patch (#1) implements the longMode -> realMode switch and invokes
the BIOS. The second reserves needed low-memory areas for such code and
registers a panic logger using the kmsg_dump interface.

Both patches are on '-next' and include XXX marks where further help is also
appreciated. Please remember that these patches, while tested, are now for
prototyping the technical feasibility of the idea.

Diffstat:

 arch/x86/kernel/saveoops-rmode.S |  483 ++++++++++++++++++++++++++++++++++++++
 arch/x86/include/asm/saveoops.h  |   15 ++
 arch/x86/kernel/saveoops.c       |  219 +++++++++++++++++
 arch/x86/kernel/setup.c          |    9 +
 arch/x86/kernel/Makefile         |    3 +
 lib/Kconfig.debug                |   15 ++
 6 files changed, 744 insertions(+), 0 deletions(-)

Related work and discussions:

 - Tony Luck, persistent store: http://article.gmane.org/gmane.linux.kernel.cross-arch/8495
 - Dirk Hohndel, hpa, Japan Symposium, 2D barcode: http://video.linux.com/video/1661
 - akpm, Dave Jones, oops pauser: http://article.gmane.org/gmane.linux.kernel/369739
 - Willy Tarreau, Randy Dunlap, kmsgdump: http://www.xenotime.net/linux/kmsgdump/

Thanks,

--
Darwish
http://darwish.07.googlepages.com


^ permalink raw reply	[relevance 82%]

* [PATCH -next 1/2][RFC] x86: Saveoops: Switch to real-mode and call BIOS
  2011-01-25 13:47 82% [PATCH 0/2][concept RFC] x86: BIOS-save kernel log to disk upon panic Ahmed S. Darwish
@ 2011-01-25 13:51 52% ` Ahmed S. Darwish
  2011-01-25 13:53 61% ` [PATCH -next 2/2][RFC] x86: Saveoops: Reserve low memory and register code Ahmed S. Darwish
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2011-01-25 13:51 UTC (permalink / raw)
  To: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, X86-ML
  Cc: Tony Luck, Dave Jones, Andrew Morton, Randy Dunlap,
	Willy Tarreau, Willy Tarreau, Dirk Hohndel, Dirk.Hohndel, IDE-ML,
	LKML


We get called here upon panic()s to save the kernel log buffer.

First, switch from 64-bit long mode to 16-bit real mode. Afterwards, save the
log buffer to disk using extended INT 0x13 BIOS services. The user has given
us an absolute LBA disk address to save the log buffer to.

By x86 design, this code is mandated to run on a single identity-mapped page.

- How to initialize the disk hardware to its POST state (thus making the
  BIOS code work reliably) while keeping system RAM unmodified?

- Is it guaranteed that '0x80' will always be the boot disk drive number?
  If not, we need to be passed the boot drive number from the bootloader.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 arch/x86/kernel/saveoops-rmode.S |  483 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 483 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/saveoops-rmode.S b/arch/x86/kernel/saveoops-rmode.S
new file mode 100644
index 0000000..6e07112
--- /dev/null
+++ b/arch/x86/kernel/saveoops-rmode.S
@@ -0,0 +1,483 @@
+/* PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE */
+
+/*
+ * Saveoops LongMode -> RealMode switch
+ *
+ * Don't come here with any unfinished business at hand, there's no return.
+ * After writing the log buffer to disk, we just halt.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/processor-flags.h>
+#include <asm/msr-index.h>
+#include <asm/pgtable_types.h>
+#include <asm/segment.h>
+#include <asm/saveoops.h>
+
+/*
+ * Notes:
+ * - Avoid using relocatable symbols: we run from a different place than
+ *   where we're originally linked to. Use absolute addresses
+ * - Run this from an identity page since we disable paging
+ * - Dynamic values are used for all x86 table bases to let this code run
+ *   from *any* memory region below 1-Mbyte
+ */
+	.code64
+ENTRY(saveoops_start)
+	/*
+	 * Switch to 32bit-compatibility mode using a L=0 code segment
+	 */
+
+	cli
+
+	/* Permanently store passed parameters */
+	movq	%rdi, %rbp
+	movl	%esi, (ringbuf_addr - saveoops_start)(%ebp)
+	movl	%edx, (rstack_base - saveoops_start)(%ebp)
+	movq	%rcx, (disk_sector - saveoops_start)(%ebp)
+	movl	%r8d, (ringbuf_len - saveoops_start)(%ebp)
+
+	/* Dynamically set the 32bit-compat. GDTR base */
+	leaq	(lmode32_gdt - saveoops_start)(%ebp), %rax
+	movq	%rax, (lmode32_gdt + 2 - saveoops_start)(%ebp)
+
+	/* Dynamically set the 32bit farpointer base */
+	leal	(compat32 - saveoops_start)(%ebp), %eax
+	movl	%eax, (lmode32_farpointer - saveoops_start)(%ebp)
+
+	lgdt	(lmode32_gdt - saveoops_start)(%ebp)
+	ljmpl	*(lmode32_farpointer - saveoops_start)(%ebp)	# addr32
+
+	.code32
+compat32:
+	/*
+	 * 32bit-compatibility Long Mode, using a L=0 %cs
+	 */
+
+	movw	$__KERNEL_DS, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %ss
+
+	/* 'Deactivate' long mode: disable paging */
+	movl	%cr0, %eax
+	andl    $~X86_CR0_PG, %eax
+	movl    %eax, %cr0
+
+	/*
+	 * Prepare identity maps for the first 2Mbytes. PAE is already
+	 * enabled from the original pmode -> lmode transition.
+	 *
+	 * Reuse head.S page tables instead of creating new ones. Such
+	 * early tables are in fact already reused by the newer direct
+	 * mapping tables, but since paging is now disabled (and we're
+	 * not returning back), hopefully nothing will blow up.
+	 */
+
+	/*
+	 * Pick a table for the PAE Page Directory (PD)
+	 */
+
+	.equ	level2_pae_ident_pgt, (level2_ident_pgt - __START_KERNEL_map)
+	.equ	level2_entry_count, 512
+	.equ	level2_entry_len, 8
+
+	xorl	%eax, %eax
+	movl	$level2_pae_ident_pgt, %edi
+	movl    $((level2_entry_count * level2_entry_len) / 4), %ecx
+	rep	stosl
+
+	movl	$(0 + __PAGE_KERNEL_IDENT_LARGE_EXEC), level2_pae_ident_pgt
+
+	/*
+	 * Pick a table for for the PAE Page Directory Pointer (PDP)
+	 */
+
+	.equ	level3_pae_ident_pgt, (level2_spare_pgt - __START_KERNEL_map)
+	.equ	level3_entry_count, 4
+	.equ	level3_entry_len, 8
+
+	xorl	%eax, %eax
+	movl	$level3_pae_ident_pgt, %edi
+	movl    $((level3_entry_count * level3_entry_len) / 4), %ecx
+	rep	stosl
+
+	movl	$(level2_pae_ident_pgt + _PAGE_PRESENT), level3_pae_ident_pgt
+
+	movl	$level3_pae_ident_pgt, %eax
+	movl    %eax, %cr3
+
+	/* 'Disable' long mode: clear the EFER.LME bit */
+	movl	$MSR_EFER, %ecx
+	rdmsr
+	btcl	$_EFER_LME, %eax
+	wrmsr
+
+	/* Finally, move to 32-bit pmode: re-enabling paging */
+	movl	%cr0, %eax
+	orl     $X86_CR0_PG, %eax
+	movl    %eax, %cr0
+	jmp	pmode32			# flush prefetch
+
+pmode32:
+	/*
+	 * 32-bit protected mode, using a 2MB identity page.
+	 */
+
+	/* Paging was only enabled for the lmode->pmode step */
+	movl	%cr0, %eax
+	andl    $~X86_CR0_PG, %eax
+	movl    %eax, %cr0		# paging no more
+
+	xorl	%eax, %eax
+	movl	%eax, %cr3		# flush the TLB
+
+	/* Dynamically set the GDTR base value */
+	leal	(pmode16_gdt - saveoops_start)(%ebp), %eax
+	movl	%eax, (pmode16_gdt + 2 - saveoops_start)(%ebp)	# base[00:32]
+
+	/* Dynamically set %cs and %ds bases */
+	leal	(pmode16 - saveoops_start)(%ebp), %eax
+	movw	%ax, (pmode16_cs + 2 - saveoops_start)(%ebp)	# base[00:15]
+	movw	%ax, (pmode16_ds + 2 - saveoops_start)(%ebp)	# base[00:15]
+	shrl	$16, %eax
+	movb	%al, (pmode16_cs + 4 - saveoops_start)(%ebp)	# base[16:23]
+	movb	%al, (pmode16_ds + 4 - saveoops_start)(%ebp)	# base[16:23]
+
+	/* Load the 16-bit code and data segments */
+	lgdt	(pmode16_gdt - saveoops_start)(%ebp)
+
+	/* Switch to 16-bit pmode: use the setup 16-bit %cs */
+	ljmp	$0x08, $0x0
+
+	/*
+	 * - “Segment base addresses should be 16-byte aligned” --Intel
+	 * - We also use this as the rmode code base; the 16-byte align
+	 *   will make address caclulations much easier.
+	 */
+	.align 16
+	.globl pmode16
+	.code16
+pmode16:
+	/*
+	 * We're now in the 16-bit protected mode. Since PE is still = 1,
+	 * we can change a segment cache by loading a GDT selector value.
+	 */
+
+	movw	$0x10, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	movw	%ax, %ss
+
+	/*
+	 * NOTE! Due to the new %cs and %ds bases, dereference addresses
+	 * using the from ‘label - pmode16’ from now on.
+	 */
+
+	/* Dynamically build an rmode segment and offset */
+	leal	(pmode16 - saveoops_start)(%ebp), %eax		# absolute value
+	shrl	$4, %eax
+	movw	%ax, rmode_farpointer - pmode16 + 2		# 8086 %cs
+	movw	$(rmode - pmode16), rmode_farpointer - pmode16	# offset
+
+	/* Restore real-mode BIOS interrupt entries */
+	lidt   (rmode_idtr - pmode16)
+
+	/* Switch to canonical real-mode: clear PE */
+	movl	%cr0, %eax
+	andl	$~X86_CR0_PE, %eax
+	movl	%eax, %cr0
+
+	/* Flush prefetch; use the 8086 code segment */
+	ljmp	*(rmode_farpointer - pmode16)
+
+#ifdef	SAVEOOPS_DEBUG
+	/*
+	 * Valid for any real-mode context where a stack exists
+	 */
+#define __print(msg)		;\
+	pushfl			;\
+	pushal			;\
+	pushw	$(1f - pmode16) ;\
+	call	print_string	;\
+	.ascii	"Saveoops: "	;\
+	.ascii	msg		;\
+	.asciz	"      \n\r"	;\
+1:	popal			;\
+	popfl
+#else
+#define __print(msg)		;
+#endif
+
+	.align 16
+rmode:
+	/*
+	 * REAL Mode, at last!
+	 *
+	 * For further details on the BIOS interrupts used, check any
+	 * version of the “Enhanced Disk Drive Specification”.
+	 */
+
+	movw	%cs, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+
+	/* Setup passed stack area */
+	movl	(rstack_base - pmode16), %eax
+	shrl	$4, %eax			# 16byte-aligned
+	movw	%ax, %ss
+	movw	$RMODE_STACK_LEN, %sp
+
+	__print	("Entered real mode")
+
+	/*
+	 * XXXX: We always use the boot disk drive number '0x80'. Can
+	 * this map to a wrong device?
+	 *
+	 * NOTE! Do not trust the BIOS: assume it clobbered all the
+	 * registers (relevant and not) while servicing interrupts.
+	 */
+
+	/*
+	 * Check Extensions Present (0x41) - Does the BIOS provide
+	 * EDD int 0x13 extensions?
+	 *
+	 * input  %bx     - 0x55aa
+	 * input  %dl     - drive number
+	 * output success - carry = 0 && bx = 0xaa55 && cx bit0 = 1
+	 * output failure - carry = 1 || any false condition above
+	 */
+	movb	$0x41, %ah
+	movw	$0x55aa, %bx
+	movb	$0x80, %dl
+	xorw	%cx, %cx
+	pushw	%ds
+	int	$0x13
+	popw	%ds
+	__print	("Queried BIOS for EDD services")
+	jc	no_edd1
+	cmpw	$0xaa55, %bx
+	jne	no_edd2
+	shrw	$1, %cx
+	jnc	no_edd3
+
+	/* Store 16byte-aligned ring buffer address in disk packet */
+	movl	(ringbuf_addr - pmode16), %eax
+	shrl	$4, %eax
+	movw	%ax, (buffer_seg - pmode16)
+	xorw	%ax, %ax
+	movw	%ax, (buffer_offset - pmode16)
+
+	/* Store ringbuf number of 512-byte blocks in disk packet */
+	movl	(ringbuf_len - pmode16), %eax
+	movb	%al, (sectors_cnt - pmode16)
+
+	__print	("Prepared the Disk Address Packet")
+
+	/*
+	 * Reset Hard Disks (0x00)
+	 *
+	 * input  %dl	  - drive number
+	 * output success - carry = 0 && %ah (err code) = 0
+	 * output failure - carry = 1 || %ah = error code
+	 *
+	 * The kernel has just paniced and left the disk controller
+	 * in an unknown state. Reset controllers before write.
+	 */
+	xorw	%ax, %ax
+	movb	$0x80, %dl
+	pushw	%ds
+	int	$0x13
+	popw	%ds
+	__print	("Disk controller reset")
+	jc	init_err1
+	cmpb	$0x0, %ah
+	jne	init_err2
+
+	/*
+	 * Extended Write (0x43) - Transfer data from RAM to disk
+	 *
+	 * input  %al     - 0 (write with verify off)
+	 * input  %dl     - drive number
+	 * input  %ds:si  - pointer to the Disk Address Packet
+	 * output success - carry = 0 && %ah (err code) = 0
+	 * output failure - carry = 1 || %ah = error code
+	 */
+	movb	$0x43, %ah
+	xorb	%al, %al
+	movb	$0x80, %dl
+	movw	$(disk_address_packet - pmode16), %si
+	pushw	%ds
+	int	$0x13
+	popw	%ds
+	__print	("Extended write finished")
+	jc	write_err1
+	cmpb	$0x0, %ah
+	jne	write_err2
+	jmp	success
+
+init_err1:
+	__print ("INT 0x13/0x0 init error 1")
+	jmp	print_errcode
+init_err2:
+	__print ("INT 0x13/0x0 init error 2")
+	jmp	print_errcode
+write_err1:
+	__print	("INT 0x13/0x43 write error 1")
+	jmp	print_errcode
+write_err2:
+	__print	("INT 0x13/0x43 write error 2")
+	jmp	print_errcode
+no_edd1:
+	__print	("Bios does not support EDD service (err=1)")
+	jmp	print_errcode
+no_edd2:
+	__print	("Bios does not support EDD service (err=2)")
+	jmp	print_errcode
+no_edd3:
+	__print	("Bios does not support EDD service (err=3)")
+	jmp	print_errcode
+success:
+	__print	("Sucess!!!")
+	jmp	print_errcode
+
+halt:	hlt
+	jmp	halt
+
+#ifdef	SAVEOOPS_DEBUG
+	/*
+	 * Print Null-terminated string pointed by top of the stack
+	 */
+	.type	print_string, @function
+print_string:
+	popw	%si
+1:	xorb	%bh, %bh
+	movb	$0x0e, %ah
+	lodsb
+	cmpb	$0, %al
+	je	2f
+	int	$0x10
+	jmp	1b
+2:	ret
+
+	/*
+	 * print %dx value in hexadecimal ascii
+	 */
+	.type	print_hex, @function
+print_hex:
+	xorb   %bh, %bh
+	movw   $4, %cx			# 2-bytes = 4 hex digits
+print_digit:
+	rolw   $4, %dx			# highest-order 4 bits in front
+	movw   $0x0e0f, %ax		# bios function 0x0e
+	andb   %dl, %al
+	cmpb   $0x0a, %al		# transform to ASCII
+	jl     digit
+	addb   $0x07, %al
+digit:
+	addb   $0x30, %al
+	int    $0x10
+	loop   print_digit
+	ret
+
+	/*
+	 * Print INT13 err code, number of sectors written
+	 */
+print_errcode:
+	movb	%ah, %dl
+	call	print_hex
+	movw	(sectors_cnt - pmode16), %dx
+	call	print_hex
+	jmp	halt
+#else
+print_errcode:
+	jmp	halt
+#endif
+
+
+/*
+ * Virtual data section; ‘(dyn.)’ = A dynamically-set value
+ */
+
+	.align 16
+lmode32_gdt:
+	.word	lmode32_gdt_end - lmode32_gdt - 1
+	.quad	0x0000000000000000	# base (dyn.)
+	.word	0, 0, 0			# padding
+lmode32_cs:
+	.word	0xffff			# limit
+	.word	0x0000			# base
+	.word	0x9a00			# P=1, C=0, type=0xA (r/x)
+	.word   0x00cf			# L=0 (compat.), D=1 (32-bit), G=1
+lmode32_ds:
+	.word	0xffff			# limit
+	.word	0x0000			# base
+	.word	0x9200			# P=1, type=0x2 (r/w)
+	.word	0x00cf			# G=1, D=1 (32-bit)
+lmode32_gdt_end:
+
+lmode32_farpointer:
+	.long	0x00000000		# offset (dyn.)
+	.word	lmode32_cs -lmode32_gdt # %cs selector
+
+	.align 16
+pmode16_gdt:
+	.word	pmode16_gdt_end - pmode16_gdt - 1
+	.long	0x00000000		# base (dyn.)
+	.word	0x0000			# padding
+pmode16_cs:
+	.word	0xffff			# limit
+	.word	0x0000			# base (dyn.)
+	.word	0x9a00			# P=1, DPL=00, type=0xA (execute/read)
+	.word	0x0000			# G=0 (byte), D=0 (16-bit)
+pmode16_ds:
+	.word	0xffff			# limit
+	.word	0x0000			# base (dyn.)
+	.word	0x9200			# P=1, DPL=00, type=0x2 (read/write)
+	.word	0x0000			# G=0 (byte), D=0 (16-bit)
+pmode16_gdt_end:
+
+rmode_farpointer:
+	.word	0x0000			# offset (dyn.)
+	.word	0x0000			# %cs (dyn.)
+
+rmode_idtr:
+	.equ	RIDT_BASE, 0x0		# PC architecture defined
+	.equ	RIDT_ENTRY_SIZE, 0x4	# 8086 defined
+	.equ	RIDT_ENTRIES, 0x100	# 8086, 286, 386+ defined
+	.word	RIDT_ENTRIES * RIDT_ENTRY_SIZE - 1
+	.long	RIDT_BASE
+
+	/* Values passed by long-mode C code */
+ringbuf_addr:
+	.long	0x00000000		# 16-byte aligned, < 1-MB (dyn.)
+ringbuf_len:
+	.long	0x00000000		# 512-byte aligned (dyn.)
+rstack_base:
+	.long	0x00000000		# 16-byte aligned, < 1-MB (dyn.)
+
+	.align 16
+disk_address_packet:			# for extended INT 0x13 services (dyn.)
+packet_size:
+	.byte	0x10			# in bytes
+reserved0:
+	.byte	0x00			# must be zero
+sectors_cnt:
+	.byte	0x00			# number of blocks to transfer [1 - 127]
+reserved1:
+	.byte	0x00			# must be zero
+buffer_offset:
+	.word	0x0000			# read/write buffer offset
+buffer_seg:
+	.word	0x0000			# read/write buffer segment
+disk_sector:
+	.quad	0x0000000000000000	# logical sector number (LBA)
+
+ENTRY(saveoops_end)
+
+/* PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE */

--
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 52%]

* [PATCH -next 2/2][RFC] x86: Saveoops: Reserve low memory and register code
  2011-01-25 13:47 82% [PATCH 0/2][concept RFC] x86: BIOS-save kernel log to disk upon panic Ahmed S. Darwish
  2011-01-25 13:51 52% ` [PATCH -next 1/2][RFC] x86: Saveoops: Switch to real-mode and call BIOS Ahmed S. Darwish
@ 2011-01-25 13:53 61% ` Ahmed S. Darwish
        3 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2011-01-25 13:53 UTC (permalink / raw)
  To: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, X86-ML
  Cc: Tony Luck, Dave Jones, Andrew Morton, Randy Dunlap,
	Willy Tarreau, Willy Tarreau, Dirk Hohndel, Dirk.Hohndel,
	Simon Kagstrom, IDE-ML, LKML


Using the x86 memblock interface, reserve below 1-Mbyte low memory areas
for the Saveoops LongMode -> RealMode switch code, ring buffer, and stack.
All the low memory areas are dynamically allocated and reserved, giving
memblock enough flexibility to choose the best available areas possible.

To trigger Saveoops on panic(), it's registered using the kmsg_dump hooks.
That interface is quite racy for our goals, but it's quickly used now to
prototype the code (check the XXX mark for details.)

Once Saveoops code is triggered, it identity maps the first 2 MBytes (the
switch code disables paging), copy the log buffer to its reserved 8086-
accessible area, and jumps to the switch code (PATCH #1.)

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

 arch/x86/kernel/saveoops.c      |  219 +++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/setup.c         |    9 ++
 arch/x86/include/asm/saveoops.h |   15 +++
 arch/x86/kernel/Makefile        |    3 +
 lib/Kconfig.debug               |   15 +++
 5 files changed, 261 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/saveoops.c b/arch/x86/kernel/saveoops.c
new file mode 100644
index 0000000..f48fc0a
--- /dev/null
+++ b/arch/x86/kernel/saveoops.c
@@ -0,0 +1,219 @@
+/* PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE */
+
+/*
+ * SAVEOOPS -- Save kernel log buffer to disk upon panic()
+ *
+ * To safely access disk in situations like very early boot or where the
+ * disk access code itself is buggy, we use BIOS INT13h extended services.
+ * To access such services, switch to 8086 real-mode first.
+ */
+
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/log2.h>
+#include <linux/time.h>
+#include <linux/kmsg_dump.h>
+#include <linux/memblock.h>
+#include <linux/sched.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/saveoops.h>
+
+/*
+ * We can only access the first MByte in real mode, thus allocate
+ * low-memory areas for the ring buffer, and rmode code and stack.
+ */
+static phys_addr_t ring_buf;
+static phys_addr_t code_buf;
+static phys_addr_t rmode_stack;
+
+/*
+ * Below 1-Mbyte pointer to lmode->rmode switch code.
+ */
+static void (* __noreturn rmode_switch)(phys_addr_t code_buf,
+					phys_addr_t ring_buf,
+					phys_addr_t rmode_stack,
+					uint64_t disk_lba,
+					uint64_t ring_buf_len);
+
+/*
+ * Absolute LBA address where the log will be saved on disk.
+ */
+static uint64_t disk_lba = CONFIG_SAVEOOPS_DISK_LBA;
+
+/*
+ * Extended BIOS services write to disk in units of 512-byte sectors.
+ * Thus, always align the ring buffer size on a 512-byte boundary.
+ */
+#define RMODE_SEGMENT_LIMIT	0x10000UL
+#define RING_SIZE		(60UL * 1024)
+#define SAVEOOPS_HEADER		"*SAVEOOPS-WRITTEN KERNEL LOG*"
+
+/*
+ * Page tables to identity map the first 2 Mbytes.
+ */
+static __aligned(PAGE_SIZE) pud_t ident_level3[PTRS_PER_PUD];
+static __aligned(PAGE_SIZE) pmd_t ident_level2[PTRS_PER_PMD];
+
+/*
+ * The lmode->rmode switching code needs to run from an identity page
+ * since it disables paging.
+ */
+static void build_identity_mappings(void)
+{
+	pgd_t *pgde;
+	pud_t *pude;
+	pmd_t *pmde;
+
+	pmde = ident_level2;
+	set_pmd(pmde, __pmd(0 + __PAGE_KERNEL_IDENT_LARGE_EXEC));
+
+	pude = ident_level3;
+	set_pud(pude, __pud(__pa(ident_level2) + _KERNPG_TABLE));
+
+	pgde = init_level4_pgt;
+	set_pgd(pgde, __pgd(__pa(ident_level3) + _KERNPG_TABLE));
+
+	__flush_tlb_all();
+}
+
+/*
+ * XXX: Our use of kmsg_dump interface is invalid. We completely halt the
+ *	machine when getting called; this means:
+ *	- other registered loggers won't have a chance to read the ring
+ *	- other CPU cores might also be accessing the disk, racing with
+ *	  BIOS code that will do the same.
+ *
+ *	Such interface is now used to get things going. A new interface
+ *	satisfying our special requirements needs to be created. A
+ *	solution is to do an rmode->lmode switch after writing to disk.
+ */
+static void saveoops_do_dump(struct kmsg_dumper *dumper,
+			     enum kmsg_dump_reason reason,
+			     const char *s1, unsigned long l1,
+			     const char *s2, unsigned long l2)
+{
+	unsigned long l1_cpy, l2_cpy, s1_start, s2_start;
+	struct timeval timestamp;
+	char *buf, *buf_orig;
+	int hdr_size;
+
+	if (reason != KMSG_DUMP_PANIC)
+		return;
+
+	do_gettimeofday(&timestamp);
+
+	buf = __va(ring_buf);
+	buf_orig = buf;
+	memset(buf, '\0', RING_SIZE);
+	buf += sprintf(buf, "%s\n", SAVEOOPS_HEADER);
+	buf += sprintf(buf, "%lu.%lu\n", timestamp.tv_sec, timestamp.tv_usec);
+
+	hdr_size = buf - buf_orig;
+	l2_cpy = min(l2, RING_SIZE - hdr_size);
+	l1_cpy = min(l1, RING_SIZE - hdr_size - l2_cpy);
+
+	s2_start = l2 - l2_cpy;
+	s1_start = l1 - l1_cpy;
+	memcpy(buf, s1 + s1_start, l1_cpy);
+	memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy);
+
+	printk(KERN_EMERG "Saveoops: Saving kernel log to boot disk LBA "
+	       "address %llu\n", disk_lba);
+
+	local_irq_disable();
+	build_identity_mappings();
+	rmode_switch(code_buf, ring_buf, rmode_stack, disk_lba, RING_SIZE >> 9);
+}
+
+static struct kmsg_dumper saveoops_dumper = {
+	.dump = saveoops_do_dump,
+};
+
+/*
+ * Real-mode switch code start and end markers.
+ * @pmode16: 16-bit protected mode entry point; 8086-segments base.
+ */
+extern const char saveoops_start[];
+extern const char saveoops_end[];
+extern const char pmode16[];
+
+/*
+ * Simplify real mode segmented-addressing calculations
+ */
+#define RMODE_DATA_ALIGN	16
+
+void __init saveoops_init(void)
+{
+	unsigned int code_size, code_align;
+	int res;
+
+	if (disk_lba == -1) {
+		printk(KERN_INFO "Saveoops: No disk LBA given; will not save "
+		       "kernel log to disk upon panic.\n");
+		return;
+	}
+
+	BUILD_BUG_ON(!IS_ALIGNED(RING_SIZE, 512));
+	BUILD_BUG_ON(RING_SIZE > RMODE_SEGMENT_LIMIT);
+	BUILD_BUG_ON(RMODE_STACK_LEN > RMODE_SEGMENT_LIMIT);
+	BUG_ON((saveoops_end - pmode16) > RMODE_SEGMENT_LIMIT);
+
+	ring_buf = memblock_find_in_range(0, 1<<20, RING_SIZE, RMODE_DATA_ALIGN);
+	if (ring_buf == MEMBLOCK_ERROR) {
+		printk(KERN_ERR "Saveoops: requesting a low-memory region "
+		       "for ring buffer failed\n");
+		return;
+	}
+	memblock_x86_reserve_range(ring_buf, ring_buf + RING_SIZE,
+				   "SAVEOOPS ringbuf");
+	printk(KERN_INFO "Saveoops: Acquired [0x%llx-0x%llx] for the ring "
+	       "buffer\n", ring_buf, ring_buf + RING_SIZE);
+
+	/* The pmode->rmode switch code “MUST” be in a single page */
+	code_size = saveoops_end - saveoops_start;
+	code_align = roundup_pow_of_two(code_size);
+	code_buf = memblock_find_in_range(0, 1<<20, code_size, code_align);
+	if (code_buf == MEMBLOCK_ERROR) {
+		printk(KERN_ERR "Saveoops: requesting a low-memory region "
+		       "for mode-switching code failed\n");
+		goto fail3;
+	}
+	memblock_x86_reserve_range(code_buf, code_buf + code_size,
+				   "SAVEOOPS codebuf");
+	printk(KERN_INFO "Saveoops: Acquired [0x%llx-0x%llx] for rmode-switch "
+	       "code\n", code_buf, code_buf + code_size);
+
+	rmode_stack = memblock_find_in_range(0, 1<<20, RMODE_STACK_LEN,
+					     RMODE_DATA_ALIGN);
+	if (rmode_stack == MEMBLOCK_ERROR) {
+		printk(KERN_ERR "Saveoops: requesting a low-memory region "
+		       "for real-mode stack failed\n");
+		goto fail2;
+	}
+	memblock_x86_reserve_range(rmode_stack, rmode_stack + RMODE_STACK_LEN,
+				   "SAVEOOPS r-stack");
+	printk(KERN_INFO "Saveoops: Acquired [0x%llx-0x%llx] for rmode stack\n",
+	       rmode_stack, rmode_stack + RMODE_STACK_LEN);
+
+	res = kmsg_dump_register(&saveoops_dumper);
+	if (res) {
+		printk(KERN_ERR "Saveoops: registering kmsg dumper failed");
+		goto fail1;
+	}
+
+	memcpy(__va(code_buf), saveoops_start, code_size);
+	rmode_switch = (void *)code_buf;
+	return;
+
+fail1:
+	memblock_x86_free_range(rmode_stack, rmode_stack + RMODE_STACK_LEN);
+fail2:
+	memblock_x86_free_range(code_buf, code_buf + code_size);
+fail3:
+	memblock_x86_free_range(ring_buf, ring_buf + RING_SIZE);
+}
+
+/* PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE - PROTOTYPE */
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index d3cfe26..3686df8 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -50,6 +50,9 @@
 #include <asm/pci-direct.h>
 #include <linux/init_ohci1394_dma.h>
 #include <linux/kvm_para.h>
+#ifdef CONFIG_SAVEOOPS
+#include <asm/saveoops.h>
+#endif
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -925,6 +928,12 @@ void __init setup_arch(char **cmdline_p)
 	memblock.current_limit = get_max_mapped();
 	memblock_x86_fill();
 
+#ifdef CONFIG_SAVEOOPS
+	/* Initialize Saveoops at the earliest point possible: memblock
+	 * find_in_range is used here to reserve low-memory areas */
+	saveoops_init();
+#endif
+
 	/* preallocate 4k for mptable mpc */
 	early_reserve_e820_mpc_new();

diff --git a/arch/x86/include/asm/saveoops.h b/arch/x86/include/asm/saveoops.h
new file mode 100644
index 0000000..d81e840
--- /dev/null
+++ b/arch/x86/include/asm/saveoops.h
@@ -0,0 +1,15 @@
+#ifndef _SAVEOOPS_H
+#define _SAVEOOPS_H
+
+/*
+ * Definitions shared between Saveoops C and assembly code.
+ */
+
+#define RMODE_STACK_LEN		0x1000	/* Arbitrary */
+
+#ifndef __ASSEMBLY__
+
+void __init saveoops_init(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _SAVEOOPS_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 34244b2..9a097f2 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -121,4 +121,7 @@ ifeq ($(CONFIG_X86_64),y)
 
 	obj-$(CONFIG_PCI_MMCONFIG)	+= mmconf-fam10h_64.o
 	obj-y				+= vsmp_64.o
+
+	obj-$(CONFIG_SAVEOOPS)		+= saveoops.o
+	obj-$(CONFIG_SAVEOOPS)		+= saveoops-rmode.o
 endif
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 4a78f8c..b994791 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -231,6 +231,21 @@ config BOOTPARAM_HUNG_TASK_PANIC
 
 	  Say N if unsure.
 
+config SAVEOOPS
+	bool "Save kernel panics to disk using BIOS"
+	depends on X86_64
+	---help---
+	  <TO-BE-ADDED>
+
+config SAVEOOPS_DISK_LBA
+       int "Boot disk LBA offset to save panic to"
+       default -1
+       depends on SAVEOOPS
+       ---help---
+	 Use this boot disk LBA address to save the kernel log.
+	 To find a partition LBA address use: $fdisk -ul
+	 [VERY DANGEROUS] <FURTHER-INFO-TO-BE-ADDED>
+
 config BOOTPARAM_HUNG_TASK_PANIC_VALUE
 	int
 	depends on DETECT_HUNG_TASK

--
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 61%]

* Re: [PATCH 0/2][concept RFC] x86: BIOS-save kernel log to disk upon panic
    @ 2011-01-25 15:36 84%   ` Ahmed S. Darwish
    1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2011-01-25 15:36 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, X86-ML, Tony Luck,
	Dave Jones, Andrew Morton, Randy Dunlap, Willy Tarreau,
	Willy Tarreau, Dirk Hohndel, Dirk.Hohndel, IDE-ML, LKML,
	Linus Torvalds, Peter Zijlstra, Frédéric Weisbecker,
	Borislav Petkov, Arjan van de Ven

On Tue, Jan 25, 2011 at 03:09:48PM +0100, Ingo Molnar wrote:
> 
> * Ahmed S. Darwish <darwish.07@gmail.com> wrote:
> 
> > Hi,
> > 
> > I've faced some very early panics in latest kernel. Being a run of the mill
> > x86 laptop, the machine is void of debugging aids like serial ports or
> > network boot.
> > 
> > As a possible solution, below patches prototypes the idea of persistently
> > storing the kernel log ring to a hard disk partition using the enhanced BIOS
> > 0x13 services.

[...]

> > 
> > Diffstat:
> > 
> >  arch/x86/kernel/saveoops-rmode.S |  483 ++++++++++++++++++++++++++++++++++++++
> >  arch/x86/include/asm/saveoops.h  |   15 ++
> >  arch/x86/kernel/saveoops.c       |  219 +++++++++++++++++
> >  arch/x86/kernel/setup.c          |    9 +
> >  arch/x86/kernel/Makefile         |    3 +
> >  lib/Kconfig.debug                |   15 ++
> >  6 files changed, 744 insertions(+), 0 deletions(-)
> 
> Ok, i have to admit that while i'm a rabid BIOS-hater i find this debug feature very 
> very interesting, for the plain reason that if it's implemented in a robust and 
> clever way then this has a chance to improve debuggability of pretty much any Linux 
> laptop quite enormously!
> 
> While we generally thoroughly hate BIOSes from beginning to end, one thing can be 
> said, a BIOS bootstraps very early during bootup, and it's relatively simple to 
> trigger as well.
> 

Yes, the BIOS subset used is the same one used by SYSLINUX, grub, etc to load
the kernel. If the kernel is on, these functions are hopefully quite stable.

The complete __roadblock__ I'm currently facing though is restoring the disk
controllers to the state originally setup by the BIOS Power-on self-test (POST).
I hope such re-initialization is even technically feasible.

Without such re-initialization, we'll just be risking the BIOS code exploding.
That was the case in the 5-minute hang described in the cover sheet (PATCH #0).

> Also, since latest kernels do not stomp on BIOS data structures anymore (low RAM), 
> there's some good chance it's still functional at the point of crash - be that an 
> early crash or a later crash.
> 

Yes, I've noticed that thankfully the kernel reserves the BIOS EBDA area. I'm
not sure though if it reserves the real-mode vector table area 0x0 -> 0x400?

> I think the biggest areas of practical concern would be:
> 
>  - Can this mechanism ever, under any circumstance corrupt any real data, destroy 
>    the MBR or do other nasties. Can you think of any additional fail-safe measures 
>    where you could _further robustify the BIOS calls_ to make sure it can never go 
>    to the wrong sector(s)? I really do not want to think of trusting a BIOS to 
>    _write to my disk_.
> 

Admittedly, I was quite worried while testing this on disk. As a possible
safety trigger, I'm thinking of coding a small script under "tools/" that will
write a cookie in the desired area. If the real-mode code did not find such
cookie in the expected place, it abandons the write operation.

>  - Is there some hidden disk area somewhere on PCs, or somewhere on a real partition
>    on typical Linux distributions, which we could use without having to reinstall
>    the box? This would increase utility and availability enormously. I'm thinking of 
>    partition _ends_ which sometimes get rounded in an awkward way and which are 
>    potentially skipped by most Linux filesystems. Even a very small, 512 bytes of 
>    area would be extremely useful for debugging weird suspend hangs ...
> 

I did not have to re-partition the box here. A kindof a hacky solution was
disabling the swap partition and using it for storing the log. That would make
the feature available without re-installing the box, at the cost of temporarily
disabling swap.

Another testing method was booting the kernel from a USB stick and writing the
log there. If there are other free places in the boot disk, it can be used. But
I'm afraid it will make saveoops much more dangerous than what it already is
(by virtue of being much closer to file-system structures and such).

>  - Could we automate the recovery of the dump, and just put it into the regular 
>    kernel log on the next (successful) bootup (on a feature-enabled kernel)? That 
>    would make the log of the 'previous crash' very conveniently available in dmesg 
>    and the syslog. Tools like kerneloops could make use of it immediately.
> 

If I can make the code reliably work, it can be very very useful in a huge
number of situations such as these and more. The catch is the "If" part :)

> All in one, a very intriguing idea IMO, and the hardest bits (lowlevel x86 
> transition) is all implemented already.
> 

There is a place under arch/x86 that already does the lmode->rmode transition?

That was (so far) the hardest part; I quite searched the tree but did not find
any, so I rolled my own lmode->rmode switch code in the file "saveoops-rmode.S"

> 
> 	Ingo

Thanks,

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 84%]

* Re: [PATCH 0/2][concept RFC] x86: BIOS-save kernel log to disk upon panic
  @ 2011-01-25 17:05 94%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2011-01-25 17:05 UTC (permalink / raw)
  To: James Bottomley
  Cc: Tejun Heo, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
	Ingo Molnar, X86-ML, Tony Luck, Dave Jones, Andrew Morton,
	Randy Dunlap, Willy Tarreau, Willy Tarreau, Dirk Hohndel,
	Dirk.Hohndel, IDE-ML, LKML, Linus Torvalds, Peter Zijlstra,
	Frédéric Weisbecker, Borislav Petkov, Arjan van de Ven,
	Jeff Garzik

Hi!

On Tue, Jan 25, 2011 at 11:02:35AM -0500, James Bottomley wrote:
> On Tue, 2011-01-25 at 17:36 +0200, Ahmed S. Darwish wrote:
> > The complete __roadblock__ I'm currently facing though is restoring the disk
> > controllers to the state originally setup by the BIOS Power-on self-test (POST).
> > I hope such re-initialization is even technically feasible.
> > 
> > Without such re-initialization, we'll just be risking the BIOS code exploding.
> > That was the case in the 5-minute hang described in the cover sheet (PATCH #0).
> 
> So this is the bit that's not really technically feasible.  BIOS tends
> to run storage devices in a very primitive way (so it takes basic
> settings, for example and sets the device up for one particular channel
> of access).  When preparing the device for an operating system, we have
> to blow away all the bios stuff and put it into a more generally
> performant mode (this isn't just the storage per se, it's also the
> interrupt and routing).  Unfortunately, currently, we don't bother to
> save the settings the BIOS was using, so there's no way to reinitialise
> the device back to bios without an effective reboot.
>

My current x86 laptop includes the very common ATA PIIX controller. If I
dumped the PIC, IOAPIC, and disk controller state in a register file in a
safe area, and re-initialized these before giving control to the BIOS, can
this move the solution space from being not really technically feasible to
"quite possible"?

I have to admit that my knowledge of disk controllers is nil. The final
result though can really be worth the effort (as stated by Ingo's mail),
so I'm _willing_ to explore and prototype different paths.

>
> Most BIOS doesn't seem to contain storage re-POST code that's usable
> (it's all embedded in the boot sequence).
>

There's this arcane `Warm boot with partial re-initialization' BIOS feature
using the CMOS register 0xf, but I don't want to to depend on it either.

> James
> 

Thanks,

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 94%]

* Re: [PATCH -next 2/2][RFC] x86: Saveoops: Reserve low memory and register code
  @ 2011-01-26  9:04 98%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2011-01-26  9:04 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, X86-ML, Tony Luck,
	Dave Jones, Andrew Morton, Randy Dunlap, Willy Tarreau,
	Willy Tarreau, Dirk Hohndel, Dirk.Hohndel, IDE-ML, LKML,
	Linus Torvalds, Peter Zijlstra, Frédéric Weisbecker,
	Borislav Petkov, Arjan van de Ven, Tejun Heo, James Bottomley,
	Mark Lord, Jeff Garzik

On Tue, Jan 25, 2011 at 09:29:58AM -0800, H. Peter Anvin wrote:
> 
> However, I'm quite nervous about this -- this patch has *plenty* of real
> possibility of wrecking data.
> 

Yes, it does.

Keep in mind though that now I'm just prototyping different solutions to
a problem I'm facing. I fully understand that in no way this patch is
going to be merged in its current state.

I'll send another email summarizing the criticism and proposing different
paths in a moment.

thanks,

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 98%]

* Re: [PATCH 0/2][concept RFC] x86: BIOS-save kernel log to disk upon panic
  @ 2011-01-26 11:44 98%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2011-01-26 11:44 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, X86-ML, Tony Luck,
	Dave Jones, Andrew Morton, Randy Dunlap, Willy Tarreau,
	Willy Tarreau, Dirk Hohndel, Dirk.Hohndel, IDE-ML, LKML,
	Linus Torvalds, Peter Zijlstra, Frédéric Weisbecker,
	Borislav Petkov, Arjan van de Ven, Tejun Heo, James Bottomley,
	Mark Lord, Jeff Garzik

On Tue, Jan 25, 2011 at 09:33:18AM -0800, H. Peter Anvin wrote:
> On 01/25/2011 07:08 AM, Tejun Heo wrote:
> 
> >> All in one, a very intriguing idea IMO, and the hardest bits
> >> (lowlevel x86 transition) is all implemented already.
> 
> Lowlevel x86 transition is not at all the hardest part.  It's
> detail-oriented but well defined (and, I might add, incompletely
> implemented -- 64 bits only, not using facilities we already have);
>

Making the transition code applicable to 32-bit CPUs will hopefully be
quite simple: it's mostly a subset of the posted parts.

Since I might use that transition code for a different purpose now, any
facilities not properly used beside the identity mappings?

thanks,

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 98%]

* Re: [PATCH 0/2][concept RFC] x86: BIOS-save kernel log to disk upon panic
       [not found]               ` <m1sjweyeax.fsf@fess.ebiederm.org>
@ 2011-02-02 11:13 98%             ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2011-02-02 11:13 UTC (permalink / raw)
  To: Ingo Molnar, Eric W. Biederman
  Cc: H. Peter Anvin, Vivek Goyal, Linus Torvalds, Thomas Gleixner,
	Ingo Molnar, X86-ML, Tony Luck, Dave Jones, Andrew Morton,
	Randy Dunlap, Willy Tarreau, Willy Tarreau, Dirk Hohndel,
	Dirk.Hohndel, IDE-ML, LKML, Peter Zijlstra,
	Frédéric Weisbecker, Borislav Petkov, Arjan van de Ven,
	Tejun Heo, James Bottomley, Mark Lord, Jeff Garzik, Haren Myneni,
	KEXEC-ML, FBDEV-ML

Hi,

Quick note: the Internet has just returned back here after a full
5-day shutdown by the “authorities”. I will hopefully return back
home on Saturday to continue working on this.

thanks,

^ permalink raw reply	[relevance 98%]

* [PATCH -next] Documentation: Improve crashkernel= description
@ 2011-02-06 15:41 99% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2011-02-06 15:41 UTC (permalink / raw)
  To: Randy Dunlap, Vivek Goyal, Haren Myneni
  Cc: Eric Biederman, kexec, LKML, linux-doc

(Also applicable over 2.6.38-rc3)

Had to explore two C code files to make sense of the 'crashkernel='
kernel parameter values.  Improve the situation.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 89835a4..8f26b42 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -545,9 +545,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			Format:
 			<first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
 
-	crashkernel=nn[KMG]@ss[KMG]
-			[KNL] Reserve a chunk of physical memory to
-			hold a kernel to switch to with kexec on panic.
+	crashkernel=size[KMG][@offset[KMG]]
+			[KNL] Using kexec, Linux can switch to a 'crash kernel'
+			upon panic. This parameter reserves the physical
+			memory region [offset, offset + size] for that kernel
+			image. If the '@offset' part was ignored, Linux finds
+			a suitable crash image start address automatically.
 
 	crashkernel=range1:size1[,range2:size2,...][@offset]
 			[KNL] Same as above, but depends on the memory

regards,

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 99%]

* [PATCH -next] Documentation: Explain the [KMG] parameters suffix
@ 2011-02-06 17:45 99% Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2011-02-06 17:45 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: LKML, linux-doc

(Also applicable over 2.6.38-rc3)

The '[KMG]' suffix is commonly described after a number of kernel
parameter values documentation.  Explicitly state its semantics.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 89835a4..3deedce 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -144,6 +144,11 @@ a fixed number of characters. This limit depends on the architecture
 and is between 256 and 4096 characters. It is defined in the file
 ./include/asm/setup.h as COMMAND_LINE_SIZE.
 
+Finally, the [KMG] suffix is commonly described after a number of kernel
+parameter values. These 'K', 'M', and 'G' letters represent the _binary_
+multipliers 'Kilo', 'Mega', and 'Giga', equalling 2^10, 2^20, and 2^30
+bytes respectively. Such letter suffixes can also be entirely omitted.
+
 
 	acpi=		[HW,ACPI,X86]
 			Advanced Configuration and Power Interface

regards,

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 99%]

* [PATCH v2 -next] Documentation: Improve crashkernel= description
  @ 2011-02-07 11:30 99%     ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2011-02-07 11:30 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: Simon Horman, Vivek Goyal, Haren Myneni, Eric Biederman, kexec,
	LKML, linux-doc


Had to explore two C code files to make sense of the 'crashkernel='
kernel parameter values.  Improve the situation.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 89835a4..5ad9980 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -545,9 +545,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			Format:
 			<first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
 
-	crashkernel=nn[KMG]@ss[KMG]
-			[KNL] Reserve a chunk of physical memory to
-			hold a kernel to switch to with kexec on panic.
+	crashkernel=size[KMG][@offset[KMG]]
+			[KNL] Using kexec, Linux can switch to a 'crash kernel'
+			upon panic. This parameter reserves the physical
+			memory region [offset, offset + size] for that kernel
+			image. If '@offset' is omitted, then a suitable offset
+			is selected automatically.
 
 	crashkernel=range1:size1[,range2:size2,...][@offset]
 			[KNL] Same as above, but depends on the memory

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] Documentation: log_buf_len accepts [KMG]
  @ 2011-02-07 11:40 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2011-02-07 11:40 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: LKML, linux-doc, Randy Dunlap

On Sun, Feb 06, 2011 at 08:40:02PM -0800, Randy Dunlap wrote:
> 
> Update the "log_buf_len" description to use [KMG] syntax for the
> buffer size.
> 
> Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
> ---
> 

This implies an ACK for the original patch?

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 99%]

* [PATCH v3 -next] Documentation: Improve crashkernel= description
  @ 2011-02-07 16:01 95%         ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2011-02-07 16:01 UTC (permalink / raw)
  To: Vivek Goyal
  Cc: Randy Dunlap, Simon Horman, Haren Myneni, Eric Biederman, kexec,
	LKML, linux-doc

On Mon, Feb 07, 2011 at 09:25:50AM -0500, Vivek Goyal wrote:
> On Mon, Feb 07, 2011 at 01:30:54PM +0200, Ahmed S. Darwish wrote:
> > 
> > Had to explore two C code files to make sense of the 'crashkernel='
> > kernel parameter values.  Improve the situation.
> > 
> 
> Did you look at Documentation/kdump/kdump.txt before looking into the
> code. I thought kdump.txt explained the meaning of crashkernel= well.
> 
> In case if it was not obivious that for further details look into
> kdump.txt, I will suggest to add a line asking reader to look into
> kdump.txt for more details.
> 

Yes, I jumped to the code first :-) Here's a new patch with the link:

(Also applicable over latest -rc3)

==>

Complete the crashkernel= kernel parameter documentation.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
---

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 89835a4..050b0e5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -545,16 +545,20 @@ and is between 256 and 4096 characters. It is defined in the file
 			Format:
 			<first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
 
-	crashkernel=nn[KMG]@ss[KMG]
-			[KNL] Reserve a chunk of physical memory to
-			hold a kernel to switch to with kexec on panic.
+	crashkernel=size[KMG][@offset[KMG]]
+			[KNL] Using kexec, Linux can switch to a 'crash kernel'
+			upon panic. This parameter reserves the physical
+			memory region [offset, offset + size] for that kernel
+			image. If '@offset' is omitted, then a suitable offset
+			is selected automatically. Check
+			Documentation/kdump/kdump.txt for further details.
 
 	crashkernel=range1:size1[,range2:size2,...][@offset]
 			[KNL] Same as above, but depends on the memory
 			in the running system. The syntax of range is
 			start-[end] where start and end are both
 			a memory unit (amount[KMG]). See also
-			Documentation/kdump/kdump.txt for a example.
+			Documentation/kdump/kdump.txt for an example.
 
 	cs89x0_dma=	[HW,NET]
 			Format: <dma>


> 
> Acked-by: Vivek Goyal <vgoyal@redhat.com>
> 

thanks,

-- 
Darwish
http://darwish.07.googlepages.com

^ permalink raw reply	[relevance 95%]

* [PATCH] can: kvaser_usb: Don't free packets when tight on URBs
@ 2014-12-23 15:46 96% Ahmed S. Darwish
  2014-12-23 15:53 36% ` [PATCH] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
                   ` (6 more replies)
  0 siblings, 7 replies; 200+ results
From: Ahmed S. Darwish @ 2014-12-23 15:46 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Flooding the Kvaser CAN to USB dongle with multiple reads and
writes in high frequency caused seemingly-random panics in the
kernel.

On further inspection, it seems the driver erroneously freed the
to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees
at a later point in time.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

 (Generated over 3.19.0-rc1)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 541fb7a..34c35d8 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -1286,6 +1286,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	struct kvaser_msg *msg;
 	int i, err;
 	int ret = NETDEV_TX_OK;
+	bool kfree_skb_on_error = true;
 
 	if (can_dropped_invalid_skb(netdev, skb))
 		return NETDEV_TX_OK;
@@ -1336,6 +1337,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 
 	if (!context) {
 		netdev_warn(netdev, "cannot find free context\n");
+		kfree_skb_on_error = false;
 		ret =  NETDEV_TX_BUSY;
 		goto releasebuf;
 	}
@@ -1364,8 +1366,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	if (unlikely(err)) {
 		can_free_echo_skb(netdev, context->echo_index);
 
-		skb = NULL; /* set to NULL to avoid double free in
-			     * dev_kfree_skb(skb) */
+		kfree_skb_on_error = false;
 
 		atomic_dec(&priv->active_tx_urbs);
 		usb_unanchor_urb(urb);
@@ -1389,7 +1390,8 @@ releasebuf:
 nobufmem:
 	usb_free_urb(urb);
 nourbmem:
-	dev_kfree_skb(skb);
+	if (kfree_skb_on_error)
+		dev_kfree_skb(skb);
 	return ret;
 }


^ permalink raw reply	[relevance 96%]

* [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-23 15:46 96% [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
@ 2014-12-23 15:53 36% ` Ahmed S. Darwish
                       ` (5 subsequent siblings)
  6 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2014-12-23 15:53 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

CAN to USB interfaces sold by the Swedish manufacturer Kvaser are
divided into two major families: 'Leaf', and 'UsbcanII'.  From an
Operating System perspective, the firmware of both families behave
in a not too drastically different fashion.

This patch adds support for the UsbcanII family of devices to the
current Kvaser Leaf-only driver.

CAN frames sending, receiving, and error handling paths has been
tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It
should also work nicely with other products in the same category.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 630 +++++++++++++++++++++++++++++++--------
 1 file changed, 505 insertions(+), 125 deletions(-)

 (Generated over 3.19.0-rc1 + generic bugfix at
  can-kvaser_usb-Don-t-free-packets-when-tight-on-URBs.patch)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 34c35d8..e7076da 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -6,12 +6,15 @@
  * Parts of this driver are based on the following:
  *  - Kvaser linux leaf driver (version 4.78)
  *  - CAN driver for esd CAN-USB/2
+ *  - Kvaser linux usbcanII driver (version 5.3)
  *
  * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
  * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * Copyright (C) 2014 Valeo Corporation
  */
 
+#include <linux/kernel.h>
 #include <linux/completion.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -21,6 +24,18 @@
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+/*
+ * Kvaser USB CAN dongles are divided into two major families:
+ * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo'
+ * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios'
+ */
+enum kvaser_usb_family {
+	KVASER_LEAF,
+	KVASER_USBCAN,
+};
+
 #define MAX_TX_URBS			16
 #define MAX_RX_URBS			4
 #define START_TIMEOUT			1000 /* msecs */
@@ -29,9 +44,12 @@
 #define USB_RECV_TIMEOUT		1000 /* msecs */
 #define RX_BUFFER_SIZE			3072
 #define CAN_USB_CLOCK			8000000
-#define MAX_NET_DEVICES			3
+#define LEAF_MAX_NET_DEVICES		3
+#define USBCAN_MAX_NET_DEVICES		2
+#define MAX_NET_DEVICES			MAX(LEAF_MAX_NET_DEVICES, \
+					    USBCAN_MAX_NET_DEVICES)
 
-/* Kvaser USB devices */
+/* Leaf USB devices */
 #define KVASER_VENDOR_ID		0x0bfd
 #define USB_LEAF_DEVEL_PRODUCT_ID	10
 #define USB_LEAF_LITE_PRODUCT_ID	11
@@ -55,6 +73,16 @@
 #define USB_CAN_R_PRODUCT_ID		39
 #define USB_LEAF_LITE_V2_PRODUCT_ID	288
 #define USB_MINI_PCIE_HS_PRODUCT_ID	289
+#define LEAF_PRODUCT_ID(id)		(id >= USB_LEAF_DEVEL_PRODUCT_ID && \
+					 id <= USB_MINI_PCIE_HS_PRODUCT_ID)
+
+/* USBCANII devices */
+#define USB_USBCAN_REVB_PRODUCT_ID	2
+#define USB_VCI2_PRODUCT_ID		3
+#define USB_USBCAN2_PRODUCT_ID		4
+#define USB_MEMORATOR_PRODUCT_ID	5
+#define USBCAN_PRODUCT_ID(id)		(id >= USB_USBCAN_REVB_PRODUCT_ID && \
+					 id <= USB_MEMORATOR_PRODUCT_ID)
 
 /* USB devices features */
 #define KVASER_HAS_SILENT_MODE		BIT(0)
@@ -73,7 +101,7 @@
 #define MSG_FLAG_TX_ACK			BIT(6)
 #define MSG_FLAG_TX_REQUEST		BIT(7)
 
-/* Can states */
+/* Can states (M16C CxSTRH register) */
 #define M16C_STATE_BUS_RESET		BIT(0)
 #define M16C_STATE_BUS_ERROR		BIT(4)
 #define M16C_STATE_BUS_PASSIVE		BIT(5)
@@ -98,7 +126,13 @@
 #define CMD_START_CHIP_REPLY		27
 #define CMD_STOP_CHIP			28
 #define CMD_STOP_CHIP_REPLY		29
-#define CMD_GET_CARD_INFO2		32
+#define CMD_READ_CLOCK			30
+#define CMD_READ_CLOCK_REPLY		31
+
+#define LEAF_CMD_GET_CARD_INFO2		32
+#define USBCAN_CMD_RESET_CLOCK		32
+#define USBCAN_CMD_CLOCK_OVERFLOW_EVENT	33
+
 #define CMD_GET_CARD_INFO		34
 #define CMD_GET_CARD_INFO_REPLY		35
 #define CMD_GET_SOFTWARE_INFO		38
@@ -108,8 +142,9 @@
 #define CMD_RESET_ERROR_COUNTER		49
 #define CMD_TX_ACKNOWLEDGE		50
 #define CMD_CAN_ERROR_EVENT		51
-#define CMD_USB_THROTTLE		77
-#define CMD_LOG_MESSAGE			106
+
+#define LEAF_CMD_USB_THROTTLE		77
+#define LEAF_CMD_LOG_MESSAGE		106
 
 /* error factors */
 #define M16C_EF_ACKE			BIT(0)
@@ -121,6 +156,13 @@
 #define M16C_EF_RCVE			BIT(6)
 #define M16C_EF_TRE			BIT(7)
 
+/* Only Leaf-based devices can report M16C error factors,
+ * thus define our own error status flags for USBCAN */
+#define USBCAN_ERROR_STATE_NONE		0
+#define USBCAN_ERROR_STATE_TX_ERROR	BIT(0)
+#define USBCAN_ERROR_STATE_RX_ERROR	BIT(1)
+#define USBCAN_ERROR_STATE_BUSERROR	BIT(2)
+
 /* bittiming parameters */
 #define KVASER_USB_TSEG1_MIN		1
 #define KVASER_USB_TSEG1_MAX		16
@@ -137,7 +179,7 @@
 #define KVASER_CTRL_MODE_SELFRECEPTION	3
 #define KVASER_CTRL_MODE_OFF		4
 
-/* log message */
+/* Extended CAN identifier flag */
 #define KVASER_EXTENDED_FRAME		BIT(31)
 
 struct kvaser_msg_simple {
@@ -148,30 +190,55 @@ struct kvaser_msg_simple {
 struct kvaser_msg_cardinfo {
 	u8 tid;
 	u8 nchannels;
-	__le32 serial_number;
-	__le32 padding;
+	union {
+		struct {
+			__le32 serial_number;
+			__le32 padding;
+		} __packed leaf0;
+		struct {
+			__le32 serial_number_low;
+			__le32 serial_number_high;
+		} __packed usbcan0;
+	} __packed;
 	__le32 clock_resolution;
 	__le32 mfgdate;
 	u8 ean[8];
 	u8 hw_revision;
-	u8 usb_hs_mode;
-	__le16 padding2;
+	union {
+		struct {
+			u8 usb_hs_mode;
+		} __packed leaf1;
+		struct {
+			u8 padding;
+		} __packed usbcan1;
+	} __packed;
+	__le16 padding;
 } __packed;
 
 struct kvaser_msg_cardinfo2 {
 	u8 tid;
-	u8 channel;
+	u8 reserved;
 	u8 pcb_id[24];
 	__le32 oem_unlock_code;
 } __packed;
 
-struct kvaser_msg_softinfo {
+struct leaf_msg_softinfo {
 	u8 tid;
-	u8 channel;
+	u8 padding0;
 	__le32 sw_options;
 	__le32 fw_version;
 	__le16 max_outstanding_tx;
-	__le16 padding[9];
+	__le16 padding1[9];
+} __packed;
+
+struct usbcan_msg_softinfo {
+	u8 tid;
+	u8 fw_name[5];
+	__le16 max_outstanding_tx;
+	u8 padding[6];
+	__le32 fw_version;
+	__le16 checksum;
+	__le16 sw_options;
 } __packed;
 
 struct kvaser_msg_busparams {
@@ -188,36 +255,86 @@ struct kvaser_msg_tx_can {
 	u8 channel;
 	u8 tid;
 	u8 msg[14];
-	u8 padding;
-	u8 flags;
+	union {
+		struct {
+			u8 padding;
+			u8 flags;
+		} __packed leaf;
+		struct {
+			u8 flags;
+			u8 padding;
+		} __packed usbcan;
+	} __packed;
+} __packed;
+
+struct kvaser_msg_rx_can_header {
+	u8 channel;
+	u8 flag;
 } __packed;
 
-struct kvaser_msg_rx_can {
+struct leaf_msg_rx_can {
 	u8 channel;
 	u8 flag;
+
 	__le16 time[3];
 	u8 msg[14];
 } __packed;
 
-struct kvaser_msg_chip_state_event {
+struct usbcan_msg_rx_can {
+	u8 channel;
+	u8 flag;
+
+	u8 msg[14];
+	__le16 time;
+} __packed;
+
+struct leaf_msg_chip_state_event {
 	u8 tid;
 	u8 channel;
+
 	__le16 time[3];
 	u8 tx_errors_count;
 	u8 rx_errors_count;
+
 	u8 status;
 	u8 padding[3];
 } __packed;
 
-struct kvaser_msg_tx_acknowledge {
+struct usbcan_msg_chip_state_event {
+	u8 tid;
+	u8 channel;
+
+	u8 tx_errors_count;
+	u8 rx_errors_count;
+	__le16 time;
+
+	u8 status;
+	u8 padding[3];
+} __packed;
+
+struct kvaser_msg_tx_acknowledge_header {
+	u8 channel;
+	u8 tid;
+};
+
+struct leaf_msg_tx_acknowledge {
 	u8 channel;
 	u8 tid;
+
 	__le16 time[3];
 	u8 flags;
 	u8 time_offset;
 } __packed;
 
-struct kvaser_msg_error_event {
+struct usbcan_msg_tx_acknowledge {
+	u8 channel;
+	u8 tid;
+
+	__le16 time;
+	__le16 padding;
+} __packed;
+
+struct leaf_msg_error_event {
 	u8 tid;
 	u8 flags;
 	__le16 time[3];
@@ -229,6 +346,18 @@ struct kvaser_msg_error_event {
 	u8 error_factor;
 } __packed;
 
+struct usbcan_msg_error_event {
+	u8 tid;
+	u8 padding;
+	u8 tx_errors_count_ch0;
+	u8 rx_errors_count_ch0;
+	u8 tx_errors_count_ch1;
+	u8 rx_errors_count_ch1;
+	u8 status_ch0;
+	u8 status_ch1;
+	__le16 time;
+} __packed;
+
 struct kvaser_msg_ctrl_mode {
 	u8 tid;
 	u8 channel;
@@ -243,7 +372,7 @@ struct kvaser_msg_flush_queue {
 	u8 padding[3];
 } __packed;
 
-struct kvaser_msg_log_message {
+struct leaf_msg_log_message {
 	u8 channel;
 	u8 flags;
 	__le16 time[3];
@@ -260,19 +389,49 @@ struct kvaser_msg {
 		struct kvaser_msg_simple simple;
 		struct kvaser_msg_cardinfo cardinfo;
 		struct kvaser_msg_cardinfo2 cardinfo2;
-		struct kvaser_msg_softinfo softinfo;
 		struct kvaser_msg_busparams busparams;
+
+		struct kvaser_msg_rx_can_header rx_can_header;
+		struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header;
+
+		union {
+			struct leaf_msg_softinfo softinfo;
+			struct leaf_msg_rx_can rx_can;
+			struct leaf_msg_chip_state_event chip_state_event;
+			struct leaf_msg_tx_acknowledge tx_acknowledge;
+			struct leaf_msg_error_event error_event;
+			struct leaf_msg_log_message log_message;
+		} __packed leaf;
+
+		union {
+			struct usbcan_msg_softinfo softinfo;
+			struct usbcan_msg_rx_can rx_can;
+			struct usbcan_msg_chip_state_event chip_state_event;
+			struct usbcan_msg_tx_acknowledge tx_acknowledge;
+			struct usbcan_msg_error_event error_event;
+		} __packed usbcan;
+
 		struct kvaser_msg_tx_can tx_can;
-		struct kvaser_msg_rx_can rx_can;
-		struct kvaser_msg_chip_state_event chip_state_event;
-		struct kvaser_msg_tx_acknowledge tx_acknowledge;
-		struct kvaser_msg_error_event error_event;
 		struct kvaser_msg_ctrl_mode ctrl_mode;
 		struct kvaser_msg_flush_queue flush_queue;
-		struct kvaser_msg_log_message log_message;
 	} u;
 } __packed;
 
+/* Leaf/USBCAN-agnostic summary of an error event.
+ * No M16C error factors for USBCAN-based devices. */
+struct kvaser_error_summary {
+	u8 channel, status, txerr, rxerr;
+	union {
+		struct {
+			u8 error_factor;
+		} leaf;
+		struct {
+			u8 other_ch_status;
+			u8 error_state;
+		} usbcan;
+	};
+};
+
 struct kvaser_usb_tx_urb_context {
 	struct kvaser_usb_net_priv *priv;
 	u32 echo_index;
@@ -288,6 +447,8 @@ struct kvaser_usb {
 
 	u32 fw_version;
 	unsigned int nchannels;
+	enum kvaser_usb_family family;
+	unsigned int max_channels;
 
 	bool rxinitdone;
 	void *rxbuf[MAX_RX_URBS];
@@ -311,6 +472,7 @@ struct kvaser_usb_net_priv {
 };
 
 static const struct usb_device_id kvaser_usb_table[] = {
+	/* Leaf family IDs */
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
@@ -360,6 +522,17 @@ static const struct usb_device_id kvaser_usb_table[] = {
 		.driver_info = KVASER_HAS_TXRX_ERRORS },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
+
+	/* USBCANII family IDs */
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -463,7 +636,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
 	if (err)
 		return err;
 
-	dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
+	switch (dev->family) {
+	case KVASER_LEAF:
+		dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
+		break;
+	case KVASER_USBCAN:
+		dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -482,7 +666,7 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
 		return err;
 
 	dev->nchannels = msg.u.cardinfo.nchannels;
-	if (dev->nchannels > MAX_NET_DEVICES)
+	if (dev->nchannels > dev->max_channels)
 		return -EINVAL;
 
 	return 0;
@@ -496,8 +680,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 	struct kvaser_usb_net_priv *priv;
 	struct sk_buff *skb;
 	struct can_frame *cf;
-	u8 channel = msg->u.tx_acknowledge.channel;
-	u8 tid = msg->u.tx_acknowledge.tid;
+	u8 channel, tid;
+
+	channel = msg->u.tx_acknowledge_header.channel;
+	tid = msg->u.tx_acknowledge_header.tid;
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -615,37 +801,83 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
 		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
 }
 
-static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
-				const struct kvaser_msg *msg)
+static void kvaser_report_error_event(const struct kvaser_usb *dev,
+				      struct kvaser_error_summary *es);
+
+/*
+ * Report error to userspace iff the controller's errors counter has
+ * increased, or we're the only channel seeing the bus error state.
+ *
+ * As reported by USBCAN sheets, "the CAN controller has difficulties
+ * to tell whether an error frame arrived on channel 1 or on channel 2."
+ * Thus, error counters are compared with their earlier values to
+ * determine which channel was responsible for the error event.
+ */
+static void usbcan_report_error_if_applicable(const struct kvaser_usb *dev,
+					      struct kvaser_error_summary *es)
 {
-	struct can_frame *cf;
-	struct sk_buff *skb;
-	struct net_device_stats *stats;
 	struct kvaser_usb_net_priv *priv;
-	unsigned int new_state;
-	u8 channel, status, txerr, rxerr, error_factor;
+	int old_tx_err_count, old_rx_err_count, channel, report_error;
+
+	channel = es->channel;
+	if (channel >= dev->nchannels) {
+		dev_err(dev->udev->dev.parent,
+			"Invalid channel number (%d)\n", channel);
+		return;
+	}
+
+	priv = dev->nets[channel];
+	old_tx_err_count = priv->bec.txerr;
+	old_rx_err_count = priv->bec.rxerr;
+
+	report_error = 0;
+	if (es->txerr > old_tx_err_count) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR;
+		report_error = 1;
+	}
+	if (es->rxerr > old_rx_err_count) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR;
+		report_error = 1;
+	}
+	if ((es->status & M16C_STATE_BUS_ERROR) &&
+	    !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR;
+		report_error = 1;
+	}
+
+	if (report_error)
+		kvaser_report_error_event(dev, es);
+}
+
+/*
+ * Extract error summary from a Leaf-based device error message
+ */
+static void leaf_extract_error_from_msg(const struct kvaser_usb *dev,
+					const struct kvaser_msg *msg)
+{
+	struct kvaser_error_summary es = { 0, };
 
 	switch (msg->id) {
 	case CMD_CAN_ERROR_EVENT:
-		channel = msg->u.error_event.channel;
-		status =  msg->u.error_event.status;
-		txerr = msg->u.error_event.tx_errors_count;
-		rxerr = msg->u.error_event.rx_errors_count;
-		error_factor = msg->u.error_event.error_factor;
+		es.channel = msg->u.leaf.error_event.channel;
+		es.status =  msg->u.leaf.error_event.status;
+		es.txerr = msg->u.leaf.error_event.tx_errors_count;
+		es.rxerr = msg->u.leaf.error_event.rx_errors_count;
+		es.leaf.error_factor = msg->u.leaf.error_event.error_factor;
 		break;
-	case CMD_LOG_MESSAGE:
-		channel = msg->u.log_message.channel;
-		status = msg->u.log_message.data[0];
-		txerr = msg->u.log_message.data[2];
-		rxerr = msg->u.log_message.data[3];
-		error_factor = msg->u.log_message.data[1];
+	case LEAF_CMD_LOG_MESSAGE:
+		es.channel = msg->u.leaf.log_message.channel;
+		es.status = msg->u.leaf.log_message.data[0];
+		es.txerr = msg->u.leaf.log_message.data[2];
+		es.rxerr = msg->u.leaf.log_message.data[3];
+		es.leaf.error_factor = msg->u.leaf.log_message.data[1];
 		break;
 	case CMD_CHIP_STATE_EVENT:
-		channel = msg->u.chip_state_event.channel;
-		status =  msg->u.chip_state_event.status;
-		txerr = msg->u.chip_state_event.tx_errors_count;
-		rxerr = msg->u.chip_state_event.rx_errors_count;
-		error_factor = 0;
+		es.channel = msg->u.leaf.chip_state_event.channel;
+		es.status =  msg->u.leaf.chip_state_event.status;
+		es.txerr = msg->u.leaf.chip_state_event.tx_errors_count;
+		es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count;
+		es.leaf.error_factor = 0;
 		break;
 	default:
 		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
@@ -653,16 +885,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		return;
 	}
 
-	if (channel >= dev->nchannels) {
+	kvaser_report_error_event(dev, &es);
+}
+
+/*
+ * Extract summary from a USBCANII-based device error message.
+ */
+static void usbcan_extract_error_from_msg(const struct kvaser_usb *dev,
+					const struct kvaser_msg *msg)
+{
+	struct kvaser_error_summary es = { 0, };
+
+	switch (msg->id) {
+
+	/* Sometimes errors are sent as unsolicited chip state events */
+	case CMD_CHIP_STATE_EVENT:
+		es.channel = msg->u.usbcan.chip_state_event.channel;
+		es.status =  msg->u.usbcan.chip_state_event.status;
+		es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count;
+		es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count;
+		usbcan_report_error_if_applicable(dev, &es);
+		break;
+
+	case CMD_CAN_ERROR_EVENT:
+		es.channel = 0;
+		es.status = msg->u.usbcan.error_event.status_ch0;
+		es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0;
+		es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0;
+		es.usbcan.other_ch_status =
+			msg->u.usbcan.error_event.status_ch1;
+		usbcan_report_error_if_applicable(dev, &es);
+
+		/* For error events, the USBCAN firmware does not support
+		 * more than 2 channels: ch0, and ch1. */
+		if (dev->nchannels > 1) {
+			es.channel = 1;
+			es.status = msg->u.usbcan.error_event.status_ch1;
+			es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1;
+			es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1;
+			es.usbcan.other_ch_status =
+				msg->u.usbcan.error_event.status_ch0;
+			usbcan_report_error_if_applicable(dev, &es);
+		}
+		break;
+
+	default:
+		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
+			msg->id);
+	}
+}
+
+static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
+				const struct kvaser_msg *msg)
+{
+	switch (dev->family) {
+	case KVASER_LEAF:
+		leaf_extract_error_from_msg(dev, msg);
+		break;
+	case KVASER_USBCAN:
+		usbcan_extract_error_from_msg(dev, msg);
+		break;
+	default:
 		dev_err(dev->udev->dev.parent,
-			"Invalid channel number (%d)\n", channel);
+			"Invalid device family (%d)\n", dev->family);
 		return;
 	}
+}
 
-	priv = dev->nets[channel];
+static void kvaser_report_error_event(const struct kvaser_usb *dev,
+				      struct kvaser_error_summary *es)
+{
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	struct net_device_stats *stats;
+	struct kvaser_usb_net_priv *priv;
+	unsigned int new_state;
+
+	if (es->channel >= dev->nchannels) {
+		dev_err(dev->udev->dev.parent,
+			"Invalid channel number (%d)\n", es->channel);
+		return;
+	}
+
+	priv = dev->nets[es->channel];
 	stats = &priv->netdev->stats;
 
-	if (status & M16C_STATE_BUS_RESET) {
+	if (es->status & M16C_STATE_BUS_RESET) {
 		kvaser_usb_unlink_tx_urbs(priv);
 		return;
 	}
@@ -675,9 +983,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
 	new_state = priv->can.state;
 
-	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
+	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
 
-	if (status & M16C_STATE_BUS_OFF) {
+	if (es->status & M16C_STATE_BUS_OFF) {
 		cf->can_id |= CAN_ERR_BUSOFF;
 
 		priv->can.can_stats.bus_off++;
@@ -687,12 +995,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		netif_carrier_off(priv->netdev);
 
 		new_state = CAN_STATE_BUS_OFF;
-	} else if (status & M16C_STATE_BUS_PASSIVE) {
+	} else if (es->status & M16C_STATE_BUS_PASSIVE) {
 		if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
 			cf->can_id |= CAN_ERR_CRTL;
 
-			if (txerr || rxerr)
-				cf->data[1] = (txerr > rxerr)
+			if (es->txerr || es->rxerr)
+				cf->data[1] = (es->txerr > es->rxerr)
 						? CAN_ERR_CRTL_TX_PASSIVE
 						: CAN_ERR_CRTL_RX_PASSIVE;
 			else
@@ -703,13 +1011,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 
 		new_state = CAN_STATE_ERROR_PASSIVE;
-	}
-
-	if (status == M16C_STATE_BUS_ERROR) {
+	} else if (es->status & M16C_STATE_BUS_ERROR) {
 		if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
-		    ((txerr >= 96) || (rxerr >= 96))) {
+		    ((es->txerr >= 96) || (es->rxerr >= 96))) {
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (txerr > rxerr)
+			cf->data[1] = (es->txerr > es->rxerr)
 					? CAN_ERR_CRTL_TX_WARNING
 					: CAN_ERR_CRTL_RX_WARNING;
 
@@ -723,7 +1029,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 	}
 
-	if (!status) {
+	if (!es->status) {
 		cf->can_id |= CAN_ERR_PROT;
 		cf->data[2] = CAN_ERR_PROT_ACTIVE;
 
@@ -739,34 +1045,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		priv->can.can_stats.restarts++;
 	}
 
-	if (error_factor) {
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-
-		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-
-		if (error_factor & M16C_EF_ACKE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
-		if (error_factor & M16C_EF_CRCE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-					CAN_ERR_PROT_LOC_CRC_DEL);
-		if (error_factor & M16C_EF_FORME)
-			cf->data[2] |= CAN_ERR_PROT_FORM;
-		if (error_factor & M16C_EF_STFE)
-			cf->data[2] |= CAN_ERR_PROT_STUFF;
-		if (error_factor & M16C_EF_BITE0)
-			cf->data[2] |= CAN_ERR_PROT_BIT0;
-		if (error_factor & M16C_EF_BITE1)
-			cf->data[2] |= CAN_ERR_PROT_BIT1;
-		if (error_factor & M16C_EF_TRE)
-			cf->data[2] |= CAN_ERR_PROT_TX;
+	switch (dev->family) {
+	case KVASER_LEAF:
+		if (es->leaf.error_factor) {
+			priv->can.can_stats.bus_error++;
+			stats->rx_errors++;
+
+			cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+
+			if (es->leaf.error_factor & M16C_EF_ACKE)
+				cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
+			if (es->leaf.error_factor & M16C_EF_CRCE)
+				cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+						CAN_ERR_PROT_LOC_CRC_DEL);
+			if (es->leaf.error_factor & M16C_EF_FORME)
+				cf->data[2] |= CAN_ERR_PROT_FORM;
+			if (es->leaf.error_factor & M16C_EF_STFE)
+				cf->data[2] |= CAN_ERR_PROT_STUFF;
+			if (es->leaf.error_factor & M16C_EF_BITE0)
+				cf->data[2] |= CAN_ERR_PROT_BIT0;
+			if (es->leaf.error_factor & M16C_EF_BITE1)
+				cf->data[2] |= CAN_ERR_PROT_BIT1;
+			if (es->leaf.error_factor & M16C_EF_TRE)
+				cf->data[2] |= CAN_ERR_PROT_TX;
+		}
+		break;
+	case KVASER_USBCAN:
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
+			stats->tx_errors++;
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
+			stats->rx_errors++;
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
+			priv->can.can_stats.bus_error++;
+			cf->can_id |= CAN_ERR_BUSERROR;
+		}
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		goto err;
 	}
 
-	cf->data[6] = txerr;
-	cf->data[7] = rxerr;
+	cf->data[6] = es->txerr;
+	cf->data[7] = es->rxerr;
 
-	priv->bec.txerr = txerr;
-	priv->bec.rxerr = rxerr;
+	priv->bec.txerr = es->txerr;
+	priv->bec.rxerr = es->rxerr;
 
 	priv->can.state = new_state;
 
@@ -774,6 +1098,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
+
+	return;
+
+err:
+	dev_kfree_skb(skb);
 }
 
 static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -783,16 +1112,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 	struct sk_buff *skb;
 	struct net_device_stats *stats = &priv->netdev->stats;
 
-	if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+	if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
 					 MSG_FLAG_NERR)) {
 		netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
-			   msg->u.rx_can.flag);
+			   msg->u.rx_can_header.flag);
 
 		stats->rx_errors++;
 		return;
 	}
 
-	if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
+	if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) {
 		skb = alloc_can_err_skb(priv->netdev, &cf);
 		if (!skb) {
 			stats->rx_dropped++;
@@ -819,7 +1148,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 	struct can_frame *cf;
 	struct sk_buff *skb;
 	struct net_device_stats *stats;
-	u8 channel = msg->u.rx_can.channel;
+	u8 channel = msg->u.rx_can_header.channel;
+	const u8 *rx_msg;
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -830,19 +1160,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 	priv = dev->nets[channel];
 	stats = &priv->netdev->stats;
 
-	if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) &&
-	    (msg->id == CMD_LOG_MESSAGE)) {
+	if ((msg->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
+	    (dev->family == KVASER_LEAF && msg->id == LEAF_CMD_LOG_MESSAGE)) {
 		kvaser_usb_rx_error(dev, msg);
 		return;
-	} else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
-					 MSG_FLAG_NERR |
-					 MSG_FLAG_OVERRUN)) {
+	} else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
+						MSG_FLAG_NERR |
+						MSG_FLAG_OVERRUN)) {
 		kvaser_usb_rx_can_err(priv, msg);
 		return;
-	} else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
+	} else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) {
 		netdev_warn(priv->netdev,
 			    "Unhandled frame (flags: 0x%02x)",
-			    msg->u.rx_can.flag);
+			    msg->u.rx_can_header.flag);
+		return;
+	}
+
+	switch (dev->family) {
+	case KVASER_LEAF:
+		rx_msg = msg->u.leaf.rx_can.msg;
+		break;
+	case KVASER_USBCAN:
+		rx_msg = msg->u.usbcan.rx_can.msg;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
 		return;
 	}
 
@@ -852,38 +1195,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 		return;
 	}
 
-	if (msg->id == CMD_LOG_MESSAGE) {
-		cf->can_id = le32_to_cpu(msg->u.log_message.id);
+	if (dev->family == KVASER_LEAF && msg->id == LEAF_CMD_LOG_MESSAGE) {
+		cf->can_id = le32_to_cpu(msg->u.leaf.log_message.id);
 		if (cf->can_id & KVASER_EXTENDED_FRAME)
 			cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
 		else
 			cf->can_id &= CAN_SFF_MASK;
 
-		cf->can_dlc = get_can_dlc(msg->u.log_message.dlc);
+		cf->can_dlc = get_can_dlc(msg->u.leaf.log_message.dlc);
 
-		if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME)
+		if (msg->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME)
 			cf->can_id |= CAN_RTR_FLAG;
 		else
-			memcpy(cf->data, &msg->u.log_message.data,
+			memcpy(cf->data, &msg->u.leaf.log_message.data,
 			       cf->can_dlc);
 	} else {
-		cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
-			     (msg->u.rx_can.msg[1] & 0x3f);
+		cf->can_id = ((rx_msg[0] & 0x1f) << 6) | (rx_msg[1] & 0x3f);
 
 		if (msg->id == CMD_RX_EXT_MESSAGE) {
 			cf->can_id <<= 18;
-			cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
-				      ((msg->u.rx_can.msg[3] & 0xff) << 6) |
-				      (msg->u.rx_can.msg[4] & 0x3f);
+			cf->can_id |= ((rx_msg[2] & 0x0f) << 14) |
+				      ((rx_msg[3] & 0xff) << 6) |
+				      (rx_msg[4] & 0x3f);
 			cf->can_id |= CAN_EFF_FLAG;
 		}
 
-		cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+		cf->can_dlc = get_can_dlc(rx_msg[5]);
 
-		if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
+		if (msg->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME)
 			cf->can_id |= CAN_RTR_FLAG;
 		else
-			memcpy(cf->data, &msg->u.rx_can.msg[6],
+			memcpy(cf->data, &rx_msg[6],
 			       cf->can_dlc);
 	}
 
@@ -947,7 +1289,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
 
 	case CMD_RX_STD_MESSAGE:
 	case CMD_RX_EXT_MESSAGE:
-	case CMD_LOG_MESSAGE:
+		kvaser_usb_rx_can_msg(dev, msg);
+		break;
+
+	case LEAF_CMD_LOG_MESSAGE:
+		if (dev->family != KVASER_LEAF)
+			goto warn;
 		kvaser_usb_rx_can_msg(dev, msg);
 		break;
 
@@ -960,8 +1307,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
 		kvaser_usb_tx_acknowledge(dev, msg);
 		break;
 
+	/* Ignored messages */
+	case USBCAN_CMD_CLOCK_OVERFLOW_EVENT:
+		if (dev->family != KVASER_USBCAN)
+			goto warn;
+		break;
+
 	default:
-		dev_warn(dev->udev->dev.parent,
+warn:		dev_warn(dev->udev->dev.parent,
 			 "Unhandled message (%d)\n", msg->id);
 		break;
 	}
@@ -1181,7 +1534,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
 				  dev->rxbuf[i],
 				  dev->rxbuf_dma[i]);
 
-	for (i = 0; i < MAX_NET_DEVICES; i++) {
+	for (i = 0; i < dev->max_channels; i++) {
 		struct kvaser_usb_net_priv *priv = dev->nets[i];
 
 		if (priv)
@@ -1286,6 +1639,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	struct kvaser_msg *msg;
 	int i, err;
 	int ret = NETDEV_TX_OK;
+	uint8_t *msg_tx_can_flags;
 	bool kfree_skb_on_error = true;
 
 	if (can_dropped_invalid_skb(netdev, skb))
@@ -1306,9 +1660,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 
 	msg = buf;
 	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
-	msg->u.tx_can.flags = 0;
 	msg->u.tx_can.channel = priv->channel;
 
+	switch (dev->family) {
+	case KVASER_LEAF:
+		msg_tx_can_flags = &msg->u.tx_can.leaf.flags;
+		break;
+	case KVASER_USBCAN:
+		msg_tx_can_flags = &msg->u.tx_can.usbcan.flags;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		goto releasebuf;
+	}
+
+	*msg_tx_can_flags = 0;
+
 	if (cf->can_id & CAN_EFF_FLAG) {
 		msg->id = CMD_TX_EXT_MESSAGE;
 		msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
@@ -1326,7 +1694,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
 
 	if (cf->can_id & CAN_RTR_FLAG)
-		msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
+		*msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
 
 	for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
 		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
@@ -1596,6 +1964,18 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 	if (!dev)
 		return -ENOMEM;
 
+	if (LEAF_PRODUCT_ID(id->idProduct)) {
+		dev->family = KVASER_LEAF;
+		dev->max_channels = LEAF_MAX_NET_DEVICES;
+	} else if (USBCAN_PRODUCT_ID(id->idProduct)) {
+		dev->family = KVASER_USBCAN;
+		dev->max_channels = USBCAN_MAX_NET_DEVICES;
+	} else {
+		dev_err(&intf->dev, "Product ID (%d) does not belong to any "
+				    "known Kvaser USB family", id->idProduct);
+		return -ENODEV;
+	}
+
 	err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
 	if (err) {
 		dev_err(&intf->dev, "Cannot get usb endpoint(s)");
@@ -1608,7 +1988,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
 	usb_set_intfdata(intf, dev);
 
-	for (i = 0; i < MAX_NET_DEVICES; i++)
+	for (i = 0; i < dev->max_channels; i++)
 		kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
 
 	err = kvaser_usb_get_software_info(dev);

^ permalink raw reply	[relevance 36%]

* Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  @ 2014-12-24 15:04 87%     ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2014-12-24 15:04 UTC (permalink / raw)
  To: Olivier Sobrie
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi Olivier,

On Wed, Dec 24, 2014 at 01:36:27PM +0100, Olivier Sobrie wrote:
> Hello Ahmed,
> 
> On Tue, Dec 23, 2014 at 05:53:11PM +0200, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
> > CAN to USB interfaces sold by the Swedish manufacturer Kvaser are
> > divided into two major families: 'Leaf', and 'UsbcanII'.  From an
> > Operating System perspective, the firmware of both families behave
> > in a not too drastically different fashion.
> > 
> > This patch adds support for the UsbcanII family of devices to the
> > current Kvaser Leaf-only driver.
> > 
> > CAN frames sending, receiving, and error handling paths has been
> > tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It
> > should also work nicely with other products in the same category.
> > 
> 
> Good, thank you :-) I'll try to test the patch during the next
> week-end. Small remarks below.
> 

Great! thanks and Merry Christmas :-)

> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > ---
> >  drivers/net/can/usb/kvaser_usb.c | 630 +++++++++++++++++++++++++++++++--------
> >  1 file changed, 505 insertions(+), 125 deletions(-)
> > 
> >  (Generated over 3.19.0-rc1 + generic bugfix at
> >   can-kvaser_usb-Don-t-free-packets-when-tight-on-URBs.patch)
> > 
> > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > index 34c35d8..e7076da 100644
> > --- a/drivers/net/can/usb/kvaser_usb.c
> > +++ b/drivers/net/can/usb/kvaser_usb.c
> > @@ -6,12 +6,15 @@
> >   * Parts of this driver are based on the following:
> >   *  - Kvaser linux leaf driver (version 4.78)
> >   *  - CAN driver for esd CAN-USB/2
> > + *  - Kvaser linux usbcanII driver (version 5.3)
> >   *
> >   * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
> >   * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
> >   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> > + * Copyright (C) 2014 Valeo Corporation
> >   */
> >  
> > +#include <linux/kernel.h>
> >  #include <linux/completion.h>
> >  #include <linux/module.h>
> >  #include <linux/netdevice.h>
> > @@ -21,6 +24,18 @@
> >  #include <linux/can/dev.h>
> >  #include <linux/can/error.h>
> >  
> > +#define MAX(a, b) ((a) > (b) ? (a) : (b))
> 
> There is a max(a, b) macro in <linux/kernel.h>.
> 

Quite true, but it unfortunately fails when the symbol is
used in array size declaration as in below:

        struct kvaser_usb {
                ...
                struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
                ...
        }

        include/linux/kernel.h:713:19: error: braced-group within
	expression allowed only inside a function
        #define max(x, y) ({    \
                   ^

> > +
> > +/*
> > + * Kvaser USB CAN dongles are divided into two major families:
> > + * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo'
> > + * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios'
> > + */
> > +enum kvaser_usb_family {
> > +	KVASER_LEAF,
> > +	KVASER_USBCAN,
> > +};
> > +
> >  #define MAX_TX_URBS			16
> >  #define MAX_RX_URBS			4
> >  #define START_TIMEOUT			1000 /* msecs */
> > @@ -29,9 +44,12 @@
> >  #define USB_RECV_TIMEOUT		1000 /* msecs */
> >  #define RX_BUFFER_SIZE			3072
> >  #define CAN_USB_CLOCK			8000000
> > -#define MAX_NET_DEVICES			3
> > +#define LEAF_MAX_NET_DEVICES		3
> > +#define USBCAN_MAX_NET_DEVICES		2
> > +#define MAX_NET_DEVICES			MAX(LEAF_MAX_NET_DEVICES, \
> > +					    USBCAN_MAX_NET_DEVICES)
> >  
> > -/* Kvaser USB devices */
> > +/* Leaf USB devices */
> >  #define KVASER_VENDOR_ID		0x0bfd
> >  #define USB_LEAF_DEVEL_PRODUCT_ID	10
> >  #define USB_LEAF_LITE_PRODUCT_ID	11
> > @@ -55,6 +73,16 @@
> >  #define USB_CAN_R_PRODUCT_ID		39
> >  #define USB_LEAF_LITE_V2_PRODUCT_ID	288
> >  #define USB_MINI_PCIE_HS_PRODUCT_ID	289
> > +#define LEAF_PRODUCT_ID(id)		(id >= USB_LEAF_DEVEL_PRODUCT_ID && \
> > +					 id <= USB_MINI_PCIE_HS_PRODUCT_ID)
> > +
> > +/* USBCANII devices */
> > +#define USB_USBCAN_REVB_PRODUCT_ID	2
> > +#define USB_VCI2_PRODUCT_ID		3
> > +#define USB_USBCAN2_PRODUCT_ID		4
> > +#define USB_MEMORATOR_PRODUCT_ID	5
> > +#define USBCAN_PRODUCT_ID(id)		(id >= USB_USBCAN_REVB_PRODUCT_ID && \
> > +					 id <= USB_MEMORATOR_PRODUCT_ID)
> >  
> >  /* USB devices features */
> >  #define KVASER_HAS_SILENT_MODE		BIT(0)
> > @@ -73,7 +101,7 @@
> >  #define MSG_FLAG_TX_ACK			BIT(6)
> >  #define MSG_FLAG_TX_REQUEST		BIT(7)
> >  
> > -/* Can states */
> > +/* Can states (M16C CxSTRH register) */
> >  #define M16C_STATE_BUS_RESET		BIT(0)
> >  #define M16C_STATE_BUS_ERROR		BIT(4)
> >  #define M16C_STATE_BUS_PASSIVE		BIT(5)
> > @@ -98,7 +126,13 @@
> >  #define CMD_START_CHIP_REPLY		27
> >  #define CMD_STOP_CHIP			28
> >  #define CMD_STOP_CHIP_REPLY		29
> > -#define CMD_GET_CARD_INFO2		32
> > +#define CMD_READ_CLOCK			30
> > +#define CMD_READ_CLOCK_REPLY		31
> > +
> > +#define LEAF_CMD_GET_CARD_INFO2		32
> > +#define USBCAN_CMD_RESET_CLOCK		32
> > +#define USBCAN_CMD_CLOCK_OVERFLOW_EVENT	33
> > +
> >  #define CMD_GET_CARD_INFO		34
> >  #define CMD_GET_CARD_INFO_REPLY		35
> >  #define CMD_GET_SOFTWARE_INFO		38
> > @@ -108,8 +142,9 @@
> >  #define CMD_RESET_ERROR_COUNTER		49
> >  #define CMD_TX_ACKNOWLEDGE		50
> >  #define CMD_CAN_ERROR_EVENT		51
> > -#define CMD_USB_THROTTLE		77
> > -#define CMD_LOG_MESSAGE			106
> > +
> > +#define LEAF_CMD_USB_THROTTLE		77
> > +#define LEAF_CMD_LOG_MESSAGE		106
> >  
> >  /* error factors */
> >  #define M16C_EF_ACKE			BIT(0)
> > @@ -121,6 +156,13 @@
> >  #define M16C_EF_RCVE			BIT(6)
> >  #define M16C_EF_TRE			BIT(7)
> >  
> > +/* Only Leaf-based devices can report M16C error factors,
> > + * thus define our own error status flags for USBCAN */
> > +#define USBCAN_ERROR_STATE_NONE		0
> > +#define USBCAN_ERROR_STATE_TX_ERROR	BIT(0)
> > +#define USBCAN_ERROR_STATE_RX_ERROR	BIT(1)
> > +#define USBCAN_ERROR_STATE_BUSERROR	BIT(2)
> > +
> >  /* bittiming parameters */
> >  #define KVASER_USB_TSEG1_MIN		1
> >  #define KVASER_USB_TSEG1_MAX		16
> > @@ -137,7 +179,7 @@
> >  #define KVASER_CTRL_MODE_SELFRECEPTION	3
> >  #define KVASER_CTRL_MODE_OFF		4
> >  
> > -/* log message */
> > +/* Extended CAN identifier flag */
> >  #define KVASER_EXTENDED_FRAME		BIT(31)
> >  
> >  struct kvaser_msg_simple {
> > @@ -148,30 +190,55 @@ struct kvaser_msg_simple {
> >  struct kvaser_msg_cardinfo {
> >  	u8 tid;
> >  	u8 nchannels;
> > -	__le32 serial_number;
> > -	__le32 padding;
> > +	union {
> > +		struct {
> > +			__le32 serial_number;
> > +			__le32 padding;
> > +		} __packed leaf0;
> > +		struct {
> > +			__le32 serial_number_low;
> > +			__le32 serial_number_high;
> > +		} __packed usbcan0;
> > +	} __packed;
> >  	__le32 clock_resolution;
> >  	__le32 mfgdate;
> >  	u8 ean[8];
> >  	u8 hw_revision;
> > -	u8 usb_hs_mode;
> > -	__le16 padding2;
> > +	union {
> > +		struct {
> > +			u8 usb_hs_mode;
> > +		} __packed leaf1;
> > +		struct {
> > +			u8 padding;
> > +		} __packed usbcan1;
> > +	} __packed;
> > +	__le16 padding;
> >  } __packed;
> >  
> >  struct kvaser_msg_cardinfo2 {
> >  	u8 tid;
> > -	u8 channel;
> > +	u8 reserved;
> >  	u8 pcb_id[24];
> >  	__le32 oem_unlock_code;
> >  } __packed;
> >  
> > -struct kvaser_msg_softinfo {
> > +struct leaf_msg_softinfo {
> >  	u8 tid;
> > -	u8 channel;
> > +	u8 padding0;
> >  	__le32 sw_options;
> >  	__le32 fw_version;
> >  	__le16 max_outstanding_tx;
> > -	__le16 padding[9];
> > +	__le16 padding1[9];
> > +} __packed;
> > +
> > +struct usbcan_msg_softinfo {
> > +	u8 tid;
> > +	u8 fw_name[5];
> > +	__le16 max_outstanding_tx;
> > +	u8 padding[6];
> > +	__le32 fw_version;
> > +	__le16 checksum;
> > +	__le16 sw_options;
> >  } __packed;
> >  
> >  struct kvaser_msg_busparams {
> > @@ -188,36 +255,86 @@ struct kvaser_msg_tx_can {
> >  	u8 channel;
> >  	u8 tid;
> >  	u8 msg[14];
> > -	u8 padding;
> > -	u8 flags;
> > +	union {
> > +		struct {
> > +			u8 padding;
> > +			u8 flags;
> > +		} __packed leaf;
> > +		struct {
> > +			u8 flags;
> > +			u8 padding;
> > +		} __packed usbcan;
> > +	} __packed;
> > +} __packed;
> > +
> > +struct kvaser_msg_rx_can_header {
> > +	u8 channel;
> > +	u8 flag;
> >  } __packed;
> >  
> > -struct kvaser_msg_rx_can {
> > +struct leaf_msg_rx_can {
> >  	u8 channel;
> >  	u8 flag;
> > +
> >  	__le16 time[3];
> >  	u8 msg[14];
> >  } __packed;
> >  
> > -struct kvaser_msg_chip_state_event {
> > +struct usbcan_msg_rx_can {
> > +	u8 channel;
> > +	u8 flag;
> > +
> > +	u8 msg[14];
> > +	__le16 time;
> > +} __packed;
> > +
> > +struct leaf_msg_chip_state_event {
> >  	u8 tid;
> >  	u8 channel;
> > +
> >  	__le16 time[3];
> >  	u8 tx_errors_count;
> >  	u8 rx_errors_count;
> > +
> >  	u8 status;
> >  	u8 padding[3];
> >  } __packed;
> >  
> > -struct kvaser_msg_tx_acknowledge {
> > +struct usbcan_msg_chip_state_event {
> > +	u8 tid;
> > +	u8 channel;
> > +
> > +	u8 tx_errors_count;
> > +	u8 rx_errors_count;
> > +	__le16 time;
> > +
> > +	u8 status;
> > +	u8 padding[3];
> > +} __packed;
> > +
> > +struct kvaser_msg_tx_acknowledge_header {
> > +	u8 channel;
> > +	u8 tid;
> > +};
> > +
> > +struct leaf_msg_tx_acknowledge {
> >  	u8 channel;
> >  	u8 tid;
> > +
> >  	__le16 time[3];
> >  	u8 flags;
> >  	u8 time_offset;
> >  } __packed;
> >  
> > -struct kvaser_msg_error_event {
> > +struct usbcan_msg_tx_acknowledge {
> > +	u8 channel;
> > +	u8 tid;
> > +
> > +	__le16 time;
> > +	__le16 padding;
> > +} __packed;
> > +
> > +struct leaf_msg_error_event {
> >  	u8 tid;
> >  	u8 flags;
> >  	__le16 time[3];
> > @@ -229,6 +346,18 @@ struct kvaser_msg_error_event {
> >  	u8 error_factor;
> >  } __packed;
> >  
> > +struct usbcan_msg_error_event {
> > +	u8 tid;
> > +	u8 padding;
> > +	u8 tx_errors_count_ch0;
> > +	u8 rx_errors_count_ch0;
> > +	u8 tx_errors_count_ch1;
> > +	u8 rx_errors_count_ch1;
> > +	u8 status_ch0;
> > +	u8 status_ch1;
> > +	__le16 time;
> > +} __packed;
> > +
> >  struct kvaser_msg_ctrl_mode {
> >  	u8 tid;
> >  	u8 channel;
> > @@ -243,7 +372,7 @@ struct kvaser_msg_flush_queue {
> >  	u8 padding[3];
> >  } __packed;
> >  
> > -struct kvaser_msg_log_message {
> > +struct leaf_msg_log_message {
> >  	u8 channel;
> >  	u8 flags;
> >  	__le16 time[3];
> > @@ -260,19 +389,49 @@ struct kvaser_msg {
> >  		struct kvaser_msg_simple simple;
> >  		struct kvaser_msg_cardinfo cardinfo;
> >  		struct kvaser_msg_cardinfo2 cardinfo2;
> > -		struct kvaser_msg_softinfo softinfo;
> >  		struct kvaser_msg_busparams busparams;
> > +
> > +		struct kvaser_msg_rx_can_header rx_can_header;
> > +		struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header;
> > +
> > +		union {
> > +			struct leaf_msg_softinfo softinfo;
> > +			struct leaf_msg_rx_can rx_can;
> > +			struct leaf_msg_chip_state_event chip_state_event;
> > +			struct leaf_msg_tx_acknowledge tx_acknowledge;
> > +			struct leaf_msg_error_event error_event;
> > +			struct leaf_msg_log_message log_message;
> > +		} __packed leaf;
> > +
> > +		union {
> > +			struct usbcan_msg_softinfo softinfo;
> > +			struct usbcan_msg_rx_can rx_can;
> > +			struct usbcan_msg_chip_state_event chip_state_event;
> > +			struct usbcan_msg_tx_acknowledge tx_acknowledge;
> > +			struct usbcan_msg_error_event error_event;
> > +		} __packed usbcan;
> > +
> >  		struct kvaser_msg_tx_can tx_can;
> > -		struct kvaser_msg_rx_can rx_can;
> > -		struct kvaser_msg_chip_state_event chip_state_event;
> > -		struct kvaser_msg_tx_acknowledge tx_acknowledge;
> > -		struct kvaser_msg_error_event error_event;
> >  		struct kvaser_msg_ctrl_mode ctrl_mode;
> >  		struct kvaser_msg_flush_queue flush_queue;
> > -		struct kvaser_msg_log_message log_message;
> >  	} u;
> >  } __packed;
> >  
> > +/* Leaf/USBCAN-agnostic summary of an error event.
> > + * No M16C error factors for USBCAN-based devices. */
> > +struct kvaser_error_summary {
> > +	u8 channel, status, txerr, rxerr;
> > +	union {
> > +		struct {
> > +			u8 error_factor;
> > +		} leaf;
> > +		struct {
> > +			u8 other_ch_status;
> > +			u8 error_state;
> > +		} usbcan;
> > +	};
> > +};
> > +
> >  struct kvaser_usb_tx_urb_context {
> >  	struct kvaser_usb_net_priv *priv;
> >  	u32 echo_index;
> > @@ -288,6 +447,8 @@ struct kvaser_usb {
> >  
> >  	u32 fw_version;
> >  	unsigned int nchannels;
> > +	enum kvaser_usb_family family;
> > +	unsigned int max_channels;
> >  
> >  	bool rxinitdone;
> >  	void *rxbuf[MAX_RX_URBS];
> > @@ -311,6 +472,7 @@ struct kvaser_usb_net_priv {
> >  };
> >  
> >  static const struct usb_device_id kvaser_usb_table[] = {
> > +	/* Leaf family IDs */
> >  	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
> >  	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
> >  	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
> > @@ -360,6 +522,17 @@ static const struct usb_device_id kvaser_usb_table[] = {
> >  		.driver_info = KVASER_HAS_TXRX_ERRORS },
> >  	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
> >  	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
> > +
> > +	/* USBCANII family IDs */
> > +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
> > +		.driver_info = KVASER_HAS_TXRX_ERRORS },
> > +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
> > +		.driver_info = KVASER_HAS_TXRX_ERRORS },
> > +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
> > +		.driver_info = KVASER_HAS_TXRX_ERRORS },
> > +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
> > +		.driver_info = KVASER_HAS_TXRX_ERRORS },
> > +
> >  	{ }
> >  };
> >  MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
> > @@ -463,7 +636,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
> >  	if (err)
> >  		return err;
> >  
> > -	dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
> > +	switch (dev->family) {
> > +	case KVASER_LEAF:
> > +		dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
> > +		break;
> > +	case KVASER_USBCAN:
> > +		dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
> > +		break;
> > +	default:
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid device family (%d)\n", dev->family);
> > +		return -EINVAL;
> > +	}
> >  
> >  	return 0;
> >  }
> > @@ -482,7 +666,7 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
> >  		return err;
> >  
> >  	dev->nchannels = msg.u.cardinfo.nchannels;
> > -	if (dev->nchannels > MAX_NET_DEVICES)
> > +	if (dev->nchannels > dev->max_channels)
> >  		return -EINVAL;
> 
> IMHO, you can keep MAX_NET_DEVICES here.
> 

The UsbcanII firmware hardcodes a maximum of 2 channels in
its protocol. This is unfortunately due to its inability to
tell whether an error event is from CAN channel 0 or ch 1,
and also due to its error_event format:

struct usbcan_msg_error_event {
	u8 tid;
	u8 padding;
	u8 tx_errors_count_ch0;
	u8 rx_errors_count_ch0;
	u8 tx_errors_count_ch1;
	u8 rx_errors_count_ch1;
	u8 status_ch0;
	u8 status_ch1;
	__le16 time;
} __packed;

But since we have MAX_NET_DEVICES = 3, and given the above,
if the UsbcanII firmware reported to us having more than 2
channels, then it's:

a) most probably a memory corruption bug either in the firmware
   or in the driver
b) an updated device/firmware we cannot support yet, since
   we cannot arbitrate the origin of error events quite correctly
   (especially in the case of CAN_ERR_BUSERROR, where the error
   counters stays the same and we have to resort to other hacks.
   Kindly check usbcan_report_error_if_applicable().)

So allowing more than 2 channels given the current set of
affairs will really induce correctness problems :-(

> >  
> >  	return 0;
> > @@ -496,8 +680,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
> >  	struct kvaser_usb_net_priv *priv;
> >  	struct sk_buff *skb;
> >  	struct can_frame *cf;
> > -	u8 channel = msg->u.tx_acknowledge.channel;
> > -	u8 tid = msg->u.tx_acknowledge.tid;
> > +	u8 channel, tid;
> > +
> > +	channel = msg->u.tx_acknowledge_header.channel;
> > +	tid = msg->u.tx_acknowledge_header.tid;
> >  
> >  	if (channel >= dev->nchannels) {
> >  		dev_err(dev->udev->dev.parent,
> > @@ -615,37 +801,83 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
> >  		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> >  }
> >  
> > -static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> > -				const struct kvaser_msg *msg)
> > +static void kvaser_report_error_event(const struct kvaser_usb *dev,
> > +				      struct kvaser_error_summary *es);
> > +
> > +/*
> > + * Report error to userspace iff the controller's errors counter has
> > + * increased, or we're the only channel seeing the bus error state.
> > + *
> > + * As reported by USBCAN sheets, "the CAN controller has difficulties
> > + * to tell whether an error frame arrived on channel 1 or on channel 2."
> > + * Thus, error counters are compared with their earlier values to
> > + * determine which channel was responsible for the error event.
> > + */
> > +static void usbcan_report_error_if_applicable(const struct kvaser_usb *dev,
> > +					      struct kvaser_error_summary *es)
> >  {
> > -	struct can_frame *cf;
> > -	struct sk_buff *skb;
> > -	struct net_device_stats *stats;
> >  	struct kvaser_usb_net_priv *priv;
> > -	unsigned int new_state;
> > -	u8 channel, status, txerr, rxerr, error_factor;
> > +	int old_tx_err_count, old_rx_err_count, channel, report_error;
> > +
> > +	channel = es->channel;
> > +	if (channel >= dev->nchannels) {
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid channel number (%d)\n", channel);
> > +		return;
> > +	}
> > +
> > +	priv = dev->nets[channel];
> > +	old_tx_err_count = priv->bec.txerr;
> > +	old_rx_err_count = priv->bec.rxerr;
> > +
> > +	report_error = 0;
> > +	if (es->txerr > old_tx_err_count) {
> > +		es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR;
> > +		report_error = 1;
> > +	}
> > +	if (es->rxerr > old_rx_err_count) {
> > +		es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR;
> > +		report_error = 1;
> > +	}
> > +	if ((es->status & M16C_STATE_BUS_ERROR) &&
> > +	    !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) {
> > +		es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR;
> > +		report_error = 1;
> > +	}
> > +
> > +	if (report_error)
> > +		kvaser_report_error_event(dev, es);
> > +}
> > +
> > +/*
> > + * Extract error summary from a Leaf-based device error message
> > + */
> > +static void leaf_extract_error_from_msg(const struct kvaser_usb *dev,
> > +					const struct kvaser_msg *msg)
> > +{
> > +	struct kvaser_error_summary es = { 0, };
> >  
> >  	switch (msg->id) {
> >  	case CMD_CAN_ERROR_EVENT:
> > -		channel = msg->u.error_event.channel;
> > -		status =  msg->u.error_event.status;
> > -		txerr = msg->u.error_event.tx_errors_count;
> > -		rxerr = msg->u.error_event.rx_errors_count;
> > -		error_factor = msg->u.error_event.error_factor;
> > +		es.channel = msg->u.leaf.error_event.channel;
> > +		es.status =  msg->u.leaf.error_event.status;
> > +		es.txerr = msg->u.leaf.error_event.tx_errors_count;
> > +		es.rxerr = msg->u.leaf.error_event.rx_errors_count;
> > +		es.leaf.error_factor = msg->u.leaf.error_event.error_factor;
> >  		break;
> > -	case CMD_LOG_MESSAGE:
> > -		channel = msg->u.log_message.channel;
> > -		status = msg->u.log_message.data[0];
> > -		txerr = msg->u.log_message.data[2];
> > -		rxerr = msg->u.log_message.data[3];
> > -		error_factor = msg->u.log_message.data[1];
> > +	case LEAF_CMD_LOG_MESSAGE:
> > +		es.channel = msg->u.leaf.log_message.channel;
> > +		es.status = msg->u.leaf.log_message.data[0];
> > +		es.txerr = msg->u.leaf.log_message.data[2];
> > +		es.rxerr = msg->u.leaf.log_message.data[3];
> > +		es.leaf.error_factor = msg->u.leaf.log_message.data[1];
> >  		break;
> >  	case CMD_CHIP_STATE_EVENT:
> > -		channel = msg->u.chip_state_event.channel;
> > -		status =  msg->u.chip_state_event.status;
> > -		txerr = msg->u.chip_state_event.tx_errors_count;
> > -		rxerr = msg->u.chip_state_event.rx_errors_count;
> > -		error_factor = 0;
> > +		es.channel = msg->u.leaf.chip_state_event.channel;
> > +		es.status =  msg->u.leaf.chip_state_event.status;
> > +		es.txerr = msg->u.leaf.chip_state_event.tx_errors_count;
> > +		es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count;
> > +		es.leaf.error_factor = 0;
> >  		break;
> >  	default:
> >  		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
> > @@ -653,16 +885,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  		return;
> >  	}
> >  
> > -	if (channel >= dev->nchannels) {
> > +	kvaser_report_error_event(dev, &es);
> > +}
> > +
> > +/*
> > + * Extract summary from a USBCANII-based device error message.
> > + */
> > +static void usbcan_extract_error_from_msg(const struct kvaser_usb *dev,
> > +					const struct kvaser_msg *msg)
> > +{
> > +	struct kvaser_error_summary es = { 0, };
> > +
> > +	switch (msg->id) {
> > +
> > +	/* Sometimes errors are sent as unsolicited chip state events */
> > +	case CMD_CHIP_STATE_EVENT:
> > +		es.channel = msg->u.usbcan.chip_state_event.channel;
> > +		es.status =  msg->u.usbcan.chip_state_event.status;
> > +		es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count;
> > +		es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count;
> > +		usbcan_report_error_if_applicable(dev, &es);
> > +		break;
> > +
> > +	case CMD_CAN_ERROR_EVENT:
> > +		es.channel = 0;
> > +		es.status = msg->u.usbcan.error_event.status_ch0;
> > +		es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0;
> > +		es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0;
> > +		es.usbcan.other_ch_status =
> > +			msg->u.usbcan.error_event.status_ch1;
> > +		usbcan_report_error_if_applicable(dev, &es);
> > +
> > +		/* For error events, the USBCAN firmware does not support
> > +		 * more than 2 channels: ch0, and ch1. */
> > +		if (dev->nchannels > 1) {
> > +			es.channel = 1;
> > +			es.status = msg->u.usbcan.error_event.status_ch1;
> > +			es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1;
> > +			es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1;
> > +			es.usbcan.other_ch_status =
> > +				msg->u.usbcan.error_event.status_ch0;
> > +			usbcan_report_error_if_applicable(dev, &es);
> > +		}
> > +		break;
> > +
> > +	default:
> > +		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
> > +			msg->id);
> > +	}
> > +}
> > +
> > +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> > +				const struct kvaser_msg *msg)
> > +{
> > +	switch (dev->family) {
> > +	case KVASER_LEAF:
> > +		leaf_extract_error_from_msg(dev, msg);
> > +		break;
> > +	case KVASER_USBCAN:
> > +		usbcan_extract_error_from_msg(dev, msg);
> > +		break;
> > +	default:
> >  		dev_err(dev->udev->dev.parent,
> > -			"Invalid channel number (%d)\n", channel);
> > +			"Invalid device family (%d)\n", dev->family);
> >  		return;
> >  	}
> > +}
> >  
> > -	priv = dev->nets[channel];
> > +static void kvaser_report_error_event(const struct kvaser_usb *dev,
> > +				      struct kvaser_error_summary *es)
> > +{
> > +	struct can_frame *cf;
> > +	struct sk_buff *skb;
> > +	struct net_device_stats *stats;
> > +	struct kvaser_usb_net_priv *priv;
> > +	unsigned int new_state;
> > +
> > +	if (es->channel >= dev->nchannels) {
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid channel number (%d)\n", es->channel);
> > +		return;
> > +	}
> > +
> > +	priv = dev->nets[es->channel];
> >  	stats = &priv->netdev->stats;
> >  
> > -	if (status & M16C_STATE_BUS_RESET) {
> > +	if (es->status & M16C_STATE_BUS_RESET) {
> >  		kvaser_usb_unlink_tx_urbs(priv);
> >  		return;
> >  	}
> > @@ -675,9 +983,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  
> >  	new_state = priv->can.state;
> >  
> > -	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
> > +	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
> >  
> > -	if (status & M16C_STATE_BUS_OFF) {
> > +	if (es->status & M16C_STATE_BUS_OFF) {
> >  		cf->can_id |= CAN_ERR_BUSOFF;
> >  
> >  		priv->can.can_stats.bus_off++;
> > @@ -687,12 +995,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  		netif_carrier_off(priv->netdev);
> >  
> >  		new_state = CAN_STATE_BUS_OFF;
> > -	} else if (status & M16C_STATE_BUS_PASSIVE) {
> > +	} else if (es->status & M16C_STATE_BUS_PASSIVE) {
> >  		if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
> >  			cf->can_id |= CAN_ERR_CRTL;
> >  
> > -			if (txerr || rxerr)
> > -				cf->data[1] = (txerr > rxerr)
> > +			if (es->txerr || es->rxerr)
> > +				cf->data[1] = (es->txerr > es->rxerr)
> >  						? CAN_ERR_CRTL_TX_PASSIVE
> >  						: CAN_ERR_CRTL_RX_PASSIVE;
> >  			else
> > @@ -703,13 +1011,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  		}
> >  
> >  		new_state = CAN_STATE_ERROR_PASSIVE;
> > -	}
> > -
> > -	if (status == M16C_STATE_BUS_ERROR) {
> > +	} else if (es->status & M16C_STATE_BUS_ERROR) {
> >  		if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
> > -		    ((txerr >= 96) || (rxerr >= 96))) {
> > +		    ((es->txerr >= 96) || (es->rxerr >= 96))) {
> >  			cf->can_id |= CAN_ERR_CRTL;
> > -			cf->data[1] = (txerr > rxerr)
> > +			cf->data[1] = (es->txerr > es->rxerr)
> >  					? CAN_ERR_CRTL_TX_WARNING
> >  					: CAN_ERR_CRTL_RX_WARNING;
> >  
> > @@ -723,7 +1029,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  		}
> >  	}
> >  
> > -	if (!status) {
> > +	if (!es->status) {
> >  		cf->can_id |= CAN_ERR_PROT;
> >  		cf->data[2] = CAN_ERR_PROT_ACTIVE;
> >  
> > @@ -739,34 +1045,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  		priv->can.can_stats.restarts++;
> >  	}
> >  
> > -	if (error_factor) {
> > -		priv->can.can_stats.bus_error++;
> > -		stats->rx_errors++;
> > -
> > -		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
> > -
> > -		if (error_factor & M16C_EF_ACKE)
> > -			cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
> > -		if (error_factor & M16C_EF_CRCE)
> > -			cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> > -					CAN_ERR_PROT_LOC_CRC_DEL);
> > -		if (error_factor & M16C_EF_FORME)
> > -			cf->data[2] |= CAN_ERR_PROT_FORM;
> > -		if (error_factor & M16C_EF_STFE)
> > -			cf->data[2] |= CAN_ERR_PROT_STUFF;
> > -		if (error_factor & M16C_EF_BITE0)
> > -			cf->data[2] |= CAN_ERR_PROT_BIT0;
> > -		if (error_factor & M16C_EF_BITE1)
> > -			cf->data[2] |= CAN_ERR_PROT_BIT1;
> > -		if (error_factor & M16C_EF_TRE)
> > -			cf->data[2] |= CAN_ERR_PROT_TX;
> > +	switch (dev->family) {
> > +	case KVASER_LEAF:
> > +		if (es->leaf.error_factor) {
> > +			priv->can.can_stats.bus_error++;
> > +			stats->rx_errors++;
> > +
> > +			cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
> > +
> > +			if (es->leaf.error_factor & M16C_EF_ACKE)
> > +				cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
> > +			if (es->leaf.error_factor & M16C_EF_CRCE)
> > +				cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> > +						CAN_ERR_PROT_LOC_CRC_DEL);
> > +			if (es->leaf.error_factor & M16C_EF_FORME)
> > +				cf->data[2] |= CAN_ERR_PROT_FORM;
> > +			if (es->leaf.error_factor & M16C_EF_STFE)
> > +				cf->data[2] |= CAN_ERR_PROT_STUFF;
> > +			if (es->leaf.error_factor & M16C_EF_BITE0)
> > +				cf->data[2] |= CAN_ERR_PROT_BIT0;
> > +			if (es->leaf.error_factor & M16C_EF_BITE1)
> > +				cf->data[2] |= CAN_ERR_PROT_BIT1;
> > +			if (es->leaf.error_factor & M16C_EF_TRE)
> > +				cf->data[2] |= CAN_ERR_PROT_TX;
> > +		}
> > +		break;
> > +	case KVASER_USBCAN:
> > +		if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
> > +			stats->tx_errors++;
> > +		if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
> > +			stats->rx_errors++;
> > +		if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
> > +			priv->can.can_stats.bus_error++;
> > +			cf->can_id |= CAN_ERR_BUSERROR;
> > +		}
> > +		break;
> > +	default:
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid device family (%d)\n", dev->family);
> > +		goto err;
> >  	}
> >  
> > -	cf->data[6] = txerr;
> > -	cf->data[7] = rxerr;
> > +	cf->data[6] = es->txerr;
> > +	cf->data[7] = es->rxerr;
> >  
> > -	priv->bec.txerr = txerr;
> > -	priv->bec.rxerr = rxerr;
> > +	priv->bec.txerr = es->txerr;
> > +	priv->bec.rxerr = es->rxerr;
> >  
> >  	priv->can.state = new_state;
> >  
> > @@ -774,6 +1098,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  
> >  	stats->rx_packets++;
> >  	stats->rx_bytes += cf->can_dlc;
> > +
> > +	return;
> > +
> > +err:
> > +	dev_kfree_skb(skb);
> >  }
> >  
> >  static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
> > @@ -783,16 +1112,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
> >  	struct sk_buff *skb;
> >  	struct net_device_stats *stats = &priv->netdev->stats;
> >  
> > -	if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
> > +	if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
> >  					 MSG_FLAG_NERR)) {
> >  		netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
> > -			   msg->u.rx_can.flag);
> > +			   msg->u.rx_can_header.flag);
> >  
> >  		stats->rx_errors++;
> >  		return;
> >  	}
> >  
> > -	if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
> > +	if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) {
> >  		skb = alloc_can_err_skb(priv->netdev, &cf);
> >  		if (!skb) {
> >  			stats->rx_dropped++;
> > @@ -819,7 +1148,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
> >  	struct can_frame *cf;
> >  	struct sk_buff *skb;
> >  	struct net_device_stats *stats;
> > -	u8 channel = msg->u.rx_can.channel;
> > +	u8 channel = msg->u.rx_can_header.channel;
> > +	const u8 *rx_msg;
> >  
> >  	if (channel >= dev->nchannels) {
> >  		dev_err(dev->udev->dev.parent,
> > @@ -830,19 +1160,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
> >  	priv = dev->nets[channel];
> >  	stats = &priv->netdev->stats;
> >  
> > -	if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) &&
> > -	    (msg->id == CMD_LOG_MESSAGE)) {
> > +	if ((msg->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
> > +	    (dev->family == KVASER_LEAF && msg->id == LEAF_CMD_LOG_MESSAGE)) {
> >  		kvaser_usb_rx_error(dev, msg);
> >  		return;
> > -	} else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
> > -					 MSG_FLAG_NERR |
> > -					 MSG_FLAG_OVERRUN)) {
> > +	} else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
> > +						MSG_FLAG_NERR |
> > +						MSG_FLAG_OVERRUN)) {
> >  		kvaser_usb_rx_can_err(priv, msg);
> >  		return;
> > -	} else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
> > +	} else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) {
> >  		netdev_warn(priv->netdev,
> >  			    "Unhandled frame (flags: 0x%02x)",
> > -			    msg->u.rx_can.flag);
> > +			    msg->u.rx_can_header.flag);
> > +		return;
> > +	}
> > +
> > +	switch (dev->family) {
> > +	case KVASER_LEAF:
> > +		rx_msg = msg->u.leaf.rx_can.msg;
> > +		break;
> > +	case KVASER_USBCAN:
> > +		rx_msg = msg->u.usbcan.rx_can.msg;
> > +		break;
> > +	default:
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid device family (%d)\n", dev->family);
> >  		return;
> >  	}
> >  
> > @@ -852,38 +1195,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
> >  		return;
> >  	}
> >  
> > -	if (msg->id == CMD_LOG_MESSAGE) {
> > -		cf->can_id = le32_to_cpu(msg->u.log_message.id);
> > +	if (dev->family == KVASER_LEAF && msg->id == LEAF_CMD_LOG_MESSAGE) {
> > +		cf->can_id = le32_to_cpu(msg->u.leaf.log_message.id);
> >  		if (cf->can_id & KVASER_EXTENDED_FRAME)
> >  			cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
> >  		else
> >  			cf->can_id &= CAN_SFF_MASK;
> >  
> > -		cf->can_dlc = get_can_dlc(msg->u.log_message.dlc);
> > +		cf->can_dlc = get_can_dlc(msg->u.leaf.log_message.dlc);
> >  
> > -		if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME)
> > +		if (msg->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME)
> >  			cf->can_id |= CAN_RTR_FLAG;
> >  		else
> > -			memcpy(cf->data, &msg->u.log_message.data,
> > +			memcpy(cf->data, &msg->u.leaf.log_message.data,
> >  			       cf->can_dlc);
> >  	} else {
> > -		cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
> > -			     (msg->u.rx_can.msg[1] & 0x3f);
> > +		cf->can_id = ((rx_msg[0] & 0x1f) << 6) | (rx_msg[1] & 0x3f);
> >  
> >  		if (msg->id == CMD_RX_EXT_MESSAGE) {
> >  			cf->can_id <<= 18;
> > -			cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
> > -				      ((msg->u.rx_can.msg[3] & 0xff) << 6) |
> > -				      (msg->u.rx_can.msg[4] & 0x3f);
> > +			cf->can_id |= ((rx_msg[2] & 0x0f) << 14) |
> > +				      ((rx_msg[3] & 0xff) << 6) |
> > +				      (rx_msg[4] & 0x3f);
> >  			cf->can_id |= CAN_EFF_FLAG;
> >  		}
> >  
> > -		cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
> > +		cf->can_dlc = get_can_dlc(rx_msg[5]);
> >  
> > -		if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
> > +		if (msg->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME)
> >  			cf->can_id |= CAN_RTR_FLAG;
> >  		else
> > -			memcpy(cf->data, &msg->u.rx_can.msg[6],
> > +			memcpy(cf->data, &rx_msg[6],
> >  			       cf->can_dlc);
> >  	}
> >  
> > @@ -947,7 +1289,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
> >  
> >  	case CMD_RX_STD_MESSAGE:
> >  	case CMD_RX_EXT_MESSAGE:
> > -	case CMD_LOG_MESSAGE:
> > +		kvaser_usb_rx_can_msg(dev, msg);
> > +		break;
> > +
> > +	case LEAF_CMD_LOG_MESSAGE:
> > +		if (dev->family != KVASER_LEAF)
> > +			goto warn;
> >  		kvaser_usb_rx_can_msg(dev, msg);
> >  		break;
> >  
> > @@ -960,8 +1307,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
> >  		kvaser_usb_tx_acknowledge(dev, msg);
> >  		break;
> >  
> > +	/* Ignored messages */
> > +	case USBCAN_CMD_CLOCK_OVERFLOW_EVENT:
> > +		if (dev->family != KVASER_USBCAN)
> > +			goto warn;
> > +		break;
> > +
> >  	default:
> > -		dev_warn(dev->udev->dev.parent,
> > +warn:		dev_warn(dev->udev->dev.parent,
> >  			 "Unhandled message (%d)\n", msg->id);
> >  		break;
> >  	}
> > @@ -1181,7 +1534,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
> >  				  dev->rxbuf[i],
> >  				  dev->rxbuf_dma[i]);
> >  
> > -	for (i = 0; i < MAX_NET_DEVICES; i++) {
> > +	for (i = 0; i < dev->max_channels; i++) {
> 
> here too... or replace it by nchannels.
> 

Yes, indeed. nchannels is the correct choice here, especially since
kvaser_usb_init_one() is called "dev->nchannels" times too.

> >  		struct kvaser_usb_net_priv *priv = dev->nets[i];
> >  
> >  		if (priv)
> > @@ -1286,6 +1639,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> >  	struct kvaser_msg *msg;
> >  	int i, err;
> >  	int ret = NETDEV_TX_OK;
> > +	uint8_t *msg_tx_can_flags;
> >  	bool kfree_skb_on_error = true;
> >  
> >  	if (can_dropped_invalid_skb(netdev, skb))
> > @@ -1306,9 +1660,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> >  
> >  	msg = buf;
> >  	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
> > -	msg->u.tx_can.flags = 0;
> >  	msg->u.tx_can.channel = priv->channel;
> >  
> > +	switch (dev->family) {
> > +	case KVASER_LEAF:
> > +		msg_tx_can_flags = &msg->u.tx_can.leaf.flags;
> > +		break;
> > +	case KVASER_USBCAN:
> > +		msg_tx_can_flags = &msg->u.tx_can.usbcan.flags;
> > +		break;
> > +	default:
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid device family (%d)\n", dev->family);
> > +		goto releasebuf;
> > +	}
> > +
> > +	*msg_tx_can_flags = 0;
> > +
> >  	if (cf->can_id & CAN_EFF_FLAG) {
> >  		msg->id = CMD_TX_EXT_MESSAGE;
> >  		msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
> > @@ -1326,7 +1694,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> >  	memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
> >  
> >  	if (cf->can_id & CAN_RTR_FLAG)
> > -		msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
> > +		*msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
> >  
> >  	for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
> >  		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
> > @@ -1596,6 +1964,18 @@ static int kvaser_usb_probe(struct usb_interface *intf,
> >  	if (!dev)
> >  		return -ENOMEM;
> >  
> > +	if (LEAF_PRODUCT_ID(id->idProduct)) {
> > +		dev->family = KVASER_LEAF;
> > +		dev->max_channels = LEAF_MAX_NET_DEVICES;
> > +	} else if (USBCAN_PRODUCT_ID(id->idProduct)) {
> > +		dev->family = KVASER_USBCAN;
> > +		dev->max_channels = USBCAN_MAX_NET_DEVICES;
> > +	} else {
> > +		dev_err(&intf->dev, "Product ID (%d) does not belong to any "
> > +				    "known Kvaser USB family", id->idProduct);
> > +		return -ENODEV;
> > +	}
> > +
> 
> Is it really required to keep max_channels in the kvaser_usb structure?
> If I looked correctly, you use this variable as a replacement for
> MAX_NET_DEVICES in the code and MAX_NET_DEVICES is only used in probe
> and disconnect functions. I think it can even be replaced by nchannels
> in the disconnect path. So I also think that it don't need to be in the
> kvaser_usb structure.
> 

hmmm.. given the current state of error arbitration explained
above, where I cannot accept a dev->nchannels > 2, I guess we
have two options:

a) Remove max_channels, and hardcode the channels count
correctness logic as follows:

        dev->nchannels = msg.u.cardinfo.nchannels;
        if ((dev->family == USBCAN && dev->nchannels > USBCAN_MAX_NET_DEVICES)
            || (dev->family == LEAF && dev->nchannels > LEAF_MAX_NET_DEVICES))
                return -EINVAL

b) Leave max_channels in 'struct kvaser_usb' as is.

I personally prefer the solution at 'b)' but I can do it as
in 'a)' if you prefer :-)

> >  	err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
> >  	if (err) {
> >  		dev_err(&intf->dev, "Cannot get usb endpoint(s)");
> > @@ -1608,7 +1988,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
> >  
> >  	usb_set_intfdata(intf, dev);
> >  
> > -	for (i = 0; i < MAX_NET_DEVICES; i++)
> > +	for (i = 0; i < dev->max_channels; i++)
> >  		kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
> 
> Someone reported me that recent leaf firmwares go in trouble when
> you send a command for a channel that does not exist. Instead of
> max_channels, you can use nchannels here and move the reset command
> in the kvaser_usb_init_one() function.
> I've a patch for this but It is not tested yet. I'll send it next week-end after
> I did some tests.
> 

Great. I guess I can submit a 3-patch series now
(kfree_skb fix + the above fix + driver).

> >  
> >  	err = kvaser_usb_get_software_info(dev);
> 
> Thank you,
> 

Thanks a lot for your review.

P.S. the Gmail mailer you've used messed badly with the patch
code identation; I had to manually restore it back to make the
discussion meaningful for others :-)

Regards,
--
Darwish

^ permalink raw reply	[relevance 87%]

* Re: [PATCH] can: kvaser_usb: Don't free packets when tight on URBs
  @ 2014-12-24 15:52 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2014-12-24 15:52 UTC (permalink / raw)
  To: Olivier Sobrie
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi Olivier,

On Wed, Dec 24, 2014 at 01:31:20PM +0100, Olivier Sobrie wrote:
> Hello Ahmed,
> 
> On Tue, Dec 23, 2014 at 05:46:54PM +0200, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
> > Flooding the Kvaser CAN to USB dongle with multiple reads and
> > writes in high frequency caused seemingly-random panics in the
> > kernel.
> > 
> > On further inspection, it seems the driver erroneously freed the
> > to-be-transmitted packet upon getting tight on URBs and returning
> > NETDEV_TX_BUSY, leading to invalid memory writes and double frees
> > at a later point in time.
> > 
> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> Thank you for the fix.
> 
> > ---
> >  drivers/net/can/usb/kvaser_usb.c | 8 +++++---
> >  1 file changed, 5 insertions(+), 3 deletions(-)
> > 
> >  (Generated over 3.19.0-rc1)
> > 
> > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > index 541fb7a..34c35d8 100644
> > --- a/drivers/net/can/usb/kvaser_usb.c
> > +++ b/drivers/net/can/usb/kvaser_usb.c
> > @@ -1286,6 +1286,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> >  	struct kvaser_msg *msg;
> >  	int i, err;
> >  	int ret = NETDEV_TX_OK;
> > +	bool kfree_skb_on_error = true;
> >  
> >  	if (can_dropped_invalid_skb(netdev, skb))
> >  		return NETDEV_TX_OK;
> > @@ -1336,6 +1337,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> >  
> >  	if (!context) {
> >  		netdev_warn(netdev, "cannot find free context\n");
> > +		kfree_skb_on_error = false;
> 
> Instead of using an extra variable, you can also set skb to NULL here.
> Or maybe better, you can move the dev_kfree_skb() in the two previous
> tests (in the check of variables urb and buf).
> 

Nice, I'll move dev_kfree_skb() to the two earlier tests then.

Thanks,

P.S. mailer and patch identation; had to manually fix them
before replying (but thanks for the quick review, ofc ;-))

> Thank you,
> 
> Olivier
> 
> >  		ret =  NETDEV_TX_BUSY;
> >  		goto releasebuf;
> >  	}
> > @@ -1364,8 +1366,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> >  	if (unlikely(err)) {
> >  		can_free_echo_skb(netdev, context->echo_index);
> >  
> > -		skb = NULL; /* set to NULL to avoid double free in
> > -			     * dev_kfree_skb(skb) */
> > +		kfree_skb_on_error = false;
> >  
> >  		atomic_dec(&priv->active_tx_urbs);
> >  		usb_unanchor_urb(urb);
> > @@ -1389,7 +1390,8 @@ releasebuf:
> >  nobufmem:
> >  	usb_free_urb(urb);
> >  nourbmem:
> > -	dev_kfree_skb(skb);
> > +	if (kfree_skb_on_error)
> > +		dev_kfree_skb(skb);
> >  	return ret;
> >  }
> > 

^ permalink raw reply	[relevance 99%]

* [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-23 15:46 96% [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
  2014-12-23 15:53 36% ` [PATCH] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  @ 2014-12-24 23:56 91% ` Ahmed S. Darwish
  2014-12-24 23:59 84%   ` [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
                       ` (3 subsequent siblings)
  6 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2014-12-24 23:56 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, Greg KH,
	Linux-stable, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Flooding the Kvaser CAN to USB dongle with multiple reads and
writes in high frequency caused seemingly-random panics in the
kernel.

On further inspection, it seems the driver erroneously freed the
to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees
at a later point in time.

Note:

Finding no more URBs/transmit-contexts and returning NETDEV_TX_BUSY
is a driver bug in and out of itself: it means that our start/stop
queue flow control is broken.

This patch only fixes the (buggy) error handling code; the root
cause shall be fixed in a later commit.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

 (Marc, Greg, I believe this should also be added to -stable?)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 541fb7a..6479a2b 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -1294,12 +1294,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	if (!urb) {
 		netdev_err(netdev, "No memory left for URBs\n");
 		stats->tx_dropped++;
-		goto nourbmem;
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
 	}
 
 	buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
 	if (!buf) {
 		stats->tx_dropped++;
+		dev_kfree_skb(skb);
 		goto nobufmem;
 	}
 
@@ -1334,6 +1336,9 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 		}
 	}
 
+	/*
+	 * This should never happen; it implies a flow control bug.
+	 */
 	if (!context) {
 		netdev_warn(netdev, "cannot find free context\n");
 		ret =  NETDEV_TX_BUSY;
@@ -1364,9 +1369,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	if (unlikely(err)) {
 		can_free_echo_skb(netdev, context->echo_index);
 
-		skb = NULL; /* set to NULL to avoid double free in
-			     * dev_kfree_skb(skb) */
-
 		atomic_dec(&priv->active_tx_urbs);
 		usb_unanchor_urb(urb);
 
@@ -1388,8 +1390,6 @@ releasebuf:
 	kfree(buf);
 nobufmem:
 	usb_free_urb(urb);
-nourbmem:
-	dev_kfree_skb(skb);
 	return ret;
 }
 

^ permalink raw reply	[relevance 91%]

* [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close
  2014-12-24 23:56 91% ` [PATCH v2 1/4] " Ahmed S. Darwish
@ 2014-12-24 23:59 84%   ` Ahmed S. Darwish
  2014-12-25  0:02 98%     ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
    1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2014-12-24 23:59 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, Greg KH,
	Linux-stable, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Flooding the Kvaser CAN to USB dongle with multiple reads and
writes in very high frequency (*), closing the CAN channel while
all the transmissions are on (#), opening the device again (@),
then sending a small number of packets would make the driver
enter an almost infinite loop of:

[....]
[15959.853988] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853990] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853991] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853993] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853994] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853995] kvaser_usb 4-3:1.0 can0: cannot find free context
[....]

_dragging the whole system down_ in the process due to the
excessive logging output.

Initially, this has caused random panics in the kernel due to a
buggy error recovery path.  That got fixed in an earlier commit.(%)
This patch aims at solving the root cause. -->

16 tx URBs and contexts are allocated per CAN channel per USB
device. Such URBs are protected by:

a) A simple atomic counter, up to a value of MAX_TX_URBS (16)
b) A flag in each URB context, stating if it's free
c) The fact that ndo_start_xmit calls are themselves protected
   by the networking layers higher above

After grabbing one of the tx URBs, if the driver noticed that all
of them are now taken, it stops the netif transmission queue.
Such queue is worken up again only if an acknowedgment was received
from the firmware on one of our earlier-sent frames.

Meanwhile, upon channel close (#), the driver sends a CMD_STOP_CHIP
to the firmware, effectively closing all further communication.  In
the high traffic case, the atomic counter remains at MAX_TX_URBS,
and all the URB contexts remain marked as active.  While opening
the channel again (@), it cannot send any further frames since no
more free tx URB contexts are available.

Reset all tx URB contexts upon CAN channel close.

(*) 50 parallel instances of `cangen0 -g 0 -ix`
(#) `ifconfig can0 down`
(@) `ifconfig can0 up`
(%) "can: kvaser_usb: Don't free packets when tight on URBs"

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 3 +++
 1 file changed, 3 insertions(+)

 (Marc, Greg, this also should be added to -stable?)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 6479a2b..598e251 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -1246,6 +1246,9 @@ static int kvaser_usb_close(struct net_device *netdev)
 	if (err)
 		netdev_warn(netdev, "Cannot stop device, error %d\n", err);
 
+	/* reset tx contexts */
+	kvaser_usb_unlink_tx_urbs(priv);
+
 	priv->can.state = CAN_STATE_STOPPED;
 	close_candev(priv->netdev);
 

^ permalink raw reply	[relevance 84%]

* [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels
  2014-12-24 23:59 84%   ` [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
@ 2014-12-25  0:02 98%     ` Ahmed S. Darwish
  2014-12-25  0:04 36%       ` [PATCH v2 4/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2014-12-25  0:02 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Greg KH, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

"Someone reported me that recent leaf firmwares go in trouble when
you send a command for a channel that does not exist. Instead ...
you can move the reset command to kvaser_usb_init_one() function."

Suggested-by: Olivier Sobrie <olivier@sobrie.be>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 598e251..2791501 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -1505,6 +1505,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
 	struct kvaser_usb_net_priv *priv;
 	int i, err;
 
+	err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel);
+	if (err)
+		return err;
+
 	netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
 	if (!netdev) {
 		dev_err(&intf->dev, "Cannot alloc candev\n");
@@ -1609,9 +1613,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
 	usb_set_intfdata(intf, dev);
 
-	for (i = 0; i < MAX_NET_DEVICES; i++)
-		kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
-
 	err = kvaser_usb_get_software_info(dev);
 	if (err) {
 		dev_err(&intf->dev,

^ permalink raw reply	[relevance 98%]

* [PATCH v2 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-25  0:02 98%     ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
@ 2014-12-25  0:04 36%       ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2014-12-25  0:04 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Greg KH, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

CAN to USB interfaces sold by the Swedish manufacturer Kvaser are
divided into two major families: 'Leaf', and 'UsbcanII'.  From an
Operating System perspective, the firmware of both families behave
in a not too drastically different fashion.

This patch adds support for the UsbcanII family of devices to the
current Kvaser Leaf-only driver.

CAN frames sending, receiving, and error handling paths has been
tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It
should also work nicely with other products in the same category.

List of new devices supported by this driver update:

         - Kvaser USBcan II HS/HS
         - Kvaser USBcan II HS/LS
         - Kvaser USBcan Rugged ("USBcan Rev B")
         - Kvaser Memorator HS/HS
         - Kvaser Memorator HS/LS
         - Scania VCI2 (if you have the Kvaser logo on top)

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/Kconfig      |   8 +-
 drivers/net/can/usb/kvaser_usb.c | 627 +++++++++++++++++++++++++++++++--------
 2 files changed, 510 insertions(+), 125 deletions(-)

** V2 Changelog:
- Update Kconfig entries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixes

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919..f6f5500 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -25,7 +25,7 @@ config CAN_KVASER_USB
 	tristate "Kvaser CAN/USB interface"
 	---help---
 	  This driver adds support for Kvaser CAN/USB devices like Kvaser
-	  Leaf Light.
+	  Leaf Light and Kvaser USBcan II.
 
 	  The driver provides support for the following devices:
 	    - Kvaser Leaf Light
@@ -46,6 +46,12 @@ config CAN_KVASER_USB
 	    - Kvaser USBcan R
 	    - Kvaser Leaf Light v2
 	    - Kvaser Mini PCI Express HS
+	    - Kvaser USBcan II HS/HS
+	    - Kvaser USBcan II HS/LS
+	    - Kvaser USBcan Rugged ("USBcan Rev B")
+	    - Kvaser Memorator HS/HS
+	    - Kvaser Memorator HS/LS
+	    - Scania VCI2 (if you have the Kvaser logo on top)
 
 	  If unsure, say N.
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 2791501..50da317 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -6,10 +6,12 @@
  * Parts of this driver are based on the following:
  *  - Kvaser linux leaf driver (version 4.78)
  *  - CAN driver for esd CAN-USB/2
+ *  - Kvaser linux usbcanII driver (version 5.3)
  *
  * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
  * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * Copyright (C) 2014 Valeo Corporation
  */
 
 #include <linux/completion.h>
@@ -21,6 +23,18 @@
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
+/*
+ * Kvaser USB CAN dongles are divided into two major families:
+ * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo'
+ * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios'
+ */
+enum kvaser_usb_family {
+	KVASER_LEAF,
+	KVASER_USBCAN,
+};
+
+#define MAX(a, b)			((a) > (b) ? (a) : (b))
+
 #define MAX_TX_URBS			16
 #define MAX_RX_URBS			4
 #define START_TIMEOUT			1000 /* msecs */
@@ -29,9 +43,12 @@
 #define USB_RECV_TIMEOUT		1000 /* msecs */
 #define RX_BUFFER_SIZE			3072
 #define CAN_USB_CLOCK			8000000
-#define MAX_NET_DEVICES			3
+#define LEAF_MAX_NET_DEVICES		3
+#define USBCAN_MAX_NET_DEVICES		2
+#define MAX_NET_DEVICES			MAX(LEAF_MAX_NET_DEVICES, \
+					    USBCAN_MAX_NET_DEVICES)
 
-/* Kvaser USB devices */
+/* Leaf USB devices */
 #define KVASER_VENDOR_ID		0x0bfd
 #define USB_LEAF_DEVEL_PRODUCT_ID	10
 #define USB_LEAF_LITE_PRODUCT_ID	11
@@ -55,6 +72,16 @@
 #define USB_CAN_R_PRODUCT_ID		39
 #define USB_LEAF_LITE_V2_PRODUCT_ID	288
 #define USB_MINI_PCIE_HS_PRODUCT_ID	289
+#define LEAF_PRODUCT_ID(id)		(id >= USB_LEAF_DEVEL_PRODUCT_ID && \
+					 id <= USB_MINI_PCIE_HS_PRODUCT_ID)
+
+/* USBCANII devices */
+#define USB_USBCAN_REVB_PRODUCT_ID	2
+#define USB_VCI2_PRODUCT_ID		3
+#define USB_USBCAN2_PRODUCT_ID		4
+#define USB_MEMORATOR_PRODUCT_ID	5
+#define USBCAN_PRODUCT_ID(id)		(id >= USB_USBCAN_REVB_PRODUCT_ID && \
+					 id <= USB_MEMORATOR_PRODUCT_ID)
 
 /* USB devices features */
 #define KVASER_HAS_SILENT_MODE		BIT(0)
@@ -73,7 +100,7 @@
 #define MSG_FLAG_TX_ACK			BIT(6)
 #define MSG_FLAG_TX_REQUEST		BIT(7)
 
-/* Can states */
+/* Can states (M16C CxSTRH register) */
 #define M16C_STATE_BUS_RESET		BIT(0)
 #define M16C_STATE_BUS_ERROR		BIT(4)
 #define M16C_STATE_BUS_PASSIVE		BIT(5)
@@ -98,7 +125,13 @@
 #define CMD_START_CHIP_REPLY		27
 #define CMD_STOP_CHIP			28
 #define CMD_STOP_CHIP_REPLY		29
-#define CMD_GET_CARD_INFO2		32
+#define CMD_READ_CLOCK			30
+#define CMD_READ_CLOCK_REPLY		31
+
+#define LEAF_CMD_GET_CARD_INFO2		32
+#define USBCAN_CMD_RESET_CLOCK		32
+#define USBCAN_CMD_CLOCK_OVERFLOW_EVENT	33
+
 #define CMD_GET_CARD_INFO		34
 #define CMD_GET_CARD_INFO_REPLY		35
 #define CMD_GET_SOFTWARE_INFO		38
@@ -108,8 +141,9 @@
 #define CMD_RESET_ERROR_COUNTER		49
 #define CMD_TX_ACKNOWLEDGE		50
 #define CMD_CAN_ERROR_EVENT		51
-#define CMD_USB_THROTTLE		77
-#define CMD_LOG_MESSAGE			106
+
+#define LEAF_CMD_USB_THROTTLE		77
+#define LEAF_CMD_LOG_MESSAGE		106
 
 /* error factors */
 #define M16C_EF_ACKE			BIT(0)
@@ -121,6 +155,13 @@
 #define M16C_EF_RCVE			BIT(6)
 #define M16C_EF_TRE			BIT(7)
 
+/* Only Leaf-based devices can report M16C error factors,
+ * thus define our own error status flags for USBCAN */
+#define USBCAN_ERROR_STATE_NONE		0
+#define USBCAN_ERROR_STATE_TX_ERROR	BIT(0)
+#define USBCAN_ERROR_STATE_RX_ERROR	BIT(1)
+#define USBCAN_ERROR_STATE_BUSERROR	BIT(2)
+
 /* bittiming parameters */
 #define KVASER_USB_TSEG1_MIN		1
 #define KVASER_USB_TSEG1_MAX		16
@@ -137,7 +178,7 @@
 #define KVASER_CTRL_MODE_SELFRECEPTION	3
 #define KVASER_CTRL_MODE_OFF		4
 
-/* log message */
+/* Extended CAN identifier flag */
 #define KVASER_EXTENDED_FRAME		BIT(31)
 
 struct kvaser_msg_simple {
@@ -148,30 +189,55 @@ struct kvaser_msg_simple {
 struct kvaser_msg_cardinfo {
 	u8 tid;
 	u8 nchannels;
-	__le32 serial_number;
-	__le32 padding;
+	union {
+		struct {
+			__le32 serial_number;
+			__le32 padding;
+		} __packed leaf0;
+		struct {
+			__le32 serial_number_low;
+			__le32 serial_number_high;
+		} __packed usbcan0;
+	} __packed;
 	__le32 clock_resolution;
 	__le32 mfgdate;
 	u8 ean[8];
 	u8 hw_revision;
-	u8 usb_hs_mode;
-	__le16 padding2;
+	union {
+		struct {
+			u8 usb_hs_mode;
+		} __packed leaf1;
+		struct {
+			u8 padding;
+		} __packed usbcan1;
+	} __packed;
+	__le16 padding;
 } __packed;
 
 struct kvaser_msg_cardinfo2 {
 	u8 tid;
-	u8 channel;
+	u8 reserved;
 	u8 pcb_id[24];
 	__le32 oem_unlock_code;
 } __packed;
 
-struct kvaser_msg_softinfo {
+struct leaf_msg_softinfo {
 	u8 tid;
-	u8 channel;
+	u8 padding0;
 	__le32 sw_options;
 	__le32 fw_version;
 	__le16 max_outstanding_tx;
-	__le16 padding[9];
+	__le16 padding1[9];
+} __packed;
+
+struct usbcan_msg_softinfo {
+	u8 tid;
+	u8 fw_name[5];
+	__le16 max_outstanding_tx;
+	u8 padding[6];
+	__le32 fw_version;
+	__le16 checksum;
+	__le16 sw_options;
 } __packed;
 
 struct kvaser_msg_busparams {
@@ -188,36 +254,86 @@ struct kvaser_msg_tx_can {
 	u8 channel;
 	u8 tid;
 	u8 msg[14];
-	u8 padding;
-	u8 flags;
+	union {
+		struct {
+			u8 padding;
+			u8 flags;
+		} __packed leaf;
+		struct {
+			u8 flags;
+			u8 padding;
+		} __packed usbcan;
+	} __packed;
+} __packed;
+
+struct kvaser_msg_rx_can_header {
+	u8 channel;
+	u8 flag;
 } __packed;
 
-struct kvaser_msg_rx_can {
+struct leaf_msg_rx_can {
 	u8 channel;
 	u8 flag;
+
 	__le16 time[3];
 	u8 msg[14];
 } __packed;
 
-struct kvaser_msg_chip_state_event {
+struct usbcan_msg_rx_can {
+	u8 channel;
+	u8 flag;
+
+	u8 msg[14];
+	__le16 time;
+} __packed;
+
+struct leaf_msg_chip_state_event {
 	u8 tid;
 	u8 channel;
+
 	__le16 time[3];
 	u8 tx_errors_count;
 	u8 rx_errors_count;
+
 	u8 status;
 	u8 padding[3];
 } __packed;
 
-struct kvaser_msg_tx_acknowledge {
+struct usbcan_msg_chip_state_event {
+	u8 tid;
+	u8 channel;
+
+	u8 tx_errors_count;
+	u8 rx_errors_count;
+	__le16 time;
+
+	u8 status;
+	u8 padding[3];
+} __packed;
+
+struct kvaser_msg_tx_acknowledge_header {
+	u8 channel;
+	u8 tid;
+};
+
+struct leaf_msg_tx_acknowledge {
 	u8 channel;
 	u8 tid;
+
 	__le16 time[3];
 	u8 flags;
 	u8 time_offset;
 } __packed;
 
-struct kvaser_msg_error_event {
+struct usbcan_msg_tx_acknowledge {
+	u8 channel;
+	u8 tid;
+
+	__le16 time;
+	__le16 padding;
+} __packed;
+
+struct leaf_msg_error_event {
 	u8 tid;
 	u8 flags;
 	__le16 time[3];
@@ -229,6 +345,18 @@ struct kvaser_msg_error_event {
 	u8 error_factor;
 } __packed;
 
+struct usbcan_msg_error_event {
+	u8 tid;
+	u8 padding;
+	u8 tx_errors_count_ch0;
+	u8 rx_errors_count_ch0;
+	u8 tx_errors_count_ch1;
+	u8 rx_errors_count_ch1;
+	u8 status_ch0;
+	u8 status_ch1;
+	__le16 time;
+} __packed;
+
 struct kvaser_msg_ctrl_mode {
 	u8 tid;
 	u8 channel;
@@ -243,7 +371,7 @@ struct kvaser_msg_flush_queue {
 	u8 padding[3];
 } __packed;
 
-struct kvaser_msg_log_message {
+struct leaf_msg_log_message {
 	u8 channel;
 	u8 flags;
 	__le16 time[3];
@@ -260,19 +388,49 @@ struct kvaser_msg {
 		struct kvaser_msg_simple simple;
 		struct kvaser_msg_cardinfo cardinfo;
 		struct kvaser_msg_cardinfo2 cardinfo2;
-		struct kvaser_msg_softinfo softinfo;
 		struct kvaser_msg_busparams busparams;
+
+		struct kvaser_msg_rx_can_header rx_can_header;
+		struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header;
+
+		union {
+			struct leaf_msg_softinfo softinfo;
+			struct leaf_msg_rx_can rx_can;
+			struct leaf_msg_chip_state_event chip_state_event;
+			struct leaf_msg_tx_acknowledge tx_acknowledge;
+			struct leaf_msg_error_event error_event;
+			struct leaf_msg_log_message log_message;
+		} __packed leaf;
+
+		union {
+			struct usbcan_msg_softinfo softinfo;
+			struct usbcan_msg_rx_can rx_can;
+			struct usbcan_msg_chip_state_event chip_state_event;
+			struct usbcan_msg_tx_acknowledge tx_acknowledge;
+			struct usbcan_msg_error_event error_event;
+		} __packed usbcan;
+
 		struct kvaser_msg_tx_can tx_can;
-		struct kvaser_msg_rx_can rx_can;
-		struct kvaser_msg_chip_state_event chip_state_event;
-		struct kvaser_msg_tx_acknowledge tx_acknowledge;
-		struct kvaser_msg_error_event error_event;
 		struct kvaser_msg_ctrl_mode ctrl_mode;
 		struct kvaser_msg_flush_queue flush_queue;
-		struct kvaser_msg_log_message log_message;
 	} u;
 } __packed;
 
+/* Leaf/USBCAN-agnostic summary of an error event.
+ * No M16C error factors for USBCAN-based devices. */
+struct kvaser_error_summary {
+	u8 channel, status, txerr, rxerr;
+	union {
+		struct {
+			u8 error_factor;
+		} leaf;
+		struct {
+			u8 other_ch_status;
+			u8 error_state;
+		} usbcan;
+	};
+};
+
 struct kvaser_usb_tx_urb_context {
 	struct kvaser_usb_net_priv *priv;
 	u32 echo_index;
@@ -288,6 +446,8 @@ struct kvaser_usb {
 
 	u32 fw_version;
 	unsigned int nchannels;
+	enum kvaser_usb_family family;
+	unsigned int max_channels;
 
 	bool rxinitdone;
 	void *rxbuf[MAX_RX_URBS];
@@ -311,6 +471,7 @@ struct kvaser_usb_net_priv {
 };
 
 static const struct usb_device_id kvaser_usb_table[] = {
+	/* Leaf family IDs */
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
@@ -360,6 +521,17 @@ static const struct usb_device_id kvaser_usb_table[] = {
 		.driver_info = KVASER_HAS_TXRX_ERRORS },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
+
+	/* USBCANII family IDs */
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -463,7 +635,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
 	if (err)
 		return err;
 
-	dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
+	switch (dev->family) {
+	case KVASER_LEAF:
+		dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
+		break;
+	case KVASER_USBCAN:
+		dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -482,7 +665,7 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
 		return err;
 
 	dev->nchannels = msg.u.cardinfo.nchannels;
-	if (dev->nchannels > MAX_NET_DEVICES)
+	if (dev->nchannels > dev->max_channels)
 		return -EINVAL;
 
 	return 0;
@@ -496,8 +679,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 	struct kvaser_usb_net_priv *priv;
 	struct sk_buff *skb;
 	struct can_frame *cf;
-	u8 channel = msg->u.tx_acknowledge.channel;
-	u8 tid = msg->u.tx_acknowledge.tid;
+	u8 channel, tid;
+
+	channel = msg->u.tx_acknowledge_header.channel;
+	tid = msg->u.tx_acknowledge_header.tid;
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -615,37 +800,83 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
 		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
 }
 
-static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
-				const struct kvaser_msg *msg)
+static void kvaser_report_error_event(const struct kvaser_usb *dev,
+				      struct kvaser_error_summary *es);
+
+/*
+ * Report error to userspace iff the controller's errors counter has
+ * increased, or we're the only channel seeing the bus error state.
+ *
+ * As reported by USBCAN sheets, "the CAN controller has difficulties
+ * to tell whether an error frame arrived on channel 1 or on channel 2."
+ * Thus, error counters are compared with their earlier values to
+ * determine which channel was responsible for the error event.
+ */
+static void usbcan_report_error_if_applicable(const struct kvaser_usb *dev,
+					      struct kvaser_error_summary *es)
 {
-	struct can_frame *cf;
-	struct sk_buff *skb;
-	struct net_device_stats *stats;
 	struct kvaser_usb_net_priv *priv;
-	unsigned int new_state;
-	u8 channel, status, txerr, rxerr, error_factor;
+	int old_tx_err_count, old_rx_err_count, channel, report_error;
+
+	channel = es->channel;
+	if (channel >= dev->nchannels) {
+		dev_err(dev->udev->dev.parent,
+			"Invalid channel number (%d)\n", channel);
+		return;
+	}
+
+	priv = dev->nets[channel];
+	old_tx_err_count = priv->bec.txerr;
+	old_rx_err_count = priv->bec.rxerr;
+
+	report_error = 0;
+	if (es->txerr > old_tx_err_count) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR;
+		report_error = 1;
+	}
+	if (es->rxerr > old_rx_err_count) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR;
+		report_error = 1;
+	}
+	if ((es->status & M16C_STATE_BUS_ERROR) &&
+	    !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR;
+		report_error = 1;
+	}
+
+	if (report_error)
+		kvaser_report_error_event(dev, es);
+}
+
+/*
+ * Extract error summary from a Leaf-based device error message
+ */
+static void leaf_extract_error_from_msg(const struct kvaser_usb *dev,
+					const struct kvaser_msg *msg)
+{
+	struct kvaser_error_summary es = { 0, };
 
 	switch (msg->id) {
 	case CMD_CAN_ERROR_EVENT:
-		channel = msg->u.error_event.channel;
-		status =  msg->u.error_event.status;
-		txerr = msg->u.error_event.tx_errors_count;
-		rxerr = msg->u.error_event.rx_errors_count;
-		error_factor = msg->u.error_event.error_factor;
+		es.channel = msg->u.leaf.error_event.channel;
+		es.status =  msg->u.leaf.error_event.status;
+		es.txerr = msg->u.leaf.error_event.tx_errors_count;
+		es.rxerr = msg->u.leaf.error_event.rx_errors_count;
+		es.leaf.error_factor = msg->u.leaf.error_event.error_factor;
 		break;
-	case CMD_LOG_MESSAGE:
-		channel = msg->u.log_message.channel;
-		status = msg->u.log_message.data[0];
-		txerr = msg->u.log_message.data[2];
-		rxerr = msg->u.log_message.data[3];
-		error_factor = msg->u.log_message.data[1];
+	case LEAF_CMD_LOG_MESSAGE:
+		es.channel = msg->u.leaf.log_message.channel;
+		es.status = msg->u.leaf.log_message.data[0];
+		es.txerr = msg->u.leaf.log_message.data[2];
+		es.rxerr = msg->u.leaf.log_message.data[3];
+		es.leaf.error_factor = msg->u.leaf.log_message.data[1];
 		break;
 	case CMD_CHIP_STATE_EVENT:
-		channel = msg->u.chip_state_event.channel;
-		status =  msg->u.chip_state_event.status;
-		txerr = msg->u.chip_state_event.tx_errors_count;
-		rxerr = msg->u.chip_state_event.rx_errors_count;
-		error_factor = 0;
+		es.channel = msg->u.leaf.chip_state_event.channel;
+		es.status =  msg->u.leaf.chip_state_event.status;
+		es.txerr = msg->u.leaf.chip_state_event.tx_errors_count;
+		es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count;
+		es.leaf.error_factor = 0;
 		break;
 	default:
 		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
@@ -653,16 +884,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		return;
 	}
 
-	if (channel >= dev->nchannels) {
+	kvaser_report_error_event(dev, &es);
+}
+
+/*
+ * Extract summary from a USBCANII-based device error message.
+ */
+static void usbcan_extract_error_from_msg(const struct kvaser_usb *dev,
+					const struct kvaser_msg *msg)
+{
+	struct kvaser_error_summary es = { 0, };
+
+	switch (msg->id) {
+
+	/* Sometimes errors are sent as unsolicited chip state events */
+	case CMD_CHIP_STATE_EVENT:
+		es.channel = msg->u.usbcan.chip_state_event.channel;
+		es.status =  msg->u.usbcan.chip_state_event.status;
+		es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count;
+		es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count;
+		usbcan_report_error_if_applicable(dev, &es);
+		break;
+
+	case CMD_CAN_ERROR_EVENT:
+		es.channel = 0;
+		es.status = msg->u.usbcan.error_event.status_ch0;
+		es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0;
+		es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0;
+		es.usbcan.other_ch_status =
+			msg->u.usbcan.error_event.status_ch1;
+		usbcan_report_error_if_applicable(dev, &es);
+
+		/* For error events, the USBCAN firmware does not support
+		 * more than 2 channels: ch0, and ch1. */
+		if (dev->nchannels > 1) {
+			es.channel = 1;
+			es.status = msg->u.usbcan.error_event.status_ch1;
+			es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1;
+			es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1;
+			es.usbcan.other_ch_status =
+				msg->u.usbcan.error_event.status_ch0;
+			usbcan_report_error_if_applicable(dev, &es);
+		}
+		break;
+
+	default:
+		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
+			msg->id);
+	}
+}
+
+static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
+				const struct kvaser_msg *msg)
+{
+	switch (dev->family) {
+	case KVASER_LEAF:
+		leaf_extract_error_from_msg(dev, msg);
+		break;
+	case KVASER_USBCAN:
+		usbcan_extract_error_from_msg(dev, msg);
+		break;
+	default:
 		dev_err(dev->udev->dev.parent,
-			"Invalid channel number (%d)\n", channel);
+			"Invalid device family (%d)\n", dev->family);
 		return;
 	}
+}
 
-	priv = dev->nets[channel];
+static void kvaser_report_error_event(const struct kvaser_usb *dev,
+				      struct kvaser_error_summary *es)
+{
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	struct net_device_stats *stats;
+	struct kvaser_usb_net_priv *priv;
+	unsigned int new_state;
+
+	if (es->channel >= dev->nchannels) {
+		dev_err(dev->udev->dev.parent,
+			"Invalid channel number (%d)\n", es->channel);
+		return;
+	}
+
+	priv = dev->nets[es->channel];
 	stats = &priv->netdev->stats;
 
-	if (status & M16C_STATE_BUS_RESET) {
+	if (es->status & M16C_STATE_BUS_RESET) {
 		kvaser_usb_unlink_tx_urbs(priv);
 		return;
 	}
@@ -675,9 +982,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
 	new_state = priv->can.state;
 
-	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
+	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
 
-	if (status & M16C_STATE_BUS_OFF) {
+	if (es->status & M16C_STATE_BUS_OFF) {
 		cf->can_id |= CAN_ERR_BUSOFF;
 
 		priv->can.can_stats.bus_off++;
@@ -687,12 +994,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		netif_carrier_off(priv->netdev);
 
 		new_state = CAN_STATE_BUS_OFF;
-	} else if (status & M16C_STATE_BUS_PASSIVE) {
+	} else if (es->status & M16C_STATE_BUS_PASSIVE) {
 		if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
 			cf->can_id |= CAN_ERR_CRTL;
 
-			if (txerr || rxerr)
-				cf->data[1] = (txerr > rxerr)
+			if (es->txerr || es->rxerr)
+				cf->data[1] = (es->txerr > es->rxerr)
 						? CAN_ERR_CRTL_TX_PASSIVE
 						: CAN_ERR_CRTL_RX_PASSIVE;
 			else
@@ -703,13 +1010,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 
 		new_state = CAN_STATE_ERROR_PASSIVE;
-	}
-
-	if (status == M16C_STATE_BUS_ERROR) {
+	} else if (es->status & M16C_STATE_BUS_ERROR) {
 		if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
-		    ((txerr >= 96) || (rxerr >= 96))) {
+		    ((es->txerr >= 96) || (es->rxerr >= 96))) {
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (txerr > rxerr)
+			cf->data[1] = (es->txerr > es->rxerr)
 					? CAN_ERR_CRTL_TX_WARNING
 					: CAN_ERR_CRTL_RX_WARNING;
 
@@ -723,7 +1028,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 	}
 
-	if (!status) {
+	if (!es->status) {
 		cf->can_id |= CAN_ERR_PROT;
 		cf->data[2] = CAN_ERR_PROT_ACTIVE;
 
@@ -739,34 +1044,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		priv->can.can_stats.restarts++;
 	}
 
-	if (error_factor) {
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-
-		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-
-		if (error_factor & M16C_EF_ACKE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
-		if (error_factor & M16C_EF_CRCE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-					CAN_ERR_PROT_LOC_CRC_DEL);
-		if (error_factor & M16C_EF_FORME)
-			cf->data[2] |= CAN_ERR_PROT_FORM;
-		if (error_factor & M16C_EF_STFE)
-			cf->data[2] |= CAN_ERR_PROT_STUFF;
-		if (error_factor & M16C_EF_BITE0)
-			cf->data[2] |= CAN_ERR_PROT_BIT0;
-		if (error_factor & M16C_EF_BITE1)
-			cf->data[2] |= CAN_ERR_PROT_BIT1;
-		if (error_factor & M16C_EF_TRE)
-			cf->data[2] |= CAN_ERR_PROT_TX;
+	switch (dev->family) {
+	case KVASER_LEAF:
+		if (es->leaf.error_factor) {
+			priv->can.can_stats.bus_error++;
+			stats->rx_errors++;
+
+			cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+
+			if (es->leaf.error_factor & M16C_EF_ACKE)
+				cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
+			if (es->leaf.error_factor & M16C_EF_CRCE)
+				cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+						CAN_ERR_PROT_LOC_CRC_DEL);
+			if (es->leaf.error_factor & M16C_EF_FORME)
+				cf->data[2] |= CAN_ERR_PROT_FORM;
+			if (es->leaf.error_factor & M16C_EF_STFE)
+				cf->data[2] |= CAN_ERR_PROT_STUFF;
+			if (es->leaf.error_factor & M16C_EF_BITE0)
+				cf->data[2] |= CAN_ERR_PROT_BIT0;
+			if (es->leaf.error_factor & M16C_EF_BITE1)
+				cf->data[2] |= CAN_ERR_PROT_BIT1;
+			if (es->leaf.error_factor & M16C_EF_TRE)
+				cf->data[2] |= CAN_ERR_PROT_TX;
+		}
+		break;
+	case KVASER_USBCAN:
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
+			stats->tx_errors++;
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
+			stats->rx_errors++;
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
+			priv->can.can_stats.bus_error++;
+			cf->can_id |= CAN_ERR_BUSERROR;
+		}
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		goto err;
 	}
 
-	cf->data[6] = txerr;
-	cf->data[7] = rxerr;
+	cf->data[6] = es->txerr;
+	cf->data[7] = es->rxerr;
 
-	priv->bec.txerr = txerr;
-	priv->bec.rxerr = rxerr;
+	priv->bec.txerr = es->txerr;
+	priv->bec.rxerr = es->rxerr;
 
 	priv->can.state = new_state;
 
@@ -774,6 +1097,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
+
+	return;
+
+err:
+	dev_kfree_skb(skb);
 }
 
 static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -783,16 +1111,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 	struct sk_buff *skb;
 	struct net_device_stats *stats = &priv->netdev->stats;
 
-	if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+	if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
 					 MSG_FLAG_NERR)) {
 		netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
-			   msg->u.rx_can.flag);
+			   msg->u.rx_can_header.flag);
 
 		stats->rx_errors++;
 		return;
 	}
 
-	if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
+	if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) {
 		skb = alloc_can_err_skb(priv->netdev, &cf);
 		if (!skb) {
 			stats->rx_dropped++;
@@ -819,7 +1147,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 	struct can_frame *cf;
 	struct sk_buff *skb;
 	struct net_device_stats *stats;
-	u8 channel = msg->u.rx_can.channel;
+	u8 channel = msg->u.rx_can_header.channel;
+	const u8 *rx_msg;
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -830,19 +1159,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 	priv = dev->nets[channel];
 	stats = &priv->netdev->stats;
 
-	if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) &&
-	    (msg->id == CMD_LOG_MESSAGE)) {
+	if ((msg->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
+	    (dev->family == KVASER_LEAF && msg->id == LEAF_CMD_LOG_MESSAGE)) {
 		kvaser_usb_rx_error(dev, msg);
 		return;
-	} else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
-					 MSG_FLAG_NERR |
-					 MSG_FLAG_OVERRUN)) {
+	} else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
+						MSG_FLAG_NERR |
+						MSG_FLAG_OVERRUN)) {
 		kvaser_usb_rx_can_err(priv, msg);
 		return;
-	} else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
+	} else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) {
 		netdev_warn(priv->netdev,
 			    "Unhandled frame (flags: 0x%02x)",
-			    msg->u.rx_can.flag);
+			    msg->u.rx_can_header.flag);
+		return;
+	}
+
+	switch (dev->family) {
+	case KVASER_LEAF:
+		rx_msg = msg->u.leaf.rx_can.msg;
+		break;
+	case KVASER_USBCAN:
+		rx_msg = msg->u.usbcan.rx_can.msg;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
 		return;
 	}
 
@@ -852,38 +1194,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 		return;
 	}
 
-	if (msg->id == CMD_LOG_MESSAGE) {
-		cf->can_id = le32_to_cpu(msg->u.log_message.id);
+	if (dev->family == KVASER_LEAF && msg->id == LEAF_CMD_LOG_MESSAGE) {
+		cf->can_id = le32_to_cpu(msg->u.leaf.log_message.id);
 		if (cf->can_id & KVASER_EXTENDED_FRAME)
 			cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
 		else
 			cf->can_id &= CAN_SFF_MASK;
 
-		cf->can_dlc = get_can_dlc(msg->u.log_message.dlc);
+		cf->can_dlc = get_can_dlc(msg->u.leaf.log_message.dlc);
 
-		if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME)
+		if (msg->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME)
 			cf->can_id |= CAN_RTR_FLAG;
 		else
-			memcpy(cf->data, &msg->u.log_message.data,
+			memcpy(cf->data, &msg->u.leaf.log_message.data,
 			       cf->can_dlc);
 	} else {
-		cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
-			     (msg->u.rx_can.msg[1] & 0x3f);
+		cf->can_id = ((rx_msg[0] & 0x1f) << 6) | (rx_msg[1] & 0x3f);
 
 		if (msg->id == CMD_RX_EXT_MESSAGE) {
 			cf->can_id <<= 18;
-			cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
-				      ((msg->u.rx_can.msg[3] & 0xff) << 6) |
-				      (msg->u.rx_can.msg[4] & 0x3f);
+			cf->can_id |= ((rx_msg[2] & 0x0f) << 14) |
+				      ((rx_msg[3] & 0xff) << 6) |
+				      (rx_msg[4] & 0x3f);
 			cf->can_id |= CAN_EFF_FLAG;
 		}
 
-		cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+		cf->can_dlc = get_can_dlc(rx_msg[5]);
 
-		if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
+		if (msg->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME)
 			cf->can_id |= CAN_RTR_FLAG;
 		else
-			memcpy(cf->data, &msg->u.rx_can.msg[6],
+			memcpy(cf->data, &rx_msg[6],
 			       cf->can_dlc);
 	}
 
@@ -947,7 +1288,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
 
 	case CMD_RX_STD_MESSAGE:
 	case CMD_RX_EXT_MESSAGE:
-	case CMD_LOG_MESSAGE:
+		kvaser_usb_rx_can_msg(dev, msg);
+		break;
+
+	case LEAF_CMD_LOG_MESSAGE:
+		if (dev->family != KVASER_LEAF)
+			goto warn;
 		kvaser_usb_rx_can_msg(dev, msg);
 		break;
 
@@ -960,8 +1306,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
 		kvaser_usb_tx_acknowledge(dev, msg);
 		break;
 
+	/* Ignored messages */
+	case USBCAN_CMD_CLOCK_OVERFLOW_EVENT:
+		if (dev->family != KVASER_USBCAN)
+			goto warn;
+		break;
+
 	default:
-		dev_warn(dev->udev->dev.parent,
+warn:		dev_warn(dev->udev->dev.parent,
 			 "Unhandled message (%d)\n", msg->id);
 		break;
 	}
@@ -1181,7 +1533,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
 				  dev->rxbuf[i],
 				  dev->rxbuf_dma[i]);
 
-	for (i = 0; i < MAX_NET_DEVICES; i++) {
+	for (i = 0; i < dev->nchannels; i++) {
 		struct kvaser_usb_net_priv *priv = dev->nets[i];
 
 		if (priv)
@@ -1289,6 +1641,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	struct kvaser_msg *msg;
 	int i, err;
 	int ret = NETDEV_TX_OK;
+	uint8_t *msg_tx_can_flags;
 
 	if (can_dropped_invalid_skb(netdev, skb))
 		return NETDEV_TX_OK;
@@ -1310,9 +1663,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 
 	msg = buf;
 	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
-	msg->u.tx_can.flags = 0;
 	msg->u.tx_can.channel = priv->channel;
 
+	switch (dev->family) {
+	case KVASER_LEAF:
+		msg_tx_can_flags = &msg->u.tx_can.leaf.flags;
+		break;
+	case KVASER_USBCAN:
+		msg_tx_can_flags = &msg->u.tx_can.usbcan.flags;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		goto releasebuf;
+	}
+
+	*msg_tx_can_flags = 0;
+
 	if (cf->can_id & CAN_EFF_FLAG) {
 		msg->id = CMD_TX_EXT_MESSAGE;
 		msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
@@ -1330,7 +1697,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
 
 	if (cf->can_id & CAN_RTR_FLAG)
-		msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
+		*msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
 
 	for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
 		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
@@ -1601,6 +1968,18 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 	if (!dev)
 		return -ENOMEM;
 
+	if (LEAF_PRODUCT_ID(id->idProduct)) {
+		dev->family = KVASER_LEAF;
+		dev->max_channels = LEAF_MAX_NET_DEVICES;
+	} else if (USBCAN_PRODUCT_ID(id->idProduct)) {
+		dev->family = KVASER_USBCAN;
+		dev->max_channels = USBCAN_MAX_NET_DEVICES;
+	} else {
+		dev_err(&intf->dev, "Product ID (%d) does not belong to any "
+				    "known Kvaser USB family", id->idProduct);
+		return -ENODEV;
+	}
+
 	err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
 	if (err) {
 		dev_err(&intf->dev, "Cannot get usb endpoint(s)");

^ permalink raw reply	[relevance 36%]

* Re: [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  @ 2014-12-25  9:38 99%     ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2014-12-25  9:38 UTC (permalink / raw)
  To: Greg KH
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, David S. Miller, Paul Gortmaker, Linux-CAN,
	netdev, Linux-stable, LKML

On Wed, Dec 24, 2014 at 06:50:11PM -0800, Greg KH wrote:
> On Thu, Dec 25, 2014 at 01:56:44AM +0200, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
  > > Flooding the Kvaser CAN to USB dongle with multiple reads and
> > writes in high frequency caused seemingly-random panics in the
> > kernel.
> > 
> > On further inspection, it seems the driver erroneously freed the
> > to-be-transmitted packet upon getting tight on URBs and returning
> > NETDEV_TX_BUSY, leading to invalid memory writes and double frees
> > at a later point in time.
> > 
> > Note:
> > 
> > Finding no more URBs/transmit-contexts and returning NETDEV_TX_BUSY
> > is a driver bug in and out of itself: it means that our start/stop
> > queue flow control is broken.
> > 
> > This patch only fixes the (buggy) error handling code; the root
> > cause shall be fixed in a later commit.
> > 
> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > ---
> >  drivers/net/can/usb/kvaser_usb.c | 12 ++++++------
> >  1 file changed, 6 insertions(+), 6 deletions(-)
> > 
> >  (Marc, Greg, I believe this should also be added to -stable?)
> 
> 
> <formletter>
> 
> This is not the correct way to submit patches for inclusion in the
> stable kernel tree.  Please read Documentation/stable_kernel_rules.txt
> for how to do this properly.
> 
> </formletter>

<msg-response>

Note taken. Sorry about that ;-)

</msg-response>

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  @ 2014-12-30 15:33 99%         ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2014-12-30 15:33 UTC (permalink / raw)
  To: Olivier Sobrie
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

On Sun, Dec 28, 2014 at 10:51:34PM +0100, Olivier Sobrie wrote:
[...]
> > > >  
> > > > +	if (LEAF_PRODUCT_ID(id->idProduct)) {
> > > > +		dev->family = KVASER_LEAF;
> > > > +		dev->max_channels = LEAF_MAX_NET_DEVICES;
> > > > +	} else if (USBCAN_PRODUCT_ID(id->idProduct)) {
> > > > +		dev->family = KVASER_USBCAN;
> > > > +		dev->max_channels = USBCAN_MAX_NET_DEVICES;
> > > > +	} else {
> > > > +		dev_err(&intf->dev, "Product ID (%d) does not belong to any "
> > > > +				    "known Kvaser USB family", id->idProduct);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > 
> > > Is it really required to keep max_channels in the kvaser_usb structure?
> > > If I looked correctly, you use this variable as a replacement for
> > > MAX_NET_DEVICES in the code and MAX_NET_DEVICES is only used in probe
> > > and disconnect functions. I think it can even be replaced by nchannels
> > > in the disconnect path. So I also think that it don't need to be in the
> > > kvaser_usb structure.
> > > 
> > 
> > hmmm.. given the current state of error arbitration explained
> > above, where I cannot accept a dev->nchannels > 2, I guess we
> > have two options:
> > 
> > a) Remove max_channels, and hardcode the channels count
> > correctness logic as follows:
> > 
> >         dev->nchannels = msg.u.cardinfo.nchannels;
> >         if ((dev->family == USBCAN && dev->nchannels > USBCAN_MAX_NET_DEVICES)
> >             || (dev->family == LEAF && dev->nchannels > LEAF_MAX_NET_DEVICES))
> >                 return -EINVAL
> > 
> > b) Leave max_channels in 'struct kvaser_usb' as is.
> > 
> > I personally prefer the solution at 'b)' but I can do it as
> > in 'a)' if you prefer :-)
> 
> Keeping max_channels in the kvaser_usb structure is useless because it
> is only used in one function that is called in the probe function.
> 
> I would prefer to have:
> 	if (dev->nchannels > MAX_NET_DEVICES)
> 		return -EINVAL
> 
> 	if ((dev->family == USBCAN) &&
> 	    (dev->nchannels > MAX_USBCAN_NET_DEVICES))
> 		return -EINVAL
> 
> You can remove LEAF_MAX_NET_DEVICES which is not used, keep
> MAX_NET_DEVICES equals to 3 and remove the MAX() macro.
> The test specific to the USBCAN family can eventually be moved in the
> kvaser_usb_probe() function.
> 

Quite nice, will do it that way in v3.

Regards,
Darwish

^ permalink raw reply	[relevance 99%]

* Re: [PATCH] can: kvaser_usb: Don't free packets when tight on URBs
  @ 2015-01-03 14:34 99%   ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2015-01-03 14:34 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, David S. Miller, Paul Gortmaker, Linux-CAN,
	netdev, LKML

On Thu, Jan 01, 2015 at 01:59:13PM -0800, Stephen Hemminger wrote:
> On Tue, 23 Dec 2014 17:46:54 +0200
> "Ahmed S. Darwish" <darwish.07@gmail.com> wrote:
> 
> >  	int ret = NETDEV_TX_OK;
> > +	bool kfree_skb_on_error = true;
> >  
> >  	if (can_dropped_invalid_skb(netdev, skb))
> >  		return NETDEV_TX_OK;
> > @@ -1336,6 +1337,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> >  
> >  	if (!context) {
> >  		netdev_warn(netdev, "cannot find free context\n");
> > +		kfree_skb_on_error = false;
> >  		ret =  NETDEV_TX_BUSY;
> 
> You already have a flag value (ret == NETDEV_TX_BUSY), why
> not use that instead of introducing another variable?

Yes, that variable got implicitly removed in v2 patch 1/4.

Thanks,

--
Darwish

^ permalink raw reply	[relevance 99%]

* [PATCH v3 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-23 15:46 96% [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
                   ` (3 preceding siblings ...)
  @ 2015-01-05 17:49 91% ` Ahmed S. Darwish
  2015-01-05 17:52 85%   ` [PATCH v3 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
  2015-01-11 20:05 99% ` [PATCH v4 00/04] can: Introduce support for Kvaser USBCAN-II devices Ahmed S. Darwish
  2015-01-20 21:44 67% ` [PATCH v5 1/5] can: kvaser_usb: Update net interface state before exiting on OOM Ahmed S. Darwish
  6 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2015-01-05 17:49 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Flooding the Kvaser CAN to USB dongle with multiple reads and
writes in high frequency caused seemingly-random panics in the
kernel.

On further inspection, it seems the driver erroneously freed the
to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees
at a later point in time.

Note:

Finding no more URBs/transmit-contexts and returning NETDEV_TX_BUSY
is a driver bug in and out of itself: it means that our start/stop
queue flow control is broken.

This patch only fixes the (buggy) error handling code; the root
cause shall be fixed in a later commit.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
Acked-by: Olivier Sobrie <olivier@sobrie.be>
---
 drivers/net/can/usb/kvaser_usb.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

** V3 Changelog:
- checkpatch.pl suggestions ('net/' commenting style)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 541fb7a..2e7d513 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -1294,12 +1294,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	if (!urb) {
 		netdev_err(netdev, "No memory left for URBs\n");
 		stats->tx_dropped++;
-		goto nourbmem;
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
 	}
 
 	buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
 	if (!buf) {
 		stats->tx_dropped++;
+		dev_kfree_skb(skb);
 		goto nobufmem;
 	}
 
@@ -1334,6 +1336,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 		}
 	}
 
+	/* This should never happen; it implies a flow control bug */
 	if (!context) {
 		netdev_warn(netdev, "cannot find free context\n");
 		ret =  NETDEV_TX_BUSY;
@@ -1364,9 +1367,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	if (unlikely(err)) {
 		can_free_echo_skb(netdev, context->echo_index);
 
-		skb = NULL; /* set to NULL to avoid double free in
-			     * dev_kfree_skb(skb) */
-
 		atomic_dec(&priv->active_tx_urbs);
 		usb_unanchor_urb(urb);
 
@@ -1388,8 +1388,6 @@ releasebuf:
 	kfree(buf);
 nobufmem:
 	usb_free_urb(urb);
-nourbmem:
-	dev_kfree_skb(skb);
 	return ret;
 }
 


^ permalink raw reply	[relevance 91%]

* [PATCH v3 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels
  2015-01-05 17:52 85%   ` [PATCH v3 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
@ 2015-01-05 17:57 97%     ` Ahmed S. Darwish
  2015-01-05 18:31 36%       ` [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2015-01-05 17:57 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Recent Leaf firmware versions (>= 3.1.557) do not allow to send
commands for non-existing channels.  If a command is sent for a
non-existing channel, the firmware crashes.

Reported-by: Christopher Storah <Christopher.Storah@invetech.com.au>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
---
 drivers/net/can/usb/kvaser_usb.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

** V3 Changelog:
- Update commit log message per Olivier remarks on v2

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 9accc82..cc7bfc0 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -1503,6 +1503,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
 	struct kvaser_usb_net_priv *priv;
 	int i, err;
 
+	err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel);
+	if (err)
+		return err;
+
 	netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
 	if (!netdev) {
 		dev_err(&intf->dev, "Cannot alloc candev\n");
@@ -1607,9 +1611,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
 	usb_set_intfdata(intf, dev);
 
-	for (i = 0; i < MAX_NET_DEVICES; i++)
-		kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
-
 	err = kvaser_usb_get_software_info(dev);
 	if (err) {
 		dev_err(&intf->dev,


^ permalink raw reply	[relevance 97%]

* [PATCH v3 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close
  2015-01-05 17:49 91% ` [PATCH v3 1/4] " Ahmed S. Darwish
@ 2015-01-05 17:52 85%   ` Ahmed S. Darwish
  2015-01-05 17:57 97%     ` [PATCH v3 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
  0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2015-01-05 17:52 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Flooding the Kvaser CAN to USB dongle with multiple reads and
writes in very high frequency (*), closing the CAN channel while
all the transmissions are on (#), opening the device again (@),
then sending a small number of packets would make the driver
enter an almost infinite loop of:

[....]
[15959.853988] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853990] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853991] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853993] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853994] kvaser_usb 4-3:1.0 can0: cannot find free context
[15959.853995] kvaser_usb 4-3:1.0 can0: cannot find free context
[....]

_dragging the whole system down_ in the process due to the
excessive logging output.

Initially, this has caused random panics in the kernel due to a
buggy error recovery path.  That got fixed in an earlier commit.(%)
This patch aims at solving the root cause. -->

16 tx URBs and contexts are allocated per CAN channel per USB
device. Such URBs are protected by:

a) A simple atomic counter, up to a value of MAX_TX_URBS (16)
b) A flag in each URB context, stating if it's free
c) The fact that ndo_start_xmit calls are themselves protected
   by the networking layers higher above

After grabbing one of the tx URBs, if the driver noticed that all
of them are now taken, it stops the netif transmission queue.
Such queue is worken up again only if an acknowedgment was received
from the firmware on one of our earlier-sent frames.

Meanwhile, upon channel close (#), the driver sends a CMD_STOP_CHIP
to the firmware, effectively closing all further communication.  In
the high traffic case, the atomic counter remains at MAX_TX_URBS,
and all the URB contexts remain marked as active.  While opening
the channel again (@), it cannot send any further frames since no
more free tx URB contexts are available.

Reset all tx URB contexts upon CAN channel close.

(*) 50 parallel instances of `cangen0 -g 0 -ix`
(#) `ifconfig can0 down`
(@) `ifconfig can0 up`
(%) "can: kvaser_usb: Don't free packets when tight on URBs"

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 2e7d513..9accc82 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -1246,6 +1246,9 @@ static int kvaser_usb_close(struct net_device *netdev)
 	if (err)
 		netdev_warn(netdev, "Cannot stop device, error %d\n", err);
 
+	/* reset tx contexts */
+	kvaser_usb_unlink_tx_urbs(priv);
+
 	priv->can.state = CAN_STATE_STOPPED;
 	close_candev(priv->netdev);
 


^ permalink raw reply	[relevance 85%]

* [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-05 17:57 97%     ` [PATCH v3 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
@ 2015-01-05 18:31 36%       ` Ahmed S. Darwish
    0 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2015-01-05 18:31 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

CAN to USB interfaces sold by the Swedish manufacturer Kvaser are
divided into two major families: 'Leaf', and 'UsbcanII'.  From an
Operating System perspective, the firmware of both families behave
in a not too drastically different fashion.

This patch adds support for the UsbcanII family of devices to the
current Kvaser Leaf-only driver.

CAN frames sending, receiving, and error handling paths has been
tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It
should also work nicely with other products in the same category.

List of new devices supported by this driver update:

         - Kvaser USBcan II HS/HS
         - Kvaser USBcan II HS/LS
         - Kvaser USBcan Rugged ("USBcan Rev B")
         - Kvaser Memorator HS/HS
         - Kvaser Memorator HS/LS
         - Scania VCI2 (if you have the Kvaser logo on top)

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/Kconfig      |   8 +-
 drivers/net/can/usb/kvaser_usb.c | 618 +++++++++++++++++++++++++++++++--------
 2 files changed, 503 insertions(+), 123 deletions(-)

** V2 Changelog:
- Update Kconfig entries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixes

** V3 Changelog:
- Fix padding for the usbcan_msg_tx_acknowledge command
- Remove kvaser_usb->max_channels and the MAX_NET_DEVICES macro
- Rename commands to CMD_LEAF_xxx and CMD_USBCAN_xxx
- Apply checkpatch.pl suggestions ('net/' comments, multi-line strings, etc.)

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919..f6f5500 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -25,7 +25,7 @@ config CAN_KVASER_USB
 	tristate "Kvaser CAN/USB interface"
 	---help---
 	  This driver adds support for Kvaser CAN/USB devices like Kvaser
-	  Leaf Light.
+	  Leaf Light and Kvaser USBcan II.
 
 	  The driver provides support for the following devices:
 	    - Kvaser Leaf Light
@@ -46,6 +46,12 @@ config CAN_KVASER_USB
 	    - Kvaser USBcan R
 	    - Kvaser Leaf Light v2
 	    - Kvaser Mini PCI Express HS
+	    - Kvaser USBcan II HS/HS
+	    - Kvaser USBcan II HS/LS
+	    - Kvaser USBcan Rugged ("USBcan Rev B")
+	    - Kvaser Memorator HS/HS
+	    - Kvaser Memorator HS/LS
+	    - Scania VCI2 (if you have the Kvaser logo on top)
 
 	  If unsure, say N.
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index cc7bfc0..43b3928 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -6,10 +6,12 @@
  * Parts of this driver are based on the following:
  *  - Kvaser linux leaf driver (version 4.78)
  *  - CAN driver for esd CAN-USB/2
+ *  - Kvaser linux usbcanII driver (version 5.3)
  *
  * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
  * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * Copyright (C) 2015 Valeo Corporation
  */
 
 #include <linux/completion.h>
@@ -21,6 +23,15 @@
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
+/* Kvaser USB CAN dongles are divided into two major families:
+ * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo'
+ * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios'
+ */
+enum kvaser_usb_family {
+	KVASER_LEAF,
+	KVASER_USBCAN,
+};
+
 #define MAX_TX_URBS			16
 #define MAX_RX_URBS			4
 #define START_TIMEOUT			1000 /* msecs */
@@ -30,8 +41,9 @@
 #define RX_BUFFER_SIZE			3072
 #define CAN_USB_CLOCK			8000000
 #define MAX_NET_DEVICES			3
+#define MAX_USBCAN_NET_DEVICES		2
 
-/* Kvaser USB devices */
+/* Leaf USB devices */
 #define KVASER_VENDOR_ID		0x0bfd
 #define USB_LEAF_DEVEL_PRODUCT_ID	10
 #define USB_LEAF_LITE_PRODUCT_ID	11
@@ -55,6 +67,16 @@
 #define USB_CAN_R_PRODUCT_ID		39
 #define USB_LEAF_LITE_V2_PRODUCT_ID	288
 #define USB_MINI_PCIE_HS_PRODUCT_ID	289
+#define LEAF_PRODUCT_ID(id)		(id >= USB_LEAF_DEVEL_PRODUCT_ID && \
+					 id <= USB_MINI_PCIE_HS_PRODUCT_ID)
+
+/* USBCANII devices */
+#define USB_USBCAN_REVB_PRODUCT_ID	2
+#define USB_VCI2_PRODUCT_ID		3
+#define USB_USBCAN2_PRODUCT_ID		4
+#define USB_MEMORATOR_PRODUCT_ID	5
+#define USBCAN_PRODUCT_ID(id)		(id >= USB_USBCAN_REVB_PRODUCT_ID && \
+					 id <= USB_MEMORATOR_PRODUCT_ID)
 
 /* USB devices features */
 #define KVASER_HAS_SILENT_MODE		BIT(0)
@@ -73,7 +95,7 @@
 #define MSG_FLAG_TX_ACK			BIT(6)
 #define MSG_FLAG_TX_REQUEST		BIT(7)
 
-/* Can states */
+/* Can states (M16C CxSTRH register) */
 #define M16C_STATE_BUS_RESET		BIT(0)
 #define M16C_STATE_BUS_ERROR		BIT(4)
 #define M16C_STATE_BUS_PASSIVE		BIT(5)
@@ -98,7 +120,13 @@
 #define CMD_START_CHIP_REPLY		27
 #define CMD_STOP_CHIP			28
 #define CMD_STOP_CHIP_REPLY		29
-#define CMD_GET_CARD_INFO2		32
+#define CMD_READ_CLOCK			30
+#define CMD_READ_CLOCK_REPLY		31
+
+#define CMD_LEAF_GET_CARD_INFO2		32
+#define CMD_USBCAN_RESET_CLOCK		32
+#define CMD_USBCAN_CLOCK_OVERFLOW_EVENT	33
+
 #define CMD_GET_CARD_INFO		34
 #define CMD_GET_CARD_INFO_REPLY		35
 #define CMD_GET_SOFTWARE_INFO		38
@@ -108,8 +136,9 @@
 #define CMD_RESET_ERROR_COUNTER		49
 #define CMD_TX_ACKNOWLEDGE		50
 #define CMD_CAN_ERROR_EVENT		51
-#define CMD_USB_THROTTLE		77
-#define CMD_LOG_MESSAGE			106
+
+#define CMD_LEAF_USB_THROTTLE		77
+#define CMD_LEAF_LOG_MESSAGE		106
 
 /* error factors */
 #define M16C_EF_ACKE			BIT(0)
@@ -121,6 +150,14 @@
 #define M16C_EF_RCVE			BIT(6)
 #define M16C_EF_TRE			BIT(7)
 
+/* Only Leaf-based devices can report M16C error factors,
+ * thus define our own error status flags for USBCANII
+ */
+#define USBCAN_ERROR_STATE_NONE		0
+#define USBCAN_ERROR_STATE_TX_ERROR	BIT(0)
+#define USBCAN_ERROR_STATE_RX_ERROR	BIT(1)
+#define USBCAN_ERROR_STATE_BUSERROR	BIT(2)
+
 /* bittiming parameters */
 #define KVASER_USB_TSEG1_MIN		1
 #define KVASER_USB_TSEG1_MAX		16
@@ -137,7 +174,7 @@
 #define KVASER_CTRL_MODE_SELFRECEPTION	3
 #define KVASER_CTRL_MODE_OFF		4
 
-/* log message */
+/* Extended CAN identifier flag */
 #define KVASER_EXTENDED_FRAME		BIT(31)
 
 struct kvaser_msg_simple {
@@ -148,30 +185,55 @@ struct kvaser_msg_simple {
 struct kvaser_msg_cardinfo {
 	u8 tid;
 	u8 nchannels;
-	__le32 serial_number;
-	__le32 padding;
+	union {
+		struct {
+			__le32 serial_number;
+			__le32 padding;
+		} __packed leaf0;
+		struct {
+			__le32 serial_number_low;
+			__le32 serial_number_high;
+		} __packed usbcan0;
+	} __packed;
 	__le32 clock_resolution;
 	__le32 mfgdate;
 	u8 ean[8];
 	u8 hw_revision;
-	u8 usb_hs_mode;
-	__le16 padding2;
+	union {
+		struct {
+			u8 usb_hs_mode;
+		} __packed leaf1;
+		struct {
+			u8 padding;
+		} __packed usbcan1;
+	} __packed;
+	__le16 padding;
 } __packed;
 
 struct kvaser_msg_cardinfo2 {
 	u8 tid;
-	u8 channel;
+	u8 reserved;
 	u8 pcb_id[24];
 	__le32 oem_unlock_code;
 } __packed;
 
-struct kvaser_msg_softinfo {
+struct leaf_msg_softinfo {
 	u8 tid;
-	u8 channel;
+	u8 padding0;
 	__le32 sw_options;
 	__le32 fw_version;
 	__le16 max_outstanding_tx;
-	__le16 padding[9];
+	__le16 padding1[9];
+} __packed;
+
+struct usbcan_msg_softinfo {
+	u8 tid;
+	u8 fw_name[5];
+	__le16 max_outstanding_tx;
+	u8 padding[6];
+	__le32 fw_version;
+	__le16 checksum;
+	__le16 sw_options;
 } __packed;
 
 struct kvaser_msg_busparams {
@@ -188,36 +250,86 @@ struct kvaser_msg_tx_can {
 	u8 channel;
 	u8 tid;
 	u8 msg[14];
-	u8 padding;
-	u8 flags;
+	union {
+		struct {
+			u8 padding;
+			u8 flags;
+		} __packed leaf;
+		struct {
+			u8 flags;
+			u8 padding;
+		} __packed usbcan;
+	} __packed;
 } __packed;
 
-struct kvaser_msg_rx_can {
+struct kvaser_msg_rx_can_header {
 	u8 channel;
 	u8 flag;
+} __packed;
+
+struct leaf_msg_rx_can {
+	u8 channel;
+	u8 flag;
+
 	__le16 time[3];
 	u8 msg[14];
 } __packed;
 
-struct kvaser_msg_chip_state_event {
+struct usbcan_msg_rx_can {
+	u8 channel;
+	u8 flag;
+
+	u8 msg[14];
+	__le16 time;
+} __packed;
+
+struct leaf_msg_chip_state_event {
 	u8 tid;
 	u8 channel;
+
 	__le16 time[3];
 	u8 tx_errors_count;
 	u8 rx_errors_count;
+
+	u8 status;
+	u8 padding[3];
+} __packed;
+
+struct usbcan_msg_chip_state_event {
+	u8 tid;
+	u8 channel;
+
+	u8 tx_errors_count;
+	u8 rx_errors_count;
+	__le16 time;
+
 	u8 status;
 	u8 padding[3];
 } __packed;
 
-struct kvaser_msg_tx_acknowledge {
+struct kvaser_msg_tx_acknowledge_header {
+	u8 channel;
+	u8 tid;
+};
+
+struct leaf_msg_tx_acknowledge {
 	u8 channel;
 	u8 tid;
+
 	__le16 time[3];
 	u8 flags;
 	u8 time_offset;
 } __packed;
 
-struct kvaser_msg_error_event {
+struct usbcan_msg_tx_acknowledge {
+	u8 channel;
+	u8 tid;
+
+	__le16 time;
+	__le16 padding;
+} __packed;
+
+struct leaf_msg_error_event {
 	u8 tid;
 	u8 flags;
 	__le16 time[3];
@@ -229,6 +341,18 @@ struct kvaser_msg_error_event {
 	u8 error_factor;
 } __packed;
 
+struct usbcan_msg_error_event {
+	u8 tid;
+	u8 padding;
+	u8 tx_errors_count_ch0;
+	u8 rx_errors_count_ch0;
+	u8 tx_errors_count_ch1;
+	u8 rx_errors_count_ch1;
+	u8 status_ch0;
+	u8 status_ch1;
+	__le16 time;
+} __packed;
+
 struct kvaser_msg_ctrl_mode {
 	u8 tid;
 	u8 channel;
@@ -243,7 +367,7 @@ struct kvaser_msg_flush_queue {
 	u8 padding[3];
 } __packed;
 
-struct kvaser_msg_log_message {
+struct leaf_msg_log_message {
 	u8 channel;
 	u8 flags;
 	__le16 time[3];
@@ -260,19 +384,50 @@ struct kvaser_msg {
 		struct kvaser_msg_simple simple;
 		struct kvaser_msg_cardinfo cardinfo;
 		struct kvaser_msg_cardinfo2 cardinfo2;
-		struct kvaser_msg_softinfo softinfo;
 		struct kvaser_msg_busparams busparams;
+
+		struct kvaser_msg_rx_can_header rx_can_header;
+		struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header;
+
+		union {
+			struct leaf_msg_softinfo softinfo;
+			struct leaf_msg_rx_can rx_can;
+			struct leaf_msg_chip_state_event chip_state_event;
+			struct leaf_msg_tx_acknowledge tx_acknowledge;
+			struct leaf_msg_error_event error_event;
+			struct leaf_msg_log_message log_message;
+		} __packed leaf;
+
+		union {
+			struct usbcan_msg_softinfo softinfo;
+			struct usbcan_msg_rx_can rx_can;
+			struct usbcan_msg_chip_state_event chip_state_event;
+			struct usbcan_msg_tx_acknowledge tx_acknowledge;
+			struct usbcan_msg_error_event error_event;
+		} __packed usbcan;
+
 		struct kvaser_msg_tx_can tx_can;
-		struct kvaser_msg_rx_can rx_can;
-		struct kvaser_msg_chip_state_event chip_state_event;
-		struct kvaser_msg_tx_acknowledge tx_acknowledge;
-		struct kvaser_msg_error_event error_event;
 		struct kvaser_msg_ctrl_mode ctrl_mode;
 		struct kvaser_msg_flush_queue flush_queue;
-		struct kvaser_msg_log_message log_message;
 	} u;
 } __packed;
 
+/* Leaf/USBCAN-agnostic summary of an error event.
+ * No M16C error factors for USBCAN-based devices.
+ */
+struct kvaser_error_summary {
+	u8 channel, status, txerr, rxerr;
+	union {
+		struct {
+			u8 error_factor;
+		} leaf;
+		struct {
+			u8 other_ch_status;
+			u8 error_state;
+		} usbcan;
+	};
+};
+
 struct kvaser_usb_tx_urb_context {
 	struct kvaser_usb_net_priv *priv;
 	u32 echo_index;
@@ -288,6 +443,7 @@ struct kvaser_usb {
 
 	u32 fw_version;
 	unsigned int nchannels;
+	enum kvaser_usb_family family;
 
 	bool rxinitdone;
 	void *rxbuf[MAX_RX_URBS];
@@ -311,6 +467,7 @@ struct kvaser_usb_net_priv {
 };
 
 static const struct usb_device_id kvaser_usb_table[] = {
+	/* Leaf family IDs */
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
@@ -360,6 +517,17 @@ static const struct usb_device_id kvaser_usb_table[] = {
 		.driver_info = KVASER_HAS_TXRX_ERRORS },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
+
+	/* USBCANII family IDs */
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -463,7 +631,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
 	if (err)
 		return err;
 
-	dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
+	switch (dev->family) {
+	case KVASER_LEAF:
+		dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
+		break;
+	case KVASER_USBCAN:
+		dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -484,6 +663,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
 	dev->nchannels = msg.u.cardinfo.nchannels;
 	if (dev->nchannels > MAX_NET_DEVICES)
 		return -EINVAL;
+	if (dev->family == KVASER_USBCAN &&
+	    dev->nchannels > MAX_USBCAN_NET_DEVICES)
+		return -EINVAL;
 
 	return 0;
 }
@@ -496,8 +678,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 	struct kvaser_usb_net_priv *priv;
 	struct sk_buff *skb;
 	struct can_frame *cf;
-	u8 channel = msg->u.tx_acknowledge.channel;
-	u8 tid = msg->u.tx_acknowledge.tid;
+	u8 channel, tid;
+
+	channel = msg->u.tx_acknowledge_header.channel;
+	tid = msg->u.tx_acknowledge_header.tid;
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -615,37 +799,80 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
 		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
 }
 
-static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
-				const struct kvaser_msg *msg)
+static void kvaser_report_error_event(const struct kvaser_usb *dev,
+				      struct kvaser_error_summary *es);
+
+/* Report error to userspace iff the controller's errors counter has
+ * increased, or we're the only channel seeing the bus error state.
+ *
+ * As reported by USBCAN sheets, "the CAN controller has difficulties
+ * to tell whether an error frame arrived on channel 1 or on channel 2."
+ * Thus, error counters are compared with their earlier values to
+ * determine which channel was responsible for the error event.
+ */
+static void usbcan_report_error_if_applicable(const struct kvaser_usb *dev,
+					      struct kvaser_error_summary *es)
 {
-	struct can_frame *cf;
-	struct sk_buff *skb;
-	struct net_device_stats *stats;
 	struct kvaser_usb_net_priv *priv;
-	unsigned int new_state;
-	u8 channel, status, txerr, rxerr, error_factor;
+	int old_tx_err_count, old_rx_err_count, channel, report_error;
+
+	channel = es->channel;
+	if (channel >= dev->nchannels) {
+		dev_err(dev->udev->dev.parent,
+			"Invalid channel number (%d)\n", channel);
+		return;
+	}
+
+	priv = dev->nets[channel];
+	old_tx_err_count = priv->bec.txerr;
+	old_rx_err_count = priv->bec.rxerr;
+
+	report_error = 0;
+	if (es->txerr > old_tx_err_count) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR;
+		report_error = 1;
+	}
+	if (es->rxerr > old_rx_err_count) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR;
+		report_error = 1;
+	}
+	if ((es->status & M16C_STATE_BUS_ERROR) &&
+	    !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR;
+		report_error = 1;
+	}
+
+	if (report_error)
+		kvaser_report_error_event(dev, es);
+}
+
+/* Extract error summary from a Leaf-based device error message */
+static void leaf_extract_error_from_msg(const struct kvaser_usb *dev,
+					const struct kvaser_msg *msg)
+{
+	struct kvaser_error_summary es = { 0, };
 
 	switch (msg->id) {
 	case CMD_CAN_ERROR_EVENT:
-		channel = msg->u.error_event.channel;
-		status =  msg->u.error_event.status;
-		txerr = msg->u.error_event.tx_errors_count;
-		rxerr = msg->u.error_event.rx_errors_count;
-		error_factor = msg->u.error_event.error_factor;
+		es.channel = msg->u.leaf.error_event.channel;
+		es.status =  msg->u.leaf.error_event.status;
+		es.txerr = msg->u.leaf.error_event.tx_errors_count;
+		es.rxerr = msg->u.leaf.error_event.rx_errors_count;
+		es.leaf.error_factor = msg->u.leaf.error_event.error_factor;
 		break;
-	case CMD_LOG_MESSAGE:
-		channel = msg->u.log_message.channel;
-		status = msg->u.log_message.data[0];
-		txerr = msg->u.log_message.data[2];
-		rxerr = msg->u.log_message.data[3];
-		error_factor = msg->u.log_message.data[1];
+	case CMD_LEAF_LOG_MESSAGE:
+		es.channel = msg->u.leaf.log_message.channel;
+		es.status = msg->u.leaf.log_message.data[0];
+		es.txerr = msg->u.leaf.log_message.data[2];
+		es.rxerr = msg->u.leaf.log_message.data[3];
+		es.leaf.error_factor = msg->u.leaf.log_message.data[1];
 		break;
 	case CMD_CHIP_STATE_EVENT:
-		channel = msg->u.chip_state_event.channel;
-		status =  msg->u.chip_state_event.status;
-		txerr = msg->u.chip_state_event.tx_errors_count;
-		rxerr = msg->u.chip_state_event.rx_errors_count;
-		error_factor = 0;
+		es.channel = msg->u.leaf.chip_state_event.channel;
+		es.status =  msg->u.leaf.chip_state_event.status;
+		es.txerr = msg->u.leaf.chip_state_event.tx_errors_count;
+		es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count;
+		es.leaf.error_factor = 0;
 		break;
 	default:
 		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
@@ -653,16 +880,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		return;
 	}
 
-	if (channel >= dev->nchannels) {
+	kvaser_report_error_event(dev, &es);
+}
+
+/* Extract error summary from a USBCANII-based device error message */
+static void usbcan_extract_error_from_msg(const struct kvaser_usb *dev,
+					  const struct kvaser_msg *msg)
+{
+	struct kvaser_error_summary es = { 0, };
+
+	switch (msg->id) {
+	/* Sometimes errors are sent as unsolicited chip state events */
+	case CMD_CHIP_STATE_EVENT:
+		es.channel = msg->u.usbcan.chip_state_event.channel;
+		es.status =  msg->u.usbcan.chip_state_event.status;
+		es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count;
+		es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count;
+		usbcan_report_error_if_applicable(dev, &es);
+		break;
+
+	case CMD_CAN_ERROR_EVENT:
+		es.channel = 0;
+		es.status = msg->u.usbcan.error_event.status_ch0;
+		es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0;
+		es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0;
+		es.usbcan.other_ch_status =
+			msg->u.usbcan.error_event.status_ch1;
+		usbcan_report_error_if_applicable(dev, &es);
+
+		/* For error events, the USBCAN firmware does not support
+		 * more than 2 channels: ch0, and ch1.
+		 */
+		if (dev->nchannels > 1) {
+			es.channel = 1;
+			es.status = msg->u.usbcan.error_event.status_ch1;
+			es.txerr =
+				msg->u.usbcan.error_event.tx_errors_count_ch1;
+			es.rxerr =
+				msg->u.usbcan.error_event.rx_errors_count_ch1;
+			es.usbcan.other_ch_status =
+				msg->u.usbcan.error_event.status_ch0;
+			usbcan_report_error_if_applicable(dev, &es);
+		}
+		break;
+
+	default:
+		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
+			msg->id);
+	}
+}
+
+static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
+				const struct kvaser_msg *msg)
+{
+	switch (dev->family) {
+	case KVASER_LEAF:
+		leaf_extract_error_from_msg(dev, msg);
+		break;
+	case KVASER_USBCAN:
+		usbcan_extract_error_from_msg(dev, msg);
+		break;
+	default:
 		dev_err(dev->udev->dev.parent,
-			"Invalid channel number (%d)\n", channel);
+			"Invalid device family (%d)\n", dev->family);
 		return;
 	}
+}
 
-	priv = dev->nets[channel];
+static void kvaser_report_error_event(const struct kvaser_usb *dev,
+				      struct kvaser_error_summary *es)
+{
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	struct net_device_stats *stats;
+	struct kvaser_usb_net_priv *priv;
+	unsigned int new_state;
+
+	if (es->channel >= dev->nchannels) {
+		dev_err(dev->udev->dev.parent,
+			"Invalid channel number (%d)\n", es->channel);
+		return;
+	}
+
+	priv = dev->nets[es->channel];
 	stats = &priv->netdev->stats;
 
-	if (status & M16C_STATE_BUS_RESET) {
+	if (es->status & M16C_STATE_BUS_RESET) {
 		kvaser_usb_unlink_tx_urbs(priv);
 		return;
 	}
@@ -675,9 +978,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
 	new_state = priv->can.state;
 
-	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
+	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
 
-	if (status & M16C_STATE_BUS_OFF) {
+	if (es->status & M16C_STATE_BUS_OFF) {
 		cf->can_id |= CAN_ERR_BUSOFF;
 
 		priv->can.can_stats.bus_off++;
@@ -687,12 +990,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		netif_carrier_off(priv->netdev);
 
 		new_state = CAN_STATE_BUS_OFF;
-	} else if (status & M16C_STATE_BUS_PASSIVE) {
+	} else if (es->status & M16C_STATE_BUS_PASSIVE) {
 		if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
 			cf->can_id |= CAN_ERR_CRTL;
 
-			if (txerr || rxerr)
-				cf->data[1] = (txerr > rxerr)
+			if (es->txerr || es->rxerr)
+				cf->data[1] = (es->txerr > es->rxerr)
 						? CAN_ERR_CRTL_TX_PASSIVE
 						: CAN_ERR_CRTL_RX_PASSIVE;
 			else
@@ -703,13 +1006,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 
 		new_state = CAN_STATE_ERROR_PASSIVE;
-	}
-
-	if (status == M16C_STATE_BUS_ERROR) {
+	} else if (es->status & M16C_STATE_BUS_ERROR) {
 		if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
-		    ((txerr >= 96) || (rxerr >= 96))) {
+		    ((es->txerr >= 96) || (es->rxerr >= 96))) {
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (txerr > rxerr)
+			cf->data[1] = (es->txerr > es->rxerr)
 					? CAN_ERR_CRTL_TX_WARNING
 					: CAN_ERR_CRTL_RX_WARNING;
 
@@ -723,7 +1024,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 	}
 
-	if (!status) {
+	if (!es->status) {
 		cf->can_id |= CAN_ERR_PROT;
 		cf->data[2] = CAN_ERR_PROT_ACTIVE;
 
@@ -739,34 +1040,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		priv->can.can_stats.restarts++;
 	}
 
-	if (error_factor) {
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-
-		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-
-		if (error_factor & M16C_EF_ACKE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
-		if (error_factor & M16C_EF_CRCE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-					CAN_ERR_PROT_LOC_CRC_DEL);
-		if (error_factor & M16C_EF_FORME)
-			cf->data[2] |= CAN_ERR_PROT_FORM;
-		if (error_factor & M16C_EF_STFE)
-			cf->data[2] |= CAN_ERR_PROT_STUFF;
-		if (error_factor & M16C_EF_BITE0)
-			cf->data[2] |= CAN_ERR_PROT_BIT0;
-		if (error_factor & M16C_EF_BITE1)
-			cf->data[2] |= CAN_ERR_PROT_BIT1;
-		if (error_factor & M16C_EF_TRE)
-			cf->data[2] |= CAN_ERR_PROT_TX;
+	switch (dev->family) {
+	case KVASER_LEAF:
+		if (es->leaf.error_factor) {
+			priv->can.can_stats.bus_error++;
+			stats->rx_errors++;
+
+			cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+
+			if (es->leaf.error_factor & M16C_EF_ACKE)
+				cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
+			if (es->leaf.error_factor & M16C_EF_CRCE)
+				cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+						CAN_ERR_PROT_LOC_CRC_DEL);
+			if (es->leaf.error_factor & M16C_EF_FORME)
+				cf->data[2] |= CAN_ERR_PROT_FORM;
+			if (es->leaf.error_factor & M16C_EF_STFE)
+				cf->data[2] |= CAN_ERR_PROT_STUFF;
+			if (es->leaf.error_factor & M16C_EF_BITE0)
+				cf->data[2] |= CAN_ERR_PROT_BIT0;
+			if (es->leaf.error_factor & M16C_EF_BITE1)
+				cf->data[2] |= CAN_ERR_PROT_BIT1;
+			if (es->leaf.error_factor & M16C_EF_TRE)
+				cf->data[2] |= CAN_ERR_PROT_TX;
+		}
+		break;
+	case KVASER_USBCAN:
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
+			stats->tx_errors++;
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
+			stats->rx_errors++;
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
+			priv->can.can_stats.bus_error++;
+			cf->can_id |= CAN_ERR_BUSERROR;
+		}
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		goto err;
 	}
 
-	cf->data[6] = txerr;
-	cf->data[7] = rxerr;
+	cf->data[6] = es->txerr;
+	cf->data[7] = es->rxerr;
 
-	priv->bec.txerr = txerr;
-	priv->bec.rxerr = rxerr;
+	priv->bec.txerr = es->txerr;
+	priv->bec.rxerr = es->rxerr;
 
 	priv->can.state = new_state;
 
@@ -774,6 +1093,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
+
+	return;
+
+err:
+	dev_kfree_skb(skb);
 }
 
 static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -783,16 +1107,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 	struct sk_buff *skb;
 	struct net_device_stats *stats = &priv->netdev->stats;
 
-	if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+	if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
 					 MSG_FLAG_NERR)) {
 		netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
-			   msg->u.rx_can.flag);
+			   msg->u.rx_can_header.flag);
 
 		stats->rx_errors++;
 		return;
 	}
 
-	if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
+	if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) {
 		skb = alloc_can_err_skb(priv->netdev, &cf);
 		if (!skb) {
 			stats->rx_dropped++;
@@ -819,7 +1143,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 	struct can_frame *cf;
 	struct sk_buff *skb;
 	struct net_device_stats *stats;
-	u8 channel = msg->u.rx_can.channel;
+	u8 channel = msg->u.rx_can_header.channel;
+	const u8 *rx_msg;
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -830,19 +1155,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 	priv = dev->nets[channel];
 	stats = &priv->netdev->stats;
 
-	if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) &&
-	    (msg->id == CMD_LOG_MESSAGE)) {
+	if ((msg->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
+	    (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE)) {
 		kvaser_usb_rx_error(dev, msg);
 		return;
-	} else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
-					 MSG_FLAG_NERR |
-					 MSG_FLAG_OVERRUN)) {
+	} else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
+						MSG_FLAG_NERR |
+						MSG_FLAG_OVERRUN)) {
 		kvaser_usb_rx_can_err(priv, msg);
 		return;
-	} else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
+	} else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) {
 		netdev_warn(priv->netdev,
 			    "Unhandled frame (flags: 0x%02x)",
-			    msg->u.rx_can.flag);
+			    msg->u.rx_can_header.flag);
+		return;
+	}
+
+	switch (dev->family) {
+	case KVASER_LEAF:
+		rx_msg = msg->u.leaf.rx_can.msg;
+		break;
+	case KVASER_USBCAN:
+		rx_msg = msg->u.usbcan.rx_can.msg;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
 		return;
 	}
 
@@ -852,38 +1190,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 		return;
 	}
 
-	if (msg->id == CMD_LOG_MESSAGE) {
-		cf->can_id = le32_to_cpu(msg->u.log_message.id);
+	if (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE) {
+		cf->can_id = le32_to_cpu(msg->u.leaf.log_message.id);
 		if (cf->can_id & KVASER_EXTENDED_FRAME)
 			cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
 		else
 			cf->can_id &= CAN_SFF_MASK;
 
-		cf->can_dlc = get_can_dlc(msg->u.log_message.dlc);
+		cf->can_dlc = get_can_dlc(msg->u.leaf.log_message.dlc);
 
-		if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME)
+		if (msg->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME)
 			cf->can_id |= CAN_RTR_FLAG;
 		else
-			memcpy(cf->data, &msg->u.log_message.data,
+			memcpy(cf->data, &msg->u.leaf.log_message.data,
 			       cf->can_dlc);
 	} else {
-		cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
-			     (msg->u.rx_can.msg[1] & 0x3f);
+		cf->can_id = ((rx_msg[0] & 0x1f) << 6) | (rx_msg[1] & 0x3f);
 
 		if (msg->id == CMD_RX_EXT_MESSAGE) {
 			cf->can_id <<= 18;
-			cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
-				      ((msg->u.rx_can.msg[3] & 0xff) << 6) |
-				      (msg->u.rx_can.msg[4] & 0x3f);
+			cf->can_id |= ((rx_msg[2] & 0x0f) << 14) |
+				      ((rx_msg[3] & 0xff) << 6) |
+				      (rx_msg[4] & 0x3f);
 			cf->can_id |= CAN_EFF_FLAG;
 		}
 
-		cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+		cf->can_dlc = get_can_dlc(rx_msg[5]);
 
-		if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
+		if (msg->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME)
 			cf->can_id |= CAN_RTR_FLAG;
 		else
-			memcpy(cf->data, &msg->u.rx_can.msg[6],
+			memcpy(cf->data, &rx_msg[6],
 			       cf->can_dlc);
 	}
 
@@ -947,7 +1284,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
 
 	case CMD_RX_STD_MESSAGE:
 	case CMD_RX_EXT_MESSAGE:
-	case CMD_LOG_MESSAGE:
+		kvaser_usb_rx_can_msg(dev, msg);
+		break;
+
+	case CMD_LEAF_LOG_MESSAGE:
+		if (dev->family != KVASER_LEAF)
+			goto warn;
 		kvaser_usb_rx_can_msg(dev, msg);
 		break;
 
@@ -960,8 +1302,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
 		kvaser_usb_tx_acknowledge(dev, msg);
 		break;
 
+	/* Ignored messages */
+	case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
+		if (dev->family != KVASER_USBCAN)
+			goto warn;
+		break;
+
 	default:
-		dev_warn(dev->udev->dev.parent,
+warn:		dev_warn(dev->udev->dev.parent,
 			 "Unhandled message (%d)\n", msg->id);
 		break;
 	}
@@ -1181,7 +1529,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
 				  dev->rxbuf[i],
 				  dev->rxbuf_dma[i]);
 
-	for (i = 0; i < MAX_NET_DEVICES; i++) {
+	for (i = 0; i < dev->nchannels; i++) {
 		struct kvaser_usb_net_priv *priv = dev->nets[i];
 
 		if (priv)
@@ -1289,6 +1637,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	struct kvaser_msg *msg;
 	int i, err;
 	int ret = NETDEV_TX_OK;
+	uint8_t *msg_tx_can_flags;
 
 	if (can_dropped_invalid_skb(netdev, skb))
 		return NETDEV_TX_OK;
@@ -1310,9 +1659,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 
 	msg = buf;
 	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
-	msg->u.tx_can.flags = 0;
 	msg->u.tx_can.channel = priv->channel;
 
+	switch (dev->family) {
+	case KVASER_LEAF:
+		msg_tx_can_flags = &msg->u.tx_can.leaf.flags;
+		break;
+	case KVASER_USBCAN:
+		msg_tx_can_flags = &msg->u.tx_can.usbcan.flags;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		goto releasebuf;
+	}
+
+	*msg_tx_can_flags = 0;
+
 	if (cf->can_id & CAN_EFF_FLAG) {
 		msg->id = CMD_TX_EXT_MESSAGE;
 		msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
@@ -1330,7 +1693,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
 
 	if (cf->can_id & CAN_RTR_FLAG)
-		msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
+		*msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
 
 	for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
 		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
@@ -1599,6 +1962,17 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 	if (!dev)
 		return -ENOMEM;
 
+	if (LEAF_PRODUCT_ID(id->idProduct)) {
+		dev->family = KVASER_LEAF;
+	} else if (USBCAN_PRODUCT_ID(id->idProduct)) {
+		dev->family = KVASER_USBCAN;
+	} else {
+		dev_err(&intf->dev,
+			"Product ID (%d) does not belong to any known Kvaser USB family",
+			id->idProduct);
+		return -ENODEV;
+	}
+
 	err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
 	if (err) {
 		dev_err(&intf->dev, "Cannot get usb endpoint(s)");



^ permalink raw reply	[relevance 36%]

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  @ 2015-01-08 15:19 76%           ` Ahmed S. Darwish
    2015-01-09  3:06 99%           ` Ahmed S. Darwish
  1 sibling, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2015-01-08 15:19 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi Marc,

On Thu, Jan 08, 2015 at 12:53:37PM +0100, Marc Kleine-Budde wrote:
> On 01/05/2015 07:31 PM, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
[...]
> > +/* Kvaser USB CAN dongles are divided into two major families:
> > + * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo'
> > + * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios'
> > + */
> > +enum kvaser_usb_family {
> > +	KVASER_LEAF,
> > +	KVASER_USBCAN,
> > +};
> > +
> >  #define MAX_TX_URBS			16
> >  #define MAX_RX_URBS			4
> >  #define START_TIMEOUT			1000 /* msecs */
> > @@ -30,8 +41,9 @@
> >  #define RX_BUFFER_SIZE			3072
> >  #define CAN_USB_CLOCK			8000000
> >  #define MAX_NET_DEVICES			3
> > +#define MAX_USBCAN_NET_DEVICES		2
> >  
> > -/* Kvaser USB devices */
> > +/* Leaf USB devices */
> >  #define KVASER_VENDOR_ID		0x0bfd
> >  #define USB_LEAF_DEVEL_PRODUCT_ID	10
> >  #define USB_LEAF_LITE_PRODUCT_ID	11
> > @@ -55,6 +67,16 @@
> >  #define USB_CAN_R_PRODUCT_ID		39
> >  #define USB_LEAF_LITE_V2_PRODUCT_ID	288
> >  #define USB_MINI_PCIE_HS_PRODUCT_ID	289
> > +#define LEAF_PRODUCT_ID(id)		(id >= USB_LEAF_DEVEL_PRODUCT_ID && \
> > +					 id <= USB_MINI_PCIE_HS_PRODUCT_ID)
> 
> Can you please convert both *_PRODUCT_ID() macros into static inline
> bool functions.
> 

Will do.

[...]
> >  MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
> > @@ -463,7 +631,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
> >  	if (err)
> >  		return err;
> >  
> > -	dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
> > +	switch (dev->family) {
> > +	case KVASER_LEAF:
> > +		dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
> > +		break;
> > +	case KVASER_USBCAN:
> > +		dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
> > +		break;
> > +	default:
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid device family (%d)\n", dev->family);
> > +		return -EINVAL;
> 
> The default case should not happen. I think you can remove it.
> 

It's true, it _should_ never happen. But I only add such checks if
the follow-up code critically depends on a certain `dev->family`
behavior. So it's kind of a defensive check against any possible
bug in driver or memory.

What do you think?

> > +	}
> >  
> >  	return 0;
> >  }
> > @@ -484,6 +663,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
> >  	dev->nchannels = msg.u.cardinfo.nchannels;
> >  	if (dev->nchannels > MAX_NET_DEVICES)
> >  		return -EINVAL;
> > +	if (dev->family == KVASER_USBCAN &&
> > +	    dev->nchannels > MAX_USBCAN_NET_DEVICES)
> > +		return -EINVAL;
> 
> Nitpick, as the new "if" also does a test on nchannels, why no extend
> the existing "if" with an "||"?
> 

Will do.

> >  
> >  	return 0;
> >  }
> > @@ -496,8 +678,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
> >  	struct kvaser_usb_net_priv *priv;
> >  	struct sk_buff *skb;
> >  	struct can_frame *cf;
> > -	u8 channel = msg->u.tx_acknowledge.channel;
> > -	u8 tid = msg->u.tx_acknowledge.tid;
> > +	u8 channel, tid;
> > +
> > +	channel = msg->u.tx_acknowledge_header.channel;
> > +	tid = msg->u.tx_acknowledge_header.tid;
> >  
> >  	if (channel >= dev->nchannels) {
> >  		dev_err(dev->udev->dev.parent,
> > @@ -615,37 +799,80 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
> >  		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> >  }
> >  
> > -static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> > -				const struct kvaser_msg *msg)
> > +static void kvaser_report_error_event(const struct kvaser_usb *dev,
> > +				      struct kvaser_error_summary *es);
> 
> Please rearange your code that forward declarations are not needed (if
> possible - I haven't checked, though).
> 

I originally did it that way, but it completely messed up with the
patch if I do such rearrangement. A huge block of code gets removed
at top of the patch, and it got added again at the end, making the
actual important lines changed _within_ such big block non-apparent.

Maybe I should do the re-arrangement in a follow-up patch?

> > +
> > +/* Report error to userspace iff the controller's errors counter has
> > + * increased, or we're the only channel seeing the bus error state.
> > + *
> > + * As reported by USBCAN sheets, "the CAN controller has difficulties
> > + * to tell whether an error frame arrived on channel 1 or on channel 2."
> > + * Thus, error counters are compared with their earlier values to
> > + * determine which channel was responsible for the error event.
> 
> Your code doesn't match this comment. You compare the error counters
> against the old values to tell if it's a rx or tx error, the channel
> information from the struct kvaser_error_summary is used directly.
> 

Hmmm, good catch, upon a second look, the code looks a bit deceiving.
The comments, meanwhile, are taken verbatim from the Kvaser sheets:

  http://www.kvaser.com/canlib-webhelp/page_hardware_specific_can_controllers.html
  Archived at http://www.webcitation.org/6VQd87jIA

So, what happens is that the firmware does not tell us whether the
received error event is for ch0 or ch1. But it gives us the (possibly
new) error counters for both of them:

struct usbcan_msg_error_event {
        [..]
        u8 tx_errors_count_ch0;
        u8 rx_errors_count_ch0;
        u8 tx_errors_count_ch1;
        u8 rx_errors_count_ch1;
	[..]
} __packed;

We loop over each channel, and report an error to userspace if extra
errors were spotted for such channel.

kvaser_error_summary is not a firmware command or response. Since
the wire format for an error event differs between Leaf and Usbcan,
it's just our way to summarize an error whether it's from any of
them, and this is where the conflict stems from:

- If it's a Leaf-device, `error_summary->channel' is the excat
channel reported by the firmware
- If it's a Usbcan device, `error_summary->channel' is just a mark
to check the error counters for such a channel and report error
to userspace iff they've increased.

Thus the raison d'etre for `error_summary' struct is to share
the error handling code between Leaf and UsbcanII devices since
it's quite similar.

So to clear up this conflict, I suggest the following error_summary
layout:

struct kvaser_error_summary {
       union {
                struct {
                       u8 channel;
                } leaf;
                struct {
                       u8 possible_channel;
                } usbcan;
       };
       /* Rest of layout is left as-is */
}

This way, it's clear that in case of Usbcan, channel is not final
and we need further work to do. What do you think?

(BTW, any better name than "kvaser_error_summary"? It conflicts a
little bit with the namespace used for the packed wire format
structures "kvaser_*")

> > + */
> > +static void usbcan_report_error_if_applicable(const struct kvaser_usb *dev,
> > +					      struct kvaser_error_summary *es)
> 
> Nitpick: can you please add a "kvaser_" prefix to the all usbcan_* and
> leaf_* functions.
> 

Will do.

> >  {
> > -	struct can_frame *cf;
> > -	struct sk_buff *skb;
> > -	struct net_device_stats *stats;
> >  	struct kvaser_usb_net_priv *priv;
> > -	unsigned int new_state;
> > -	u8 channel, status, txerr, rxerr, error_factor;
> > +	int old_tx_err_count, old_rx_err_count, channel, report_error;
> 
> bool report_error;
> 

Will do.

> > +
> > +	channel = es->channel;
> > +	if (channel >= dev->nchannels) {
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid channel number (%d)\n", channel);
> > +		return;
> > +	}
> > +
> > +	priv = dev->nets[channel];
> > +	old_tx_err_count = priv->bec.txerr;
> > +	old_rx_err_count = priv->bec.rxerr;
> 
> Why do you make a copy of priv->bec, AFAICS you can use
> priv->bec.{r,t}xerr directly?
> 

Initially, just for clarity, as I was not used yet to socketCAN
structures ;-) will remove it in the next submission.

> > +
> > +	report_error = 0;
> > +	if (es->txerr > old_tx_err_count) {
> > +		es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR;
> > +		report_error = 1;
> > +	}
> > +	if (es->rxerr > old_rx_err_count) {
> > +		es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR;
> > +		report_error = 1;
> > +	}
> > +	if ((es->status & M16C_STATE_BUS_ERROR) &&
> > +	    !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) {
> > +		es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR;
> > +		report_error = 1;
> > +	}
> > +
> > +	if (report_error)
> > +		kvaser_report_error_event(dev, es);
> > +}
> > +
> > +/* Extract error summary from a Leaf-based device error message */
> > +static void leaf_extract_error_from_msg(const struct kvaser_usb *dev,
> > +					const struct kvaser_msg *msg)
> > +{
> > +	struct kvaser_error_summary es = { 0, };
> 
> IIRC "es = { };" should be sufficient.
> 

Correct, will do.

> >  
> >  	switch (msg->id) {
> >  	case CMD_CAN_ERROR_EVENT:
> > -		channel = msg->u.error_event.channel;
> > -		status =  msg->u.error_event.status;
> > -		txerr = msg->u.error_event.tx_errors_count;
> > -		rxerr = msg->u.error_event.rx_errors_count;
> > -		error_factor = msg->u.error_event.error_factor;
> > +		es.channel = msg->u.leaf.error_event.channel;
> > +		es.status =  msg->u.leaf.error_event.status;
> > +		es.txerr = msg->u.leaf.error_event.tx_errors_count;
> > +		es.rxerr = msg->u.leaf.error_event.rx_errors_count;
> > +		es.leaf.error_factor = msg->u.leaf.error_event.error_factor;
> >  		break;
> > -	case CMD_LOG_MESSAGE:
> > -		channel = msg->u.log_message.channel;
> > -		status = msg->u.log_message.data[0];
> > -		txerr = msg->u.log_message.data[2];
> > -		rxerr = msg->u.log_message.data[3];
> > -		error_factor = msg->u.log_message.data[1];
> > +	case CMD_LEAF_LOG_MESSAGE:
> > +		es.channel = msg->u.leaf.log_message.channel;
> > +		es.status = msg->u.leaf.log_message.data[0];
> > +		es.txerr = msg->u.leaf.log_message.data[2];
> > +		es.rxerr = msg->u.leaf.log_message.data[3];
> > +		es.leaf.error_factor = msg->u.leaf.log_message.data[1];
> >  		break;
> >  	case CMD_CHIP_STATE_EVENT:
> > -		channel = msg->u.chip_state_event.channel;
> > -		status =  msg->u.chip_state_event.status;
> > -		txerr = msg->u.chip_state_event.tx_errors_count;
> > -		rxerr = msg->u.chip_state_event.rx_errors_count;
> > -		error_factor = 0;
> > +		es.channel = msg->u.leaf.chip_state_event.channel;
> > +		es.status =  msg->u.leaf.chip_state_event.status;
> > +		es.txerr = msg->u.leaf.chip_state_event.tx_errors_count;
> > +		es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count;
> > +		es.leaf.error_factor = 0;
> >  		break;
> >  	default:
> >  		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
> > @@ -653,16 +880,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  		return;
> >  	}
> >  
> > -	if (channel >= dev->nchannels) {
> > +	kvaser_report_error_event(dev, &es);
> > +}
> > +
> > +/* Extract error summary from a USBCANII-based device error message */
> > +static void usbcan_extract_error_from_msg(const struct kvaser_usb *dev,
> > +					  const struct kvaser_msg *msg)
> > +{
> > +	struct kvaser_error_summary es = { 0, };
> 
> same here.
> 

Ditto.

> > +
> > +	switch (msg->id) {
> > +	/* Sometimes errors are sent as unsolicited chip state events */
> > +	case CMD_CHIP_STATE_EVENT:
> > +		es.channel = msg->u.usbcan.chip_state_event.channel;
> > +		es.status =  msg->u.usbcan.chip_state_event.status;
> > +		es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count;
> > +		es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count;
> > +		usbcan_report_error_if_applicable(dev, &es);
> > +		break;
> > +
> > +	case CMD_CAN_ERROR_EVENT:
> > +		es.channel = 0;
> > +		es.status = msg->u.usbcan.error_event.status_ch0;
> > +		es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0;
> > +		es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0;
> > +		es.usbcan.other_ch_status =
> > +			msg->u.usbcan.error_event.status_ch1;
> > +		usbcan_report_error_if_applicable(dev, &es);
> > +
> > +		/* For error events, the USBCAN firmware does not support
> > +		 * more than 2 channels: ch0, and ch1.
> > +		 */
> > +		if (dev->nchannels > 1) {
> > +			es.channel = 1;
> 
> Why is channel == 1 if the device has more than 1 channel?
> 

This is related to the "kvaser_error_summary" discussion above
where "channel" is only a suggestion for checking the error
counters.

If the Usbcan device has only one channel, then there's no need
to check if the "tx_errors_count_ch1", "rx_errors_count_ch1" has
increased or not. Their values are undefined.

> > +			es.status = msg->u.usbcan.error_event.status_ch1;
> > +			es.txerr =
> > +				msg->u.usbcan.error_event.tx_errors_count_ch1;
> > +			es.rxerr =
> > +				msg->u.usbcan.error_event.rx_errors_count_ch1;
> > +			es.usbcan.other_ch_status =
> > +				msg->u.usbcan.error_event.status_ch0;
> > +			usbcan_report_error_if_applicable(dev, &es);
> > +		}
> > +		break;
> > +
> > +	default:
> > +		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
> > +			msg->id);
> > +	}
> > +}
> > +
> > +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> > +				const struct kvaser_msg *msg)
> > +{
> > +	switch (dev->family) {
> > +	case KVASER_LEAF:
> > +		leaf_extract_error_from_msg(dev, msg);
> > +		break;
> > +	case KVASER_USBCAN:
> > +		usbcan_extract_error_from_msg(dev, msg);
> > +		break;
> > +	default:
> should not happen.

Yes. As in above, will wait your input in this regarding the checks
being defensive.

[...]
> > +	case KVASER_USBCAN:
> > +		if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
> > +			stats->tx_errors++;
> > +		if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
> > +			stats->rx_errors++;
> > +		if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
> > +			priv->can.can_stats.bus_error++;
> > +			cf->can_id |= CAN_ERR_BUSERROR;
> > +		}
> > +		break;
> > +	default:
> > +		dev_err(dev->udev->dev.parent,
> > +			"Invalid device family (%d)\n", dev->family);
> > +		goto err;
> 
> should not happen.
> 

Ditto.

> >  	}
> >  
> > -	cf->data[6] = txerr;
> > -	cf->data[7] = rxerr;
> > +	cf->data[6] = es->txerr;
> > +	cf->data[7] = es->rxerr;
> >  
> > -	priv->bec.txerr = txerr;
> > -	priv->bec.rxerr = rxerr;
> > +	priv->bec.txerr = es->txerr;
> > +	priv->bec.rxerr = es->rxerr;
> >  
> >  	priv->can.state = new_state;
> >  
> > @@ -774,6 +1093,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >  
> >  	stats->rx_packets++;
> >  	stats->rx_bytes += cf->can_dlc;
> > +
> > +	return;
> > +
> > +err:
> > +	dev_kfree_skb(skb);
> >  }
> >  
> >  static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
> > @@ -783,16 +1107,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
> >  	struct sk_buff *skb;
> >  	struct net_device_stats *stats = &priv->netdev->stats;
> >  
> > -	if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
> > +	if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
> >  					 MSG_FLAG_NERR)) {
> >  		netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
> > -			   msg->u.rx_can.flag);
> > +			   msg->u.rx_can_header.flag);
> >  
> >  		stats->rx_errors++;
> >  		return;
> >  	}
> >  
> > -	if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
> > +	if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) {
> >  		skb = alloc_can_err_skb(priv->netdev, &cf);
> > 		if (!skb) {
> > 			stats->rx_dropped++;
> > 			return;
> > 		}
> 
> Can you prepare a (seperate) patch that does the stats, even in case of OOM here. Same for kvaser_report_error_event()

Sure.

In kvaser_report_error_event() though, isn't it a little bit tricky?
Specially in fragments as in below:

        switch (dev->family) {
        case KVASER_LEAF:
                if (es->leaf.error_factor) {
                        priv->can.can_stats.bus_error++;
                        stats->rx_errors++;

                        cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
                        [...]
                }
                break;
        case KVASER_USBCAN:
                if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
                        stats->tx_errors++;
                if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
                        stats->rx_errors++;
                if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
                        priv->can.can_stats.bus_error++;
                        cf->can_id |= CAN_ERR_BUSERROR;
                }
                break;
        }

IMHO, there will be some duplication of the above fragment. Once
to handle "stats->*", and once to handle packet-related "cf->*" stuff.
Also in the Usbcan case, it will clutter the error_state checks in
different places.

> 
> > 
> > 		cf->can_id |= CAN_ERR_CRTL;
> > 		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
> > 
> > 		stats->rx_over_errors++;
> > 		stats->rx_errors++;
> > 
> > 		netif_rx(skb);
> > 
> > 		stats->rx_packets++;
> > 		stats->rx_bytes += cf->can_dlc;
> 
> Another patch would be not to touch cf after netif_rx(), please move the stats handling before calling netif_rx(). Same applies to the kvaser_usb_rx_can_msg() function.
> 

Indeed, these can be totally bogus values after netif_rx().
I'll introduce this as a new patch in a new series.

Thanks for your review!

Regards,
Darwish

^ permalink raw reply	[relevance 76%]

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
    2015-01-08 15:19 76%           ` Ahmed S. Darwish
@ 2015-01-09  3:06 99%           ` Ahmed S. Darwish
  1 sibling, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2015-01-09  3:06 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

On Thu, Jan 08, 2015 at 12:53:37PM +0100, Marc Kleine-Budde wrote:
> On 01/05/2015 07:31 PM, Ahmed S. Darwish wrote:
> > 

[...]

> > 
> > 		cf->can_id |= CAN_ERR_CRTL;
> > 		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
> > 
> > 		stats->rx_over_errors++;
> > 		stats->rx_errors++;
> > 
> > 		netif_rx(skb);
> > 
> > 		stats->rx_packets++;
> > 		stats->rx_bytes += cf->can_dlc;
> 
> Another patch would be not to touch cf after netif_rx(), please move the stats handling before calling netif_rx(). Same applies to the kvaser_usb_rx_can_msg() function.
> 

BTW, is it guaranteed from the SocketCAN stack that netif_rx()
will never return NET_RX_DROPPED? Because if no guarantee
exists, I guess below fragment cannot be completely correct?

        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
        netif_rx(skb);

On the other hand, I don't see evan a single CAN driver checking
netif_rx() return value, so maybe such a check is an overkill...

Thanks,
Darwish

^ permalink raw reply	[relevance 99%]

* Re: Fix for synchronization issue in IPV6 implementation in smack module(v3.18)
  @ 2015-01-09 13:42 94% ` Ahmed S. Darwish
  0 siblings, 0 replies; 200+ results
From: Ahmed S. Darwish @ 2015-01-09 13:42 UTC (permalink / raw)
  To: Vishal Goel; +Cc: linux-kernel, linux-security-module, casey

Hi Vishal,

On Thu, Jan 08, 2015 at 10:11:52PM +0530, Vishal Goel wrote:
>  [PATCH] This patch fixes the synchronization issue in IPv6
>  implementation. Previously there was no synchronization mechanism used while
>  accessing(adding/reading/deletion) smk_ipv6_port_list. It could be possible
>  that when one thread is reading the list, at the same time another thread is
>  adding/deleting in the list.So it is possible that reader thread will read
>  the inaccurate or incomplete list. So to make sure that reader thread will
>  read the accurate list, rcu mechanism has been used while accessing the
>  list.RCU allows readers to access a data structure even when it is in the
>  process of being updated
> 
> Signed-off-by: Vishal Goel <vishal.goel@samsung.com>
>             Himanshu Shukla <himanshu.sh@samsung.com>

The legality of your patches are blurry. You're sending from
a personal email, while having Signed-off-by signatures by your
employer.

You **really** need to add a "From: XXX@samsung.com" header on
the very first line of your emails if this is a sponsored work.
Kindly check Documentation/SubmittingPatches for further details.

Beside the above:

- Your patches are not applicable to the tree since they're
  white-spaces mangled. You're using Gmail's web interface, which
  is well known at converting tabs to white-spaces. Check
  Documentation/email-clients.txt for further details.

- Please fix you Subject line. Make it something in the form of:
  [PATCH 1/3] smack: Fix xxx

- No need for "[PATCH]" in the commit log body, only in the
  subject line.

- Please make the commit message more comprehensible. Check
  the kernel git log history for good examples. A grammar
  check will also be nice; there are a number of free good
  tools on the web.

- Add "Signed-off-by" headers for each developer. In the patch
  above, you'll need _two_ "Signed-off-by" lines.

- You're sending multiple related patches, but posting each one
  in its own thread. This will make it very very hard for review,
  especially in a very busy list like LKML. Please send related
  patches in an "email thread", with clear sequence numbers.

  (e.g., your follow-up patch titled as "In Ref to previous 3
  patches:Fix for synchronization..." is completely bogus.)

Happy kernel coding :-)

Regards,
Darwish

> ---
>  security/smack/smack_lsm.c | 21 +++++++++++++++------
>  1 file changed, 15 insertions(+), 6 deletions(-)
> 
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index d515ec2..b3427ee 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -52,6 +52,7 @@
>  #define SMK_RECEIVING  1
>  #define SMK_SENDING    2
> 
> +DEFINE_MUTEX(smack_ipv6_lock);
>  LIST_HEAD(smk_ipv6_port_list);
> 
>  #ifdef CONFIG_SECURITY_SMACK_BRINGUP
> @@ -2232,17 +2233,20 @@ static void smk_ipv6_port_label(struct socket
> *sock, struct sockaddr *address)
>              * on the bound socket. Take the changes to the port
>              * as well.
>              */
> -           list_for_each_entry(spp, &smk_ipv6_port_list, list) {
> +           rcu_read_lock();
> +           list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
>                   if (sk != spp->smk_sock)
>                         continue;
>                   spp->smk_in = ssp->smk_in;
>                   spp->smk_out = ssp->smk_out;
> +                 rcu_read_unlock();
>                   return;
>             }
>             /*
>              * A NULL address is only used for updating existing
>              * bound entries. If there isn't one, it's OK.
>              */
> +           rcu_read_unlock();
>             return;
>       }
> 
> @@ -2258,16 +2262,18 @@ static void smk_ipv6_port_label(struct socket
> *sock, struct sockaddr *address)
>        * Look for an existing port list entry.
>        * This is an indication that a port is getting reused.
>        */
> -     list_for_each_entry(spp, &smk_ipv6_port_list, list) {
> +     rcu_read_lock();
> +     list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
>             if (spp->smk_port != port)
>                   continue;
>             spp->smk_port = port;
>             spp->smk_sock = sk;
>             spp->smk_in = ssp->smk_in;
>             spp->smk_out = ssp->smk_out;
> +           rcu_read_unlock();
>             return;
>       }
> -
> +     rcu_read_unlock();
>       /*
>        * A new port entry is required.
>        */
> @@ -2280,7 +2286,9 @@ static void smk_ipv6_port_label(struct socket
> *sock, struct sockaddr *address)
>       spp->smk_in = ssp->smk_in;
>       spp->smk_out = ssp->smk_out;
> 
> -     list_add(&spp->list, &smk_ipv6_port_list);
> +     mutex_lock(&smack_ipv6_lock);
> +     list_add_rcu(&spp->list, &smk_ipv6_port_list);
> +     mutex_unlock(&smack_ipv6_lock);
>       return;
>  }
> 
> @@ -2335,8 +2343,8 @@ static int smk_ipv6_port_check(struct sock *sk,
> struct sockaddr_in6 *address,
>             skp = &smack_known_web;
>             goto auditout;
>       }
> -
> -     list_for_each_entry(spp, &smk_ipv6_port_list, list) {
> +     rcu_read_lock();
> +     list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
>             if (spp->smk_port != port)
>                   continue;
>             object = spp->smk_in;
> @@ -2344,6 +2352,7 @@ static int smk_ipv6_port_check(struct sock *sk,
> struct sockaddr_in6 *address,
>                   ssp->smk_packet = spp->smk_out;
>             break;
>       }
> +     rcu_read_unlock();
> 
>  auditout:
> 
> --
> 1.8.3.2
> --

^ permalink raw reply	[relevance 94%]

* [PATCH v4 00/04] can: Introduce support for Kvaser USBCAN-II devices
  2014-12-23 15:46 96% [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
                   ` (4 preceding siblings ...)
  2015-01-05 17:49 91% ` [PATCH v3 1/4] " Ahmed S. Darwish
@ 2015-01-11 20:05 99% ` Ahmed S. Darwish
  2015-01-11 20:11 96%   ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices Ahmed S. Darwish
  2015-01-20 21:44 67% ` [PATCH v5 1/5] can: kvaser_usb: Update net interface state before exiting on OOM Ahmed S. Darwish
  6 siblings, 1 reply; 200+ results
From: Ahmed S. Darwish @ 2015-01-11 20:05 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi,

Now since earlier v3 submission patches #1-3 got merged, this
is a new patch series expanding on patch v3 #4: support for
the USBCAN-II family.

A new series is introduced due to the extra additions suggested
by code review, which required being added in their own
self-contained patches.

Thanks,
Darwish

^ permalink raw reply	[relevance 99%]

* Re: [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices
  2015-01-11 20:05 99% ` [PATCH v4 00/04] can: Introduce support for Kvaser USBCAN-II devices Ahmed S. Darwish
@ 2015-01-11 20:11 96%   ` Ahmed S. Darwish
  2015-01-11 20:15 99%     ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Ahmed S. Darwish
  2015-01-11 20:49 96%     ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() Ahmed S. Darwish
  0 siblings, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2015-01-11 20:11 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

We should not touch the packet after a netif_rx: it might
get freed behind our back.

Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index cc7bfc0..c32cd61 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -520,10 +520,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 		skb = alloc_can_err_skb(priv->netdev, &cf);
 		if (skb) {
 			cf->can_id |= CAN_ERR_RESTARTED;
-			netif_rx(skb);
 
 			stats->rx_packets++;
 			stats->rx_bytes += cf->can_dlc;
+			netif_rx(skb);
 		} else {
 			netdev_err(priv->netdev,
 				   "No memory left for err_skb\n");
@@ -770,10 +770,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
 	priv->can.state = new_state;
 
-	netif_rx(skb);
-
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
+	netif_rx(skb);
 }
 
 static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -805,10 +804,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 		stats->rx_over_errors++;
 		stats->rx_errors++;
 
-		netif_rx(skb);
-
 		stats->rx_packets++;
 		stats->rx_bytes += cf->can_dlc;
+		netif_rx(skb);
 	}
 }
 
@@ -887,10 +885,9 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 			       cf->can_dlc);
 	}
 
-	netif_rx(skb);
-
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
+	netif_rx(skb);
 }
 
 static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
-- 
1.9.1


^ permalink raw reply	[relevance 96%]

* [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
  2015-01-11 20:11 96%   ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices Ahmed S. Darwish
@ 2015-01-11 20:15 99%     ` Ahmed S. Darwish
  2015-01-11 20:36 36%       ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
    2015-01-11 20:49 96%     ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() Ahmed S. Darwish
  1 sibling, 2 replies; 200+ results
From: Ahmed S. Darwish @ 2015-01-11 20:15 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Let the error counters be more accurate in case of Out of
Memory conditions.

Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index c32cd61..0eb870b 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -792,6 +792,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 	}
 
 	if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
+		stats->rx_over_errors++;
+		stats->rx_errors++;
+
 		skb = alloc_can_err_skb(priv->netdev, &cf);
 		if (!skb) {
 			stats->rx_dropped++;
@@ -801,9 +804,6 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 		cf->can_id |= CAN_ERR_CRTL;
 		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
 
-		stats->rx_over_errors++;
-		stats->rx_errors++;
-
 		stats->rx_packets++;
 		stats->rx_bytes += cf->can_dlc;
 		netif_rx(skb);
-- 
1.9.1


^ permalink raw reply	[relevance 99%]

* [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-11 20:15 99%     ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Ahmed S. Darwish
@ 2015-01-11 20:36 36%       ` Ahmed S. Darwish
  2015-01-11 20:45 91%         ` [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
                           ` (3 more replies)
    1 sibling, 4 replies; 200+ results
From: Ahmed S. Darwish @ 2015-01-11 20:36 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

CAN to USB interfaces sold by the Swedish manufacturer Kvaser are
divided into two major families: 'Leaf', and 'UsbcanII'.  From an
Operating System perspective, the firmware of both families behave
in a not too drastically different fashion.

This patch adds support for the UsbcanII family of devices to the
current Kvaser Leaf-only driver.

CAN frames sending, receiving, and error handling paths has been
tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It
should also work nicely with other products in the same category.

List of new devices supported by this driver update:

         - Kvaser USBcan II HS/HS
         - Kvaser USBcan II HS/LS
         - Kvaser USBcan Rugged ("USBcan Rev B")
         - Kvaser Memorator HS/HS
         - Kvaser Memorator HS/LS
         - Scania VCI2 (if you have the Kvaser logo on top)

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/Kconfig      |   8 +-
 drivers/net/can/usb/kvaser_usb.c | 612 ++++++++++++++++++++++++++++++---------
 2 files changed, 487 insertions(+), 133 deletions(-)

** V4 Changelog:
- Use type-safe C methods instead of cpp macros
- Further clarify the code and comments on error events channel arbitration
- Remove defensive checks against non-existing families
- Re-order methods to remove forward declarations
- Smaller stuff spotted by earlier review (function prefexes, etc.)

** V3 Changelog:
- Fix padding for the usbcan_msg_tx_acknowledge command
- Remove kvaser_usb->max_channels and the MAX_NET_DEVICES macro
- Rename commands to CMD_LEAF_xxx and CMD_USBCAN_xxx
- Apply checkpatch.pl suggestions ('net/' comments, multi-line strings, etc.)

** V2 Changelog:
- Update Kconfig entries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixes

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919..f6f5500 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -25,7 +25,7 @@ config CAN_KVASER_USB
 	tristate "Kvaser CAN/USB interface"
 	---help---
 	  This driver adds support for Kvaser CAN/USB devices like Kvaser
-	  Leaf Light.
+	  Leaf Light and Kvaser USBcan II.
 
 	  The driver provides support for the following devices:
 	    - Kvaser Leaf Light
@@ -46,6 +46,12 @@ config CAN_KVASER_USB
 	    - Kvaser USBcan R
 	    - Kvaser Leaf Light v2
 	    - Kvaser Mini PCI Express HS
+	    - Kvaser USBcan II HS/HS
+	    - Kvaser USBcan II HS/LS
+	    - Kvaser USBcan Rugged ("USBcan Rev B")
+	    - Kvaser Memorator HS/HS
+	    - Kvaser Memorator HS/LS
+	    - Scania VCI2 (if you have the Kvaser logo on top)
 
 	  If unsure, say N.
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 0eb870b..da47d17 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -6,10 +6,12 @@
  * Parts of this driver are based on the following:
  *  - Kvaser linux leaf driver (version 4.78)
  *  - CAN driver for esd CAN-USB/2
+ *  - Kvaser linux usbcanII driver (version 5.3)
  *
  * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
  * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * Copyright (C) 2015 Valeo Corporation
  */
 
 #include <linux/completion.h>
@@ -21,6 +23,15 @@
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
+/* Kvaser USB CAN dongles are divided into two major families:
+ * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo'
+ * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios'
+ */
+enum kvaser_usb_family {
+	KVASER_LEAF,
+	KVASER_USBCAN,
+};
+
 #define MAX_TX_URBS			16
 #define MAX_RX_URBS			4
 #define START_TIMEOUT			1000 /* msecs */
@@ -30,8 +41,9 @@
 #define RX_BUFFER_SIZE			3072
 #define CAN_USB_CLOCK			8000000
 #define MAX_NET_DEVICES			3
+#define MAX_USBCAN_NET_DEVICES		2
 
-/* Kvaser USB devices */
+/* Leaf USB devices */
 #define KVASER_VENDOR_ID		0x0bfd
 #define USB_LEAF_DEVEL_PRODUCT_ID	10
 #define USB_LEAF_LITE_PRODUCT_ID	11
@@ -56,6 +68,24 @@
 #define USB_LEAF_LITE_V2_PRODUCT_ID	288
 #define USB_MINI_PCIE_HS_PRODUCT_ID	289
 
+static inline bool kvaser_is_leaf(const struct usb_device_id *id)
+{
+	return id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
+	       id->idProduct <= USB_MINI_PCIE_HS_PRODUCT_ID;
+}
+
+/* USBCANII devices */
+#define USB_USBCAN_REVB_PRODUCT_ID	2
+#define USB_VCI2_PRODUCT_ID		3
+#define USB_USBCAN2_PRODUCT_ID		4
+#define USB_MEMORATOR_PRODUCT_ID	5
+
+static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
+{
+	return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
+	       id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
+}
+
 /* USB devices features */
 #define KVASER_HAS_SILENT_MODE		BIT(0)
 #define KVASER_HAS_TXRX_ERRORS		BIT(1)
@@ -73,7 +103,7 @@
 #define MSG_FLAG_TX_ACK			BIT(6)
 #define MSG_FLAG_TX_REQUEST		BIT(7)
 
-/* Can states */
+/* Can states (M16C CxSTRH register) */
 #define M16C_STATE_BUS_RESET		BIT(0)
 #define M16C_STATE_BUS_ERROR		BIT(4)
 #define M16C_STATE_BUS_PASSIVE		BIT(5)
@@ -98,7 +128,13 @@
 #define CMD_START_CHIP_REPLY		27
 #define CMD_STOP_CHIP			28
 #define CMD_STOP_CHIP_REPLY		29
-#define CMD_GET_CARD_INFO2		32
+#define CMD_READ_CLOCK			30
+#define CMD_READ_CLOCK_REPLY		31
+
+#define CMD_LEAF_GET_CARD_INFO2		32
+#define CMD_USBCAN_RESET_CLOCK		32
+#define CMD_USBCAN_CLOCK_OVERFLOW_EVENT	33
+
 #define CMD_GET_CARD_INFO		34
 #define CMD_GET_CARD_INFO_REPLY		35
 #define CMD_GET_SOFTWARE_INFO		38
@@ -108,8 +144,9 @@
 #define CMD_RESET_ERROR_COUNTER		49
 #define CMD_TX_ACKNOWLEDGE		50
 #define CMD_CAN_ERROR_EVENT		51
-#define CMD_USB_THROTTLE		77
-#define CMD_LOG_MESSAGE			106
+
+#define CMD_LEAF_USB_THROTTLE		77
+#define CMD_LEAF_LOG_MESSAGE		106
 
 /* error factors */
 #define M16C_EF_ACKE			BIT(0)
@@ -121,6 +158,14 @@
 #define M16C_EF_RCVE			BIT(6)
 #define M16C_EF_TRE			BIT(7)
 
+/* Only Leaf-based devices can report M16C error factors,
+ * thus define our own error status flags for USBCANII
+ */
+#define USBCAN_ERROR_STATE_NONE		0
+#define USBCAN_ERROR_STATE_TX_ERROR	BIT(0)
+#define USBCAN_ERROR_STATE_RX_ERROR	BIT(1)
+#define USBCAN_ERROR_STATE_BUSERROR	BIT(2)
+
 /* bittiming parameters */
 #define KVASER_USB_TSEG1_MIN		1
 #define KVASER_USB_TSEG1_MAX		16
@@ -137,7 +182,7 @@
 #define KVASER_CTRL_MODE_SELFRECEPTION	3
 #define KVASER_CTRL_MODE_OFF		4
 
-/* log message */
+/* Extended CAN identifier flag */
 #define KVASER_EXTENDED_FRAME		BIT(31)
 
 struct kvaser_msg_simple {
@@ -148,30 +193,55 @@ struct kvaser_msg_simple {
 struct kvaser_msg_cardinfo {
 	u8 tid;
 	u8 nchannels;
-	__le32 serial_number;
-	__le32 padding;
+	union {
+		struct {
+			__le32 serial_number;
+			__le32 padding;
+		} __packed leaf0;
+		struct {
+			__le32 serial_number_low;
+			__le32 serial_number_high;
+		} __packed usbcan0;
+	} __packed;
 	__le32 clock_resolution;
 	__le32 mfgdate;
 	u8 ean[8];
 	u8 hw_revision;
-	u8 usb_hs_mode;
-	__le16 padding2;
+	union {
+		struct {
+			u8 usb_hs_mode;
+		} __packed leaf1;
+		struct {
+			u8 padding;
+		} __packed usbcan1;
+	} __packed;
+	__le16 padding;
 } __packed;
 
 struct kvaser_msg_cardinfo2 {
 	u8 tid;
-	u8 channel;
+	u8 reserved;
 	u8 pcb_id[24];
 	__le32 oem_unlock_code;
 } __packed;
 
-struct kvaser_msg_softinfo {
+struct leaf_msg_softinfo {
 	u8 tid;
-	u8 channel;
+	u8 padding0;
 	__le32 sw_options;
 	__le32 fw_version;
 	__le16 max_outstanding_tx;
-	__le16 padding[9];
+	__le16 padding1[9];
+} __packed;
+
+struct usbcan_msg_softinfo {
+	u8 tid;
+	u8 fw_name[5];
+	__le16 max_outstanding_tx;
+	u8 padding[6];
+	__le32 fw_version;
+	__le16 checksum;
+	__le16 sw_options;
 } __packed;
 
 struct kvaser_msg_busparams {
@@ -188,36 +258,86 @@ struct kvaser_msg_tx_can {
 	u8 channel;
 	u8 tid;
 	u8 msg[14];
-	u8 padding;
-	u8 flags;
+	union {
+		struct {
+			u8 padding;
+			u8 flags;
+		} __packed leaf;
+		struct {
+			u8 flags;
+			u8 padding;
+		} __packed usbcan;
+	} __packed;
+} __packed;
+
+struct kvaser_msg_rx_can_header {
+	u8 channel;
+	u8 flag;
 } __packed;
 
-struct kvaser_msg_rx_can {
+struct leaf_msg_rx_can {
 	u8 channel;
 	u8 flag;
+
 	__le16 time[3];
 	u8 msg[14];
 } __packed;
 
-struct kvaser_msg_chip_state_event {
+struct usbcan_msg_rx_can {
+	u8 channel;
+	u8 flag;
+
+	u8 msg[14];
+	__le16 time;
+} __packed;
+
+struct leaf_msg_chip_state_event {
 	u8 tid;
 	u8 channel;
+
 	__le16 time[3];
 	u8 tx_errors_count;
 	u8 rx_errors_count;
+
 	u8 status;
 	u8 padding[3];
 } __packed;
 
-struct kvaser_msg_tx_acknowledge {
+struct usbcan_msg_chip_state_event {
+	u8 tid;
+	u8 channel;
+
+	u8 tx_errors_count;
+	u8 rx_errors_count;
+	__le16 time;
+
+	u8 status;
+	u8 padding[3];
+} __packed;
+
+struct kvaser_msg_tx_acknowledge_header {
+	u8 channel;
+	u8 tid;
+};
+
+struct leaf_msg_tx_acknowledge {
 	u8 channel;
 	u8 tid;
+
 	__le16 time[3];
 	u8 flags;
 	u8 time_offset;
 } __packed;
 
-struct kvaser_msg_error_event {
+struct usbcan_msg_tx_acknowledge {
+	u8 channel;
+	u8 tid;
+
+	__le16 time;
+	__le16 padding;
+} __packed;
+
+struct leaf_msg_error_event {
 	u8 tid;
 	u8 flags;
 	__le16 time[3];
@@ -229,6 +349,18 @@ struct kvaser_msg_error_event {
 	u8 error_factor;
 } __packed;
 
+struct usbcan_msg_error_event {
+	u8 tid;
+	u8 padding;
+	u8 tx_errors_count_ch0;
+	u8 rx_errors_count_ch0;
+	u8 tx_errors_count_ch1;
+	u8 rx_errors_count_ch1;
+	u8 status_ch0;
+	u8 status_ch1;
+	__le16 time;
+} __packed;
+
 struct kvaser_msg_ctrl_mode {
 	u8 tid;
 	u8 channel;
@@ -243,7 +375,7 @@ struct kvaser_msg_flush_queue {
 	u8 padding[3];
 } __packed;
 
-struct kvaser_msg_log_message {
+struct leaf_msg_log_message {
 	u8 channel;
 	u8 flags;
 	__le16 time[3];
@@ -260,19 +392,57 @@ struct kvaser_msg {
 		struct kvaser_msg_simple simple;
 		struct kvaser_msg_cardinfo cardinfo;
 		struct kvaser_msg_cardinfo2 cardinfo2;
-		struct kvaser_msg_softinfo softinfo;
 		struct kvaser_msg_busparams busparams;
+
+		struct kvaser_msg_rx_can_header rx_can_header;
+		struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header;
+
+		union {
+			struct leaf_msg_softinfo softinfo;
+			struct leaf_msg_rx_can rx_can;
+			struct leaf_msg_chip_state_event chip_state_event;
+			struct leaf_msg_tx_acknowledge tx_acknowledge;
+			struct leaf_msg_error_event error_event;
+			struct leaf_msg_log_message log_message;
+		} __packed leaf;
+
+		union {
+			struct usbcan_msg_softinfo softinfo;
+			struct usbcan_msg_rx_can rx_can;
+			struct usbcan_msg_chip_state_event chip_state_event;
+			struct usbcan_msg_tx_acknowledge tx_acknowledge;
+			struct usbcan_msg_error_event error_event;
+		} __packed usbcan;
+
 		struct kvaser_msg_tx_can tx_can;
-		struct kvaser_msg_rx_can rx_can;
-		struct kvaser_msg_chip_state_event chip_state_event;
-		struct kvaser_msg_tx_acknowledge tx_acknowledge;
-		struct kvaser_msg_error_event error_event;
 		struct kvaser_msg_ctrl_mode ctrl_mode;
 		struct kvaser_msg_flush_queue flush_queue;
-		struct kvaser_msg_log_message log_message;
 	} u;
 } __packed;
 
+/* Summary of a kvaser error event, for a unified Leaf/Usbcan error
+ * handling. Some discrepancies between the two families exist:
+ *
+ * - USBCAN firmware does not report M16C "error factors"
+ * - USBCAN controllers has difficulties reporting if the raised error
+ *   event is for ch0 or ch1. They leave such arbitration to the OS
+ *   driver by letting it compare error counters with previous values
+ *   and decide the error event's channel. Thus for USBCAN, the channel
+ *   field is only advisory.
+ */
+struct kvaser_error_summary {
+	u8 channel, status, txerr, rxerr;
+	union {
+		struct {
+			u8 error_factor;
+		} leaf;
+		struct {
+			u8 other_ch_status;
+			u8 error_state;
+		} usbcan;
+	};
+};
+
 struct kvaser_usb_tx_urb_context {
 	struct kvaser_usb_net_priv *priv;
 	u32 echo_index;
@@ -288,6 +458,7 @@ struct kvaser_usb {
 
 	u32 fw_version;
 	unsigned int nchannels;
+	enum kvaser_usb_family family;
 
 	bool rxinitdone;
 	void *rxbuf[MAX_RX_URBS];
@@ -311,6 +482,7 @@ struct kvaser_usb_net_priv {
 };
 
 static const struct usb_device_id kvaser_usb_table[] = {
+	/* Leaf family IDs */
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
@@ -360,6 +532,17 @@ static const struct usb_device_id kvaser_usb_table[] = {
 		.driver_info = KVASER_HAS_TXRX_ERRORS },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
+
+	/* USBCANII family IDs */
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
+		.driver_info = KVASER_HAS_TXRX_ERRORS },
+
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -463,7 +646,14 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
 	if (err)
 		return err;
 
-	dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
+	switch (dev->family) {
+	case KVASER_LEAF:
+		dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
+		break;
+	case KVASER_USBCAN:
+		dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
+		break;
+	}
 
 	return 0;
 }
@@ -482,7 +672,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
 		return err;
 
 	dev->nchannels = msg.u.cardinfo.nchannels;
-	if (dev->nchannels > MAX_NET_DEVICES)
+	if ((dev->nchannels > MAX_NET_DEVICES) ||
+	    (dev->family == KVASER_USBCAN &&
+	     dev->nchannels > MAX_USBCAN_NET_DEVICES))
 		return -EINVAL;
 
 	return 0;
@@ -496,8 +688,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 	struct kvaser_usb_net_priv *priv;
 	struct sk_buff *skb;
 	struct can_frame *cf;
-	u8 channel = msg->u.tx_acknowledge.channel;
-	u8 tid = msg->u.tx_acknowledge.tid;
+	u8 channel, tid;
+
+	channel = msg->u.tx_acknowledge_header.channel;
+	tid = msg->u.tx_acknowledge_header.tid;
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -616,53 +810,24 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
 }
 
 static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
-				const struct kvaser_msg *msg)
+				struct kvaser_error_summary *es)
 {
 	struct can_frame *cf;
 	struct sk_buff *skb;
 	struct net_device_stats *stats;
 	struct kvaser_usb_net_priv *priv;
 	unsigned int new_state;
-	u8 channel, status, txerr, rxerr, error_factor;
-
-	switch (msg->id) {
-	case CMD_CAN_ERROR_EVENT:
-		channel = msg->u.error_event.channel;
-		status =  msg->u.error_event.status;
-		txerr = msg->u.error_event.tx_errors_count;
-		rxerr = msg->u.error_event.rx_errors_count;
-		error_factor = msg->u.error_event.error_factor;
-		break;
-	case CMD_LOG_MESSAGE:
-		channel = msg->u.log_message.channel;
-		status = msg->u.log_message.data[0];
-		txerr = msg->u.log_message.data[2];
-		rxerr = msg->u.log_message.data[3];
-		error_factor = msg->u.log_message.data[1];
-		break;
-	case CMD_CHIP_STATE_EVENT:
-		channel = msg->u.chip_state_event.channel;
-		status =  msg->u.chip_state_event.status;
-		txerr = msg->u.chip_state_event.tx_errors_count;
-		rxerr = msg->u.chip_state_event.rx_errors_count;
-		error_factor = 0;
-		break;
-	default:
-		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
-			msg->id);
-		return;
-	}
 
-	if (channel >= dev->nchannels) {
+	if (es->channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
-			"Invalid channel number (%d)\n", channel);
+			"Invalid channel number (%d)\n", es->channel);
 		return;
 	}
 
-	priv = dev->nets[channel];
+	priv = dev->nets[es->channel];
 	stats = &priv->netdev->stats;
 
-	if (status & M16C_STATE_BUS_RESET) {
+	if (es->status & M16C_STATE_BUS_RESET) {
 		kvaser_usb_unlink_tx_urbs(priv);
 		return;
 	}
@@ -675,9 +840,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
 	new_state = priv->can.state;
 
-	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
+	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
 
-	if (status & M16C_STATE_BUS_OFF) {
+	if (es->status & M16C_STATE_BUS_OFF) {
 		cf->can_id |= CAN_ERR_BUSOFF;
 
 		priv->can.can_stats.bus_off++;
@@ -687,12 +852,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		netif_carrier_off(priv->netdev);
 
 		new_state = CAN_STATE_BUS_OFF;
-	} else if (status & M16C_STATE_BUS_PASSIVE) {
+	} else if (es->status & M16C_STATE_BUS_PASSIVE) {
 		if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
 			cf->can_id |= CAN_ERR_CRTL;
 
-			if (txerr || rxerr)
-				cf->data[1] = (txerr > rxerr)
+			if (es->txerr || es->rxerr)
+				cf->data[1] = (es->txerr > es->rxerr)
 						? CAN_ERR_CRTL_TX_PASSIVE
 						: CAN_ERR_CRTL_RX_PASSIVE;
 			else
@@ -703,13 +868,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 
 		new_state = CAN_STATE_ERROR_PASSIVE;
-	}
-
-	if (status == M16C_STATE_BUS_ERROR) {
+	} else if (es->status & M16C_STATE_BUS_ERROR) {
 		if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
-		    ((txerr >= 96) || (rxerr >= 96))) {
+		    ((es->txerr >= 96) || (es->rxerr >= 96))) {
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (txerr > rxerr)
+			cf->data[1] = (es->txerr > es->rxerr)
 					? CAN_ERR_CRTL_TX_WARNING
 					: CAN_ERR_CRTL_RX_WARNING;
 
@@ -723,7 +886,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 	}
 
-	if (!status) {
+	if (!es->status) {
 		cf->can_id |= CAN_ERR_PROT;
 		cf->data[2] = CAN_ERR_PROT_ACTIVE;
 
@@ -739,34 +902,48 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		priv->can.can_stats.restarts++;
 	}
 
-	if (error_factor) {
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-
-		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-
-		if (error_factor & M16C_EF_ACKE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
-		if (error_factor & M16C_EF_CRCE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-					CAN_ERR_PROT_LOC_CRC_DEL);
-		if (error_factor & M16C_EF_FORME)
-			cf->data[2] |= CAN_ERR_PROT_FORM;
-		if (error_factor & M16C_EF_STFE)
-			cf->data[2] |= CAN_ERR_PROT_STUFF;
-		if (error_factor & M16C_EF_BITE0)
-			cf->data[2] |= CAN_ERR_PROT_BIT0;
-		if (error_factor & M16C_EF_BITE1)
-			cf->data[2] |= CAN_ERR_PROT_BIT1;
-		if (error_factor & M16C_EF_TRE)
-			cf->data[2] |= CAN_ERR_PROT_TX;
+	switch (dev->family) {
+	case KVASER_LEAF:
+		if (es->leaf.error_factor) {
+			priv->can.can_stats.bus_error++;
+			stats->rx_errors++;
+
+			cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+
+			if (es->leaf.error_factor & M16C_EF_ACKE)
+				cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
+			if (es->leaf.error_factor & M16C_EF_CRCE)
+				cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+						CAN_ERR_PROT_LOC_CRC_DEL);
+			if (es->leaf.error_factor & M16C_EF_FORME)
+				cf->data[2] |= CAN_ERR_PROT_FORM;
+			if (es->leaf.error_factor & M16C_EF_STFE)
+				cf->data[2] |= CAN_ERR_PROT_STUFF;
+			if (es->leaf.error_factor & M16C_EF_BITE0)
+				cf->data[2] |= CAN_ERR_PROT_BIT0;
+			if (es->leaf.error_factor & M16C_EF_BITE1)
+				cf->data[2] |= CAN_ERR_PROT_BIT1;
+			if (es->leaf.error_factor & M16C_EF_TRE)
+				cf->data[2] |= CAN_ERR_PROT_TX;
+		}
+		break;
+	case KVASER_USBCAN:
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
+			stats->tx_errors++;
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
+			stats->rx_errors++;
+		if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
+			priv->can.can_stats.bus_error++;
+			cf->can_id |= CAN_ERR_BUSERROR;
+		}
+		break;
 	}
 
-	cf->data[6] = txerr;
-	cf->data[7] = rxerr;
+	cf->data[6] = es->txerr;
+	cf->data[7] = es->rxerr;
 
-	priv->bec.txerr = txerr;
-	priv->bec.rxerr = rxerr;
+	priv->bec.txerr = es->txerr;
+	priv->bec.rxerr = es->rxerr;
 
 	priv->can.state = new_state;
 
@@ -775,6 +952,124 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 	netif_rx(skb);
 }
 
+/* For USBCAN, report error to userspace iff the channels's errors counter
+ * has increased, or we're the only channel seeing a bus error state.
+ */
+static void kvaser_usbcan_conditionally_rx_error(const struct kvaser_usb *dev,
+						 struct kvaser_error_summary *es)
+{
+	struct kvaser_usb_net_priv *priv;
+	int channel;
+	bool report_error;
+
+	channel = es->channel;
+	if (channel >= dev->nchannels) {
+		dev_err(dev->udev->dev.parent,
+			"Invalid channel number (%d)\n", channel);
+		return;
+	}
+
+	priv = dev->nets[channel];
+	report_error = false;
+
+	if (es->txerr > priv->bec.txerr) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR;
+		report_error = true;
+	}
+	if (es->rxerr > priv->bec.rxerr) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR;
+		report_error = true;
+	}
+	if ((es->status & M16C_STATE_BUS_ERROR) &&
+	    !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) {
+		es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR;
+		report_error = true;
+	}
+
+	if (report_error)
+		kvaser_usb_rx_error(dev, es);
+}
+
+static void kvaser_usbcan_rx_error(const struct kvaser_usb *dev,
+				   const struct kvaser_msg *msg)
+{
+	struct kvaser_error_summary es = { };
+
+	switch (msg->id) {
+	/* Sometimes errors are sent as unsolicited chip state events */
+	case CMD_CHIP_STATE_EVENT:
+		es.channel = msg->u.usbcan.chip_state_event.channel;
+		es.status =  msg->u.usbcan.chip_state_event.status;
+		es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count;
+		es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count;
+		kvaser_usbcan_conditionally_rx_error(dev, &es);
+		break;
+
+	case CMD_CAN_ERROR_EVENT:
+		es.channel = 0;
+		es.status = msg->u.usbcan.error_event.status_ch0;
+		es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0;
+		es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0;
+		es.usbcan.other_ch_status =
+			msg->u.usbcan.error_event.status_ch1;
+		kvaser_usbcan_conditionally_rx_error(dev, &es);
+
+		/* The USBCAN firmware does not support more than 2 channels.
+		 * Now that ch0 was checked, check if ch1 has any errors.
+		 */
+		if (dev->nchannels == MAX_USBCAN_NET_DEVICES) {
+			es.channel = 1;
+			es.status = msg->u.usbcan.error_event.status_ch1;
+			es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1;
+			es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1;
+			es.usbcan.other_ch_status =
+				msg->u.usbcan.error_event.status_ch0;
+			kvaser_usbcan_conditionally_rx_error(dev, &es);
+		}
+		break;
+
+	default:
+		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
+			msg->id);
+	}
+}
+
+static void kvaser_leaf_rx_error(const struct kvaser_usb *dev,
+				 const struct kvaser_msg *msg)
+{
+	struct kvaser_error_summary es = { };
+
+	switch (msg->id) {
+	case CMD_CAN_ERROR_EVENT:
+		es.channel = msg->u.leaf.error_event.channel;
+		es.status =  msg->u.leaf.error_event.status;
+		es.txerr = msg->u.leaf.error_event.tx_errors_count;
+		es.rxerr = msg->u.leaf.error_event.rx_errors_count;
+		es.leaf.error_factor = msg->u.leaf.error_event.error_factor;
+		break;
+	case CMD_LEAF_LOG_MESSAGE:
+		es.channel = msg->u.leaf.log_message.channel;
+		es.status = msg->u.leaf.log_message.data[0];
+		es.txerr = msg->u.leaf.log_message.data[2];
+		es.rxerr = msg->u.leaf.log_message.data[3];
+		es.leaf.error_factor = msg->u.leaf.log_message.data[1];
+		break;
+	case CMD_CHIP_STATE_EVENT:
+		es.channel = msg->u.leaf.chip_state_event.channel;
+		es.status =  msg->u.leaf.chip_state_event.status;
+		es.txerr = msg->u.leaf.chip_state_event.tx_errors_count;
+		es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count;
+		es.leaf.error_factor = 0;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
+			msg->id);
+		return;
+	}
+
+	kvaser_usb_rx_error(dev, &es);
+}
+
 static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 				  const struct kvaser_msg *msg)
 {
@@ -782,16 +1077,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 	struct sk_buff *skb;
 	struct net_device_stats *stats = &priv->netdev->stats;
 
-	if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+	if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
 					 MSG_FLAG_NERR)) {
 		netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
-			   msg->u.rx_can.flag);
+			   msg->u.rx_can_header.flag);
 
 		stats->rx_errors++;
 		return;
 	}
 
-	if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
+	if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) {
 		stats->rx_over_errors++;
 		stats->rx_errors++;
 
@@ -817,7 +1112,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 	struct can_frame *cf;
 	struct sk_buff *skb;
 	struct net_device_stats *stats;
-	u8 channel = msg->u.rx_can.channel;
+	u8 channel = msg->u.rx_can_header.channel;
+	const u8 *rx_msg;
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -828,19 +1124,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 	priv = dev->nets[channel];
 	stats = &priv->netdev->stats;
 
-	if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) &&
-	    (msg->id == CMD_LOG_MESSAGE)) {
-		kvaser_usb_rx_error(dev, msg);
+	if ((msg->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
+	    (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE)) {
+		kvaser_leaf_rx_error(dev, msg);
 		return;
-	} else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
-					 MSG_FLAG_NERR |
-					 MSG_FLAG_OVERRUN)) {
+	} else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
+						MSG_FLAG_NERR |
+						MSG_FLAG_OVERRUN)) {
 		kvaser_usb_rx_can_err(priv, msg);
 		return;
-	} else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
+	} else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) {
 		netdev_warn(priv->netdev,
 			    "Unhandled frame (flags: 0x%02x)",
-			    msg->u.rx_can.flag);
+			    msg->u.rx_can_header.flag);
+		return;
+	}
+
+	switch (dev->family) {
+	case KVASER_LEAF:
+		rx_msg = msg->u.leaf.rx_can.msg;
+		break;
+	case KVASER_USBCAN:
+		rx_msg = msg->u.usbcan.rx_can.msg;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
 		return;
 	}
 
@@ -850,38 +1159,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
 		return;
 	}
 
-	if (msg->id == CMD_LOG_MESSAGE) {
-		cf->can_id = le32_to_cpu(msg->u.log_message.id);
+	if (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE) {
+		cf->can_id = le32_to_cpu(msg->u.leaf.log_message.id);
 		if (cf->can_id & KVASER_EXTENDED_FRAME)
 			cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
 		else
 			cf->can_id &= CAN_SFF_MASK;
 
-		cf->can_dlc = get_can_dlc(msg->u.log_message.dlc);
+		cf->can_dlc = get_can_dlc(msg->u.leaf.log_message.dlc);
 
-		if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME)
+		if (msg->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME)
 			cf->can_id |= CAN_RTR_FLAG;
 		else
-			memcpy(cf->data, &msg->u.log_message.data,
+			memcpy(cf->data, &msg->u.leaf.log_message.data,
 			       cf->can_dlc);
 	} else {
-		cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
-			     (msg->u.rx_can.msg[1] & 0x3f);
+		cf->can_id = ((rx_msg[0] & 0x1f) << 6) | (rx_msg[1] & 0x3f);
 
 		if (msg->id == CMD_RX_EXT_MESSAGE) {
 			cf->can_id <<= 18;
-			cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
-				      ((msg->u.rx_can.msg[3] & 0xff) << 6) |
-				      (msg->u.rx_can.msg[4] & 0x3f);
+			cf->can_id |= ((rx_msg[2] & 0x0f) << 14) |
+				      ((rx_msg[3] & 0xff) << 6) |
+				      (rx_msg[4] & 0x3f);
 			cf->can_id |= CAN_EFF_FLAG;
 		}
 
-		cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+		cf->can_dlc = get_can_dlc(rx_msg[5]);
 
-		if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
+		if (msg->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME)
 			cf->can_id |= CAN_RTR_FLAG;
 		else
-			memcpy(cf->data, &msg->u.rx_can.msg[6],
+			memcpy(cf->data, &rx_msg[6],
 			       cf->can_dlc);
 	}
 
@@ -944,21 +1252,35 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
 
 	case CMD_RX_STD_MESSAGE:
 	case CMD_RX_EXT_MESSAGE:
-	case CMD_LOG_MESSAGE:
+		kvaser_usb_rx_can_msg(dev, msg);
+		break;
+
+	case CMD_LEAF_LOG_MESSAGE:
+		if (dev->family != KVASER_LEAF)
+			goto warn;
 		kvaser_usb_rx_can_msg(dev, msg);
 		break;
 
 	case CMD_CHIP_STATE_EVENT:
 	case CMD_CAN_ERROR_EVENT:
-		kvaser_usb_rx_error(dev, msg);
+		if (dev->family == KVASER_LEAF)
+			kvaser_leaf_rx_error(dev, msg);
+		else
+			kvaser_usbcan_rx_error(dev, msg);
 		break;
 
 	case CMD_TX_ACKNOWLEDGE:
 		kvaser_usb_tx_acknowledge(dev, msg);
 		break;
 
+	/* Ignored messages */
+	case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
+		if (dev->family != KVASER_USBCAN)
+			goto warn;
+		break;
+
 	default:
-		dev_warn(dev->udev->dev.parent,
+warn:		dev_warn(dev->udev->dev.parent,
 			 "Unhandled message (%d)\n", msg->id);
 		break;
 	}
@@ -1178,7 +1500,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
 				  dev->rxbuf[i],
 				  dev->rxbuf_dma[i]);
 
-	for (i = 0; i < MAX_NET_DEVICES; i++) {
+	for (i = 0; i < dev->nchannels; i++) {
 		struct kvaser_usb_net_priv *priv = dev->nets[i];
 
 		if (priv)
@@ -1286,6 +1608,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	struct kvaser_msg *msg;
 	int i, err;
 	int ret = NETDEV_TX_OK;
+	uint8_t *msg_tx_can_flags;
 
 	if (can_dropped_invalid_skb(netdev, skb))
 		return NETDEV_TX_OK;
@@ -1307,9 +1630,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 
 	msg = buf;
 	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
-	msg->u.tx_can.flags = 0;
 	msg->u.tx_can.channel = priv->channel;
 
+	switch (dev->family) {
+	case KVASER_LEAF:
+		msg_tx_can_flags = &msg->u.tx_can.leaf.flags;
+		break;
+	case KVASER_USBCAN:
+		msg_tx_can_flags = &msg->u.tx_can.usbcan.flags;
+		break;
+	default:
+		dev_err(dev->udev->dev.parent,
+			"Invalid device family (%d)\n", dev->family);
+		goto releasebuf;
+	}
+
+	*msg_tx_can_flags = 0;
+
 	if (cf->can_id & CAN_EFF_FLAG) {
 		msg->id = CMD_TX_EXT_MESSAGE;
 		msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
@@ -1327,7 +1664,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 	memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
 
 	if (cf->can_id & CAN_RTR_FLAG)
-		msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
+		*msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
 
 	for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
 		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
@@ -1596,6 +1933,17 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 	if (!dev)
 		return -ENOMEM;
 
+	if (kvaser_is_leaf(id)) {
+		dev->family = KVASER_LEAF;
+	} else if (kvaser_is_usbcan(id)) {
+		dev->family = KVASER_USBCAN;
+	} else {
+		dev_err(&intf->dev,
+			"Product ID (%d) does not belong to any known Kvaser USB family",
+			id->idProduct);
+		return -ENODEV;
+	}
+
 	err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
 	if (err) {
 		dev_err(&intf->dev, "Cannot get usb endpoint(s)");
-- 
1.9.1


^ permalink raw reply	[relevance 36%]

* [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
  2015-01-11 20:36 36%       ` [PATCH v4 3/4] can: kvas