Message ID | 1427972721-18420-2-git-send-email-gavin.guo@canonical.com |
---|---|
State | New |
Headers | show |
Looks good, and thanks for the detailed writeup. I'm surprised that this patch didn't CC: stable as it seems that other stable kernels may benefit from this patch. Acked-By: Chris J Arges <chris.j.arges@canonical.com> On 04/02/2015 06:05 AM, Gavin Guo wrote: > From: Paul Moore <pmoore@redhat.com> > > BugLink: http://bugs.launchpad.net/bugs/1439441 > > There is a problem with the audit system when multiple audit records > are created for the same path, each with a different path name type. > The root cause of the problem is in __audit_inode() when an exact > match (both the path name and path name type) is not found for a > path name record; the existing code creates a new path name record, > but it never sets the path name in this record, leaving it NULL. > This patch corrects this problem by assigning the path name to these > newly created records. > > There are many ways to reproduce this problem, but one of the > easiest is the following (assuming auditd is running): > > # mkdir /root/tmp/test > # touch /root/tmp/test/567 > # auditctl -a always,exit -F dir=/root/tmp/test > # touch /root/tmp/test/567 > > Afterwards, or while the commands above are running, check the audit > log and pay special attention to the PATH records. A faulty kernel > will display something like the following for the file creation: > > type=SYSCALL msg=audit(1416957442.025:93): arch=c000003e syscall=2 > success=yes exit=3 ... comm="touch" exe="/usr/bin/touch" > type=CWD msg=audit(1416957442.025:93): cwd="/root/tmp" > type=PATH msg=audit(1416957442.025:93): item=0 name="test/" > inode=401409 ... nametype=PARENT > type=PATH msg=audit(1416957442.025:93): item=1 name=(null) > inode=393804 ... nametype=NORMAL > type=PATH msg=audit(1416957442.025:93): item=2 name=(null) > inode=393804 ... nametype=NORMAL > > While a patched kernel will show the following: > > type=SYSCALL msg=audit(1416955786.566:89): arch=c000003e syscall=2 > success=yes exit=3 ... comm="touch" exe="/usr/bin/touch" > type=CWD msg=audit(1416955786.566:89): cwd="/root/tmp" > type=PATH msg=audit(1416955786.566:89): item=0 name="test/" > inode=401409 ... nametype=PARENT > type=PATH msg=audit(1416955786.566:89): item=1 name="test/567" > inode=393804 ... nametype=NORMAL > > This issue was brought up by a number of people, but special credit > should go to hujianyang@huawei.com for reporting the problem along > with an explanation of the problem and a patch. While the original > patch did have some problems (see the archive link below), it did > demonstrate the problem and helped kickstart the fix presented here. > > * https://lkml.org/lkml/2014/9/5/66 > > Reported-by: hujianyang <hujianyang@huawei.com> > Signed-off-by: Paul Moore <pmoore@redhat.com> > Acked-by: Richard Guy Briggs <rgb@redhat.com> > (cherry picked from commit 4a92843601ad0f5067f441d2f0dca55bbe18c076) > Signed-off-by: Gavin Guo <gavin.guo@canonical.com> > --- > kernel/auditsc.c | 14 ++++++++++---- > 1 file changed, 10 insertions(+), 4 deletions(-) > > diff --git a/kernel/auditsc.c b/kernel/auditsc.c > index 21eae3c..ff99c05 100644 > --- a/kernel/auditsc.c > +++ b/kernel/auditsc.c > @@ -1886,12 +1886,18 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, > } > > out_alloc: > - /* unable to find the name from a previous getname(). Allocate a new > - * anonymous entry. > - */ > - n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); > + /* unable to find an entry with both a matching name and type */ > + n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); > if (!n) > return; > + if (name) > + /* since name is not NULL we know there is already a matching > + * name record, see audit_getname(), so there must be a type > + * mismatch; reuse the string path since the original name > + * record will keep the string valid until we free it in > + * audit_free_names() */ > + n->name = name; > + > out: > if (parent) { > n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; >
On Thu, Apr 02, 2015 at 07:05:21PM +0800, Gavin Guo wrote: > From: Paul Moore <pmoore@redhat.com> > > BugLink: http://bugs.launchpad.net/bugs/1439441 > > There is a problem with the audit system when multiple audit records > are created for the same path, each with a different path name type. > The root cause of the problem is in __audit_inode() when an exact > match (both the path name and path name type) is not found for a > path name record; the existing code creates a new path name record, > but it never sets the path name in this record, leaving it NULL. > This patch corrects this problem by assigning the path name to these > newly created records. > > There are many ways to reproduce this problem, but one of the > easiest is the following (assuming auditd is running): > > # mkdir /root/tmp/test > # touch /root/tmp/test/567 > # auditctl -a always,exit -F dir=/root/tmp/test > # touch /root/tmp/test/567 > > Afterwards, or while the commands above are running, check the audit > log and pay special attention to the PATH records. A faulty kernel > will display something like the following for the file creation: > > type=SYSCALL msg=audit(1416957442.025:93): arch=c000003e syscall=2 > success=yes exit=3 ... comm="touch" exe="/usr/bin/touch" > type=CWD msg=audit(1416957442.025:93): cwd="/root/tmp" > type=PATH msg=audit(1416957442.025:93): item=0 name="test/" > inode=401409 ... nametype=PARENT > type=PATH msg=audit(1416957442.025:93): item=1 name=(null) > inode=393804 ... nametype=NORMAL > type=PATH msg=audit(1416957442.025:93): item=2 name=(null) > inode=393804 ... nametype=NORMAL > > While a patched kernel will show the following: > > type=SYSCALL msg=audit(1416955786.566:89): arch=c000003e syscall=2 > success=yes exit=3 ... comm="touch" exe="/usr/bin/touch" > type=CWD msg=audit(1416955786.566:89): cwd="/root/tmp" > type=PATH msg=audit(1416955786.566:89): item=0 name="test/" > inode=401409 ... nametype=PARENT > type=PATH msg=audit(1416955786.566:89): item=1 name="test/567" > inode=393804 ... nametype=NORMAL > > This issue was brought up by a number of people, but special credit > should go to hujianyang@huawei.com for reporting the problem along > with an explanation of the problem and a patch. While the original > patch did have some problems (see the archive link below), it did > demonstrate the problem and helped kickstart the fix presented here. > > * https://lkml.org/lkml/2014/9/5/66 > > Reported-by: hujianyang <hujianyang@huawei.com> > Signed-off-by: Paul Moore <pmoore@redhat.com> > Acked-by: Richard Guy Briggs <rgb@redhat.com> > (cherry picked from commit 4a92843601ad0f5067f441d2f0dca55bbe18c076) > Signed-off-by: Gavin Guo <gavin.guo@canonical.com> > --- > kernel/auditsc.c | 14 ++++++++++---- > 1 file changed, 10 insertions(+), 4 deletions(-) > > diff --git a/kernel/auditsc.c b/kernel/auditsc.c > index 21eae3c..ff99c05 100644 > --- a/kernel/auditsc.c > +++ b/kernel/auditsc.c > @@ -1886,12 +1886,18 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, > } > > out_alloc: > - /* unable to find the name from a previous getname(). Allocate a new > - * anonymous entry. > - */ > - n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); > + /* unable to find an entry with both a matching name and type */ > + n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); > if (!n) > return; > + if (name) > + /* since name is not NULL we know there is already a matching > + * name record, see audit_getname(), so there must be a type > + * mismatch; reuse the string path since the original name > + * record will keep the string valid until we free it in > + * audit_free_names() */ > + n->name = name; > + > out: > if (parent) { > n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; Looks to do what is claimed. Represents a regression against P. Acked-by: Andy Whitcroft <apw@canonical.com> -apw
Hi Andy, On Thu, Apr 2, 2015 at 8:06 PM, Andy Whitcroft <apw@canonical.com> wrote: > On Thu, Apr 02, 2015 at 07:05:21PM +0800, Gavin Guo wrote: >> From: Paul Moore <pmoore@redhat.com> >> >> BugLink: http://bugs.launchpad.net/bugs/1439441 >> >> There is a problem with the audit system when multiple audit records >> are created for the same path, each with a different path name type. >> The root cause of the problem is in __audit_inode() when an exact >> match (both the path name and path name type) is not found for a >> path name record; the existing code creates a new path name record, >> but it never sets the path name in this record, leaving it NULL. >> This patch corrects this problem by assigning the path name to these >> newly created records. >> >> There are many ways to reproduce this problem, but one of the >> easiest is the following (assuming auditd is running): >> >> # mkdir /root/tmp/test >> # touch /root/tmp/test/567 >> # auditctl -a always,exit -F dir=/root/tmp/test >> # touch /root/tmp/test/567 >> >> Afterwards, or while the commands above are running, check the audit >> log and pay special attention to the PATH records. A faulty kernel >> will display something like the following for the file creation: >> >> type=SYSCALL msg=audit(1416957442.025:93): arch=c000003e syscall=2 >> success=yes exit=3 ... comm="touch" exe="/usr/bin/touch" >> type=CWD msg=audit(1416957442.025:93): cwd="/root/tmp" >> type=PATH msg=audit(1416957442.025:93): item=0 name="test/" >> inode=401409 ... nametype=PARENT >> type=PATH msg=audit(1416957442.025:93): item=1 name=(null) >> inode=393804 ... nametype=NORMAL >> type=PATH msg=audit(1416957442.025:93): item=2 name=(null) >> inode=393804 ... nametype=NORMAL >> >> While a patched kernel will show the following: >> >> type=SYSCALL msg=audit(1416955786.566:89): arch=c000003e syscall=2 >> success=yes exit=3 ... comm="touch" exe="/usr/bin/touch" >> type=CWD msg=audit(1416955786.566:89): cwd="/root/tmp" >> type=PATH msg=audit(1416955786.566:89): item=0 name="test/" >> inode=401409 ... nametype=PARENT >> type=PATH msg=audit(1416955786.566:89): item=1 name="test/567" >> inode=393804 ... nametype=NORMAL >> >> This issue was brought up by a number of people, but special credit >> should go to hujianyang@huawei.com for reporting the problem along >> with an explanation of the problem and a patch. While the original >> patch did have some problems (see the archive link below), it did >> demonstrate the problem and helped kickstart the fix presented here. >> >> * https://lkml.org/lkml/2014/9/5/66 >> >> Reported-by: hujianyang <hujianyang@huawei.com> >> Signed-off-by: Paul Moore <pmoore@redhat.com> >> Acked-by: Richard Guy Briggs <rgb@redhat.com> >> (cherry picked from commit 4a92843601ad0f5067f441d2f0dca55bbe18c076) >> Signed-off-by: Gavin Guo <gavin.guo@canonical.com> >> --- >> kernel/auditsc.c | 14 ++++++++++---- >> 1 file changed, 10 insertions(+), 4 deletions(-) >> >> diff --git a/kernel/auditsc.c b/kernel/auditsc.c >> index 21eae3c..ff99c05 100644 >> --- a/kernel/auditsc.c >> +++ b/kernel/auditsc.c >> @@ -1886,12 +1886,18 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, >> } >> >> out_alloc: >> - /* unable to find the name from a previous getname(). Allocate a new >> - * anonymous entry. >> - */ >> - n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); >> + /* unable to find an entry with both a matching name and type */ >> + n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); >> if (!n) >> return; >> + if (name) >> + /* since name is not NULL we know there is already a matching >> + * name record, see audit_getname(), so there must be a type >> + * mismatch; reuse the string path since the original name >> + * record will keep the string valid until we free it in >> + * audit_free_names() */ >> + n->name = name; >> + >> out: >> if (parent) { >> n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; > > Looks to do what is claimed. Represents a regression against P. > > Acked-by: Andy Whitcroft <apw@canonical.com> > > -apw I've tested with linux-image-3.2.0-23-generic and linux-image-3.2.0-79-virtual in my manual bisect. Both are good. The following is the detail process. Test of the following kernel fail: linux-image-3.13.0-031300-generic_3.13.0-031300.201401192235_amd64.deb linux-image-3.13.0-24-generic linux-image-3.13.0-46-generic linux-image-3.15.0-031500-generic_3.15.0-031500.201406131105_amd64.deb linux-image-3.17.0-031700-generic_3.17.0-031700.201410060605_amd64.deb linux-image-3.18.0-031800-generic_3.18.0-031800.201412071935_amd64.deb linux-image-3.18.9-031809-generic_3.18.9-031809.201503080036_amd64.deb Success: linux-image-3.2.0-23-generic linux-image-3.2.0-79-virtual linux-image-3.19.0-031900rc2-generic_3.19.0-031900rc2.201412290135_amd64.deb linux-image-3.19.0-031900rc4-generic_3.19.0-031900rc4.201501112135_amd64.deb linux-image-3.19.0-031900-generic_3.19.0-031900.201502091451_amd64.deb linux-image-4.0.0-040000rc6-generic_4.0.0-040000rc6.201503291935_amd64.deb Bisect process: linux-image-3.13.0-031300-generic_3.13.0-031300.201401192235_amd64.deb - fail linux-image-3.13.0-24-generic - fail linux-image-3.13.0-46-generic - fail linux-image-3.15.0-031500-generic_3.15.0-031500.201406131105_amd64.deb - fail linux-image-3.17.0-031700-generic_3.17.0-031700.201410060605_amd64.deb - fail linux-image-3.18.0-031800-generic_3.18.0-031800.201412071935_amd64.deb - fail linux-image-3.18.9-031809-generic_3.18.9-031809.201503080036_amd64.deb - fail linux-image-3.19.0-031900rc1-generic_3.19.0-031900rc1.201412210135_amd64.deb - fail linux-image-3.19.0-031900rc2-generic_3.19.0-031900rc2.201412290135_amd64.deb - success linux-image-3.19.0-031900rc4-generic_3.19.0-031900rc4.201501112135_amd64.deb - success linux-image-3.19.0-031900-generic_3.19.0-031900.201502091451_amd64.deb - success linux-image-4.0.0-040000rc6-generic_4.0.0-040000rc6.201503291935_amd64.deb - success Gavin
On 04/02/2015 06:29 AM, Gavin Guo wrote: > Hi Andy, > > On Thu, Apr 2, 2015 at 8:06 PM, Andy Whitcroft <apw@canonical.com> wrote: >> On Thu, Apr 02, 2015 at 07:05:21PM +0800, Gavin Guo wrote: >>> From: Paul Moore <pmoore@redhat.com> >>> >>> BugLink: http://bugs.launchpad.net/bugs/1439441 >>> >>> There is a problem with the audit system when multiple audit records >>> are created for the same path, each with a different path name type. >>> The root cause of the problem is in __audit_inode() when an exact >>> match (both the path name and path name type) is not found for a >>> path name record; the existing code creates a new path name record, >>> but it never sets the path name in this record, leaving it NULL. >>> This patch corrects this problem by assigning the path name to these >>> newly created records. >>> >>> There are many ways to reproduce this problem, but one of the >>> easiest is the following (assuming auditd is running): >>> >>> # mkdir /root/tmp/test >>> # touch /root/tmp/test/567 >>> # auditctl -a always,exit -F dir=/root/tmp/test >>> # touch /root/tmp/test/567 >>> >>> Afterwards, or while the commands above are running, check the audit >>> log and pay special attention to the PATH records. A faulty kernel >>> will display something like the following for the file creation: >>> >>> type=SYSCALL msg=audit(1416957442.025:93): arch=c000003e syscall=2 >>> success=yes exit=3 ... comm="touch" exe="/usr/bin/touch" >>> type=CWD msg=audit(1416957442.025:93): cwd="/root/tmp" >>> type=PATH msg=audit(1416957442.025:93): item=0 name="test/" >>> inode=401409 ... nametype=PARENT >>> type=PATH msg=audit(1416957442.025:93): item=1 name=(null) >>> inode=393804 ... nametype=NORMAL >>> type=PATH msg=audit(1416957442.025:93): item=2 name=(null) >>> inode=393804 ... nametype=NORMAL >>> >>> While a patched kernel will show the following: >>> >>> type=SYSCALL msg=audit(1416955786.566:89): arch=c000003e syscall=2 >>> success=yes exit=3 ... comm="touch" exe="/usr/bin/touch" >>> type=CWD msg=audit(1416955786.566:89): cwd="/root/tmp" >>> type=PATH msg=audit(1416955786.566:89): item=0 name="test/" >>> inode=401409 ... nametype=PARENT >>> type=PATH msg=audit(1416955786.566:89): item=1 name="test/567" >>> inode=393804 ... nametype=NORMAL >>> >>> This issue was brought up by a number of people, but special credit >>> should go to hujianyang@huawei.com for reporting the problem along >>> with an explanation of the problem and a patch. While the original >>> patch did have some problems (see the archive link below), it did >>> demonstrate the problem and helped kickstart the fix presented here. >>> >>> * https://lkml.org/lkml/2014/9/5/66 >>> >>> Reported-by: hujianyang <hujianyang@huawei.com> >>> Signed-off-by: Paul Moore <pmoore@redhat.com> >>> Acked-by: Richard Guy Briggs <rgb@redhat.com> >>> (cherry picked from commit 4a92843601ad0f5067f441d2f0dca55bbe18c076) >>> Signed-off-by: Gavin Guo <gavin.guo@canonical.com> >>> --- >>> kernel/auditsc.c | 14 ++++++++++---- >>> 1 file changed, 10 insertions(+), 4 deletions(-) >>> >>> diff --git a/kernel/auditsc.c b/kernel/auditsc.c >>> index 21eae3c..ff99c05 100644 >>> --- a/kernel/auditsc.c >>> +++ b/kernel/auditsc.c >>> @@ -1886,12 +1886,18 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, >>> } >>> >>> out_alloc: >>> - /* unable to find the name from a previous getname(). Allocate a new >>> - * anonymous entry. >>> - */ >>> - n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); >>> + /* unable to find an entry with both a matching name and type */ >>> + n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); >>> if (!n) >>> return; >>> + if (name) >>> + /* since name is not NULL we know there is already a matching >>> + * name record, see audit_getname(), so there must be a type >>> + * mismatch; reuse the string path since the original name >>> + * record will keep the string valid until we free it in >>> + * audit_free_names() */ >>> + n->name = name; >>> + >>> out: >>> if (parent) { >>> n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; >> >> Looks to do what is claimed. Represents a regression against P. >> >> Acked-by: Andy Whitcroft <apw@canonical.com> >> >> -apw > > I've tested with linux-image-3.2.0-23-generic and > linux-image-3.2.0-79-virtual in my manual bisect. Both are good. > > The following is the detail process. > Test of the following kernel fail: > linux-image-3.13.0-031300-generic_3.13.0-031300.201401192235_amd64.deb > linux-image-3.13.0-24-generic > linux-image-3.13.0-46-generic > linux-image-3.15.0-031500-generic_3.15.0-031500.201406131105_amd64.deb > linux-image-3.17.0-031700-generic_3.17.0-031700.201410060605_amd64.deb > linux-image-3.18.0-031800-generic_3.18.0-031800.201412071935_amd64.deb > linux-image-3.18.9-031809-generic_3.18.9-031809.201503080036_amd64.deb > > Success: > linux-image-3.2.0-23-generic > linux-image-3.2.0-79-virtual > linux-image-3.19.0-031900rc2-generic_3.19.0-031900rc2.201412290135_amd64.deb > linux-image-3.19.0-031900rc4-generic_3.19.0-031900rc4.201501112135_amd64.deb > linux-image-3.19.0-031900-generic_3.19.0-031900.201502091451_amd64.deb > linux-image-4.0.0-040000rc6-generic_4.0.0-040000rc6.201503291935_amd64.deb > > > Bisect process: > linux-image-3.13.0-031300-generic_3.13.0-031300.201401192235_amd64.deb - fail > linux-image-3.13.0-24-generic - fail > linux-image-3.13.0-46-generic - fail > linux-image-3.15.0-031500-generic_3.15.0-031500.201406131105_amd64.deb - fail > linux-image-3.17.0-031700-generic_3.17.0-031700.201410060605_amd64.deb - fail > linux-image-3.18.0-031800-generic_3.18.0-031800.201412071935_amd64.deb - fail > linux-image-3.18.9-031809-generic_3.18.9-031809.201503080036_amd64.deb - fail > linux-image-3.19.0-031900rc1-generic_3.19.0-031900rc1.201412210135_amd64.deb > - fail > linux-image-3.19.0-031900rc2-generic_3.19.0-031900rc2.201412290135_amd64.deb > - success > linux-image-3.19.0-031900rc4-generic_3.19.0-031900rc4.201501112135_amd64.deb > - success > linux-image-3.19.0-031900-generic_3.19.0-031900.201502091451_amd64.deb - success > linux-image-4.0.0-040000rc6-generic_4.0.0-040000rc6.201503291935_amd64.deb > - success > > Gavin >
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 21eae3c..ff99c05 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1886,12 +1886,18 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, } out_alloc: - /* unable to find the name from a previous getname(). Allocate a new - * anonymous entry. - */ - n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); + /* unable to find an entry with both a matching name and type */ + n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); if (!n) return; + if (name) + /* since name is not NULL we know there is already a matching + * name record, see audit_getname(), so there must be a type + * mismatch; reuse the string path since the original name + * record will keep the string valid until we free it in + * audit_free_names() */ + n->name = name; + out: if (parent) { n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;