cap_syslog: don't refuse cap_sys_admin for now (v3)
PATCH 1/1 cap_syslog: don't refuse cap_sys_admin for now (v3)
In commit ce6ada35bdf710d16582cc4869c26722547e6f11, Serge messed up userspace backward compatibility. As Gergely pointed out, userspace which was doing the right thing and dropping all but cap_sys_admin before calling syslog is now breaking.
At 2.6.39 or 2.6.40, let's add a sysctl which defaults to 1. When 0, if the user has cap_sys_admin but no cap_syslog, return -EPERM. When 1 in that case, allow. Alternatively, as David pointed out, just leaving the behavior as below is still very useful.
Please apply.
--- kernel/printk.c | 26 ++++++++++++++++---------- 1 files changed, 16 insertions(+), 10 deletions(-)
kernel/printk.c +16 -10
@@ -274,12 +274,24 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)* at open time. */ if (type ==SYSLOG_ACTION_OPEN || !from_file) { -if (dmesg_restrict && !capable (CAP_SYSLOG )) - goto warn;/* switch to return -EPERM after 2.6.39 */ +if (dmesg_restrict && !capable (CAP_SYSLOG )) { +/* remove after 2.6.39 */ +if (capable (CAP_SYS_ADMIN )) +WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " +"but no CAP_SYSLOG (deprecated).\n" ); +else +return -EPERM ; + }if ((type !=SYSLOG_ACTION_READ_ALL && type !=SYSLOG_ACTION_SIZE_BUFFER ) && - !capable (CAP_SYSLOG )) - goto warn;/* switch to return -EPERM after 2.6.39 */ + !capable (CAP_SYSLOG )) { +/* remove after 2.6.39 */ +if (capable (CAP_SYS_ADMIN )) +WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " +"but no CAP_SYSLOG (deprecated).\n" ); +else +return -EPERM ; + } } error =security_syslog (type);
@@ -423,12 +435,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) } out:return error; -warn: -/* remove after 2.6.39 */ -if (capable (CAP_SYS_ADMIN )) -WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " -"but no CAP_SYSLOG (deprecated and denied).\n" ); -return -EPERM ; } SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
Signature · 1 line
1.7.2.3
Quoted 2 lines · Serge E. Hallyn
Please apply.
Hmm. So I detest the duplication and the ugly resulting code. It was a bit hard to follow before, now it's just nasty.
Why not make this all into some nicer helper functions instead - something simple like the attached?
UNTESTED! I'm not going to apply it unless I get acks/tested-by's.
Linus
kernel/printk.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 files changed, 35 insertions(+), 19 deletions(-)
kernel/printk.c +35 -19
@@ -262,25 +262,47 @@ int dmesg_restrict = 1;int dmesg_restrict;#endif +static int syslog_action_restricted (int type) +{ +if (dmesg_restrict) +return 1 ; +/* Unless restricted, we allow "read all" and "get buffer size" for everybody */ +return type !=SYSLOG_ACTION_READ_ALL && type !=SYSLOG_ACTION_SIZE_BUFFER ; +} + +static int check_syslog_permissions (int type,bool from_file) +{ +/* +* If this is from /proc/kmsg and we've already opened it, then we've +* already the capabilities checks at open time. +*/ +if (from_file && type !=SYSLOG_ACTION_OPEN ) +return 0 ; + +if (syslog_action_restricted (type)) { +if (capable (CAP_SYSLOG )) +return 0 ; +/* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ +if (capable (CAP_SYS_ADMIN )) { +WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " +"but no CAP_SYSLOG (deprecated).\n" ); +return 0 ; + } +return -EPERM ; + } +return 0 ; +} +int do_syslog (int type,char __user *buf,int len,bool from_file) {unsigned i, j, limit, count;int do_clear =0 ;char c; -int error =0 ; +int error; -/* -* If this is from /proc/kmsg we only do the capabilities checks -* at open time. -*/ -if (type ==SYSLOG_ACTION_OPEN || !from_file) { -if (dmesg_restrict && !capable (CAP_SYSLOG )) - goto warn;/* switch to return -EPERM after 2.6.39 */ -if ((type !=SYSLOG_ACTION_READ_ALL && - type !=SYSLOG_ACTION_SIZE_BUFFER ) && - !capable (CAP_SYSLOG )) - goto warn;/* switch to return -EPERM after 2.6.39 */ - } + error =check_syslog_permissions (type, from_file); +if (error) + goto out; error =security_syslog (type);if (error)
@@ -423,12 +445,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) } out:return error; -warn: -/* remove after 2.6.39 */ -if (capable (CAP_SYS_ADMIN )) -WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " -"but no CAP_SYSLOG (deprecated and denied).\n" ); -return -EPERM ; } SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
Serge E. Hallyn
Acked-byQuoted 7 lines · Linus Torvalds
Quoted 2 lines · Serge E. Hallyn
Please apply.
Hmm. So I detest the duplication and the ugly resulting code. It was a bit hard to follow before, now it's just nasty.
Quoted 6 lines
Why not make this all into some nicer helper functions instead - something simple like the attached?
UNTESTED! I'm not going to apply it unless I get acks/tested-by's.
Linus
It looks correct (and much nicer indeed)
Setting up a box to actually test on...
thanks,
-serge
Quoted 81 lines
kernel/printk.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 files changed, 35 insertions(+), 19 deletions(-)kernel/printk.c +35
-19@@ -262,25 +262,47 @@ int dmesg_restrict = 1;int dmesg_restrict;#endif +static int syslog_action_restricted (int type) +{ +if (dmesg_restrict) +return 1 ; +/* Unless restricted, we allow "read all" and "get buffer size" for everybody */ +return type !=SYSLOG_ACTION_READ_ALL && type !=SYSLOG_ACTION_SIZE_BUFFER ; +} + +static int check_syslog_permissions (int type,bool from_file) +{ +/* +* If this is from /proc/kmsg and we've already opened it, then we've +* already the capabilities checks at open time. +*/ +if (from_file && type !=SYSLOG_ACTION_OPEN ) +return 0 ; + +if (syslog_action_restricted (type)) { +if (capable (CAP_SYSLOG )) +return 0 ; +/* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ +if (capable (CAP_SYS_ADMIN )) { +WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " +"but no CAP_SYSLOG (deprecated).\n" ); +return 0 ; + } +return -EPERM ; + } +return 0 ; +} +int do_syslog (int type,char __user *buf,int len,bool from_file) {unsigned i, j, limit, count;int do_clear =0 ;char c; -int error =0 ; +int error; -/* -* If this is from /proc/kmsg we only do the capabilities checks -* at open time. -*/ -if (type ==SYSLOG_ACTION_OPEN || !from_file) { -if (dmesg_restrict && !capable (CAP_SYSLOG )) - goto warn;/* switch to return -EPERM after 2.6.39 */ -if ((type !=SYSLOG_ACTION_READ_ALL && - type !=SYSLOG_ACTION_SIZE_BUFFER ) && - !capable (CAP_SYSLOG )) - goto warn;/* switch to return -EPERM after 2.6.39 */ - } + error =check_syslog_permissions (type, from_file); +if (error) + goto out; error =security_syslog (type);if (error)@@ -423,12 +445,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) } out:return error; -warn: -/* remove after 2.6.39 */ -if (capable (CAP_SYS_ADMIN )) -WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " -"but no CAP_SYSLOG (deprecated and denied).\n" ); -return -EPERM ; } SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
James Morris
Reviewed-byQuoted 11 lines · Linus Torvalds
Quoted 2 lines · Serge E. Hallyn
Please apply.
Hmm. So I detest the duplication and the ugly resulting code. It was a bit hard to follow before, now it's just nasty.
Why not make this all into some nicer helper functions instead - something simple like the attached?
UNTESTED! I'm not going to apply it unless I get acks/tested-by's.
Signature · 2 lines
James Morris <[email protected]>
Quoted 11 lines · Linus Torvalds
Quoted 2 lines · Serge E. Hallyn
Please apply.
Hmm. So I detest the duplication and the ugly resulting code. It was a bit hard to follow before, now it's just nasty.
Why not make this all into some nicer helper functions instead - something simple like the attached?
UNTESTED! I'm not going to apply it unless I get acks/tested-by's.
I tested using klogctl with actions 10, 3 and 5. Without dmesg_restrict set, an unprivileged program could get the size and read-all, but not clear the buffer. With either CAP_SYS_ADMIN or CAP_SYSLOG, it could do all three. With dmesg_restrict set, the capabilities were needed for all actions.
Worked perfectly.
thanks,
-serge
Quoted 83 lines
Linus
kernel/printk.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 files changed, 35 insertions(+), 19 deletions(-)kernel/printk.c +35
-19@@ -262,25 +262,47 @@ int dmesg_restrict = 1;int dmesg_restrict;#endif +static int syslog_action_restricted (int type) +{ +if (dmesg_restrict) +return 1 ; +/* Unless restricted, we allow "read all" and "get buffer size" for everybody */ +return type !=SYSLOG_ACTION_READ_ALL && type !=SYSLOG_ACTION_SIZE_BUFFER ; +} + +static int check_syslog_permissions (int type,bool from_file) +{ +/* +* If this is from /proc/kmsg and we've already opened it, then we've +* already the capabilities checks at open time. +*/ +if (from_file && type !=SYSLOG_ACTION_OPEN ) +return 0 ; + +if (syslog_action_restricted (type)) { +if (capable (CAP_SYSLOG )) +return 0 ; +/* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ +if (capable (CAP_SYS_ADMIN )) { +WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " +"but no CAP_SYSLOG (deprecated).\n" ); +return 0 ; + } +return -EPERM ; + } +return 0 ; +} +int do_syslog (int type,char __user *buf,int len,bool from_file) {unsigned i, j, limit, count;int do_clear =0 ;char c; -int error =0 ; +int error; -/* -* If this is from /proc/kmsg we only do the capabilities checks -* at open time. -*/ -if (type ==SYSLOG_ACTION_OPEN || !from_file) { -if (dmesg_restrict && !capable (CAP_SYSLOG )) - goto warn;/* switch to return -EPERM after 2.6.39 */ -if ((type !=SYSLOG_ACTION_READ_ALL && - type !=SYSLOG_ACTION_SIZE_BUFFER ) && - !capable (CAP_SYSLOG )) - goto warn;/* switch to return -EPERM after 2.6.39 */ - } + error =check_syslog_permissions (type, from_file); +if (error) + goto out; error =security_syslog (type);if (error)@@ -423,12 +445,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) } out:return error; -warn: -/* remove after 2.6.39 */ -if (capable (CAP_SYS_ADMIN )) -WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " -"but no CAP_SYSLOG (deprecated and denied).\n" ); -return -EPERM ; } SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
[PATCH/RFC] cap_syslog: make CAP_SYS_ADMIN deprecation notice less alarming
In reply to Linus Torvaldssyslog-ng versions in active use assume that CAP_SYS_ADMIN is sufficent to access syslog. As a result, ever since CAP_SYSLOG was introduce in v2.6.38-rc1~429^2~18 (security: Define CAP_SYSLOG, 2010-11-25), they have triggered a warning, complete with kernel backtrace.
v2.6.38-rc5~46 (cap_syslog: accept CAP_SYS_ADMIN for now, 2011-02-10) made things a little better by removing the regression in behavior, just keeping the WARN_ONCE. But still, this is a warning that adds many lines to syslog, sets a taint flag, and alarms sysadmins when nothing worse has happened than use of an old userspace with a recent kernel.
Convert the WARN_ONCE to a printk_once to avoid this while continuing to give userspace developers a hint that this is an unwanted backward-compatibility feature and won't be around forever.
---
Hi,
Nothing urgent about this, but it seems to be a frequently[1] reported[2] source of unnecessary worry. Thoughts?
[1] http://thread.gmane.org/gmane.linux.kernel/1145040
[2] http://thread.gmane.org/gmane.linux.kernel/1153808
Context: http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=32;bug=636501
kernel/printk.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
kernel/printk.c +2 -1
@@ -318,7 +318,8 @@ static int check_syslog_permissions(int type, bool from_file)return 0 ;/* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ if (capable (CAP_SYS_ADMIN )) { -WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " +printk_once (KERN_WARNING +"Attempt to access syslog with CAP_SYS_ADMIN " "but no CAP_SYSLOG (deprecated).\n" );return 0 ; }
Signature · 1 line
1.7.6
Re: [PATCH/RFC] cap_syslog: make CAP_SYS_ADMIN deprecation notice less alarming
Quoted 3 lines · Jonathan Nieder
Convert the
WARN_ONCEto aprintk_onceto avoid this while continuing to give userspace developers a hint that this is an unwanted backward-compatibility feature and won't be around forever.
Seems reasonable to me.
Signature · 2 lines
James Morris <[email protected]>
Serge E. Hallyn
Acked-byRe: [PATCH/RFC] cap_syslog: make CAP_SYS_ADMIN deprecation notice less alarming
In reply to Jonathan NiederQuoted 10 lines · Jonathan Nieder
syslog-ng versions in active use assume that
CAP_SYS_ADMINis sufficent to access syslog. As a result, ever sinceCAP_SYSLOGwas introduce in v2.6.38-rc1~429^2~18 (security: DefineCAP_SYSLOG, 2010-11-25), they have triggered a warning, complete with kernel backtrace.v2.6.38-rc5~46 (
cap_syslog: acceptCAP_SYS_ADMINfor now, 2011-02-10) made things a little better by removing the regression in behavior, just keeping theWARN_ONCE. But still, this is a warning that adds many lines to syslog, sets a taint flag, and alarms sysadmins when
Sets the taint flag? That's a bit over the top, so:
Quoted 7 lines
nothing worse has happened than use of an old userspace with a recent kernel.
Convert the
WARN_ONCEto aprintk_onceto avoid this while continuing to give userspace developers a hint that this is an unwanted backward-compatibility feature and won't be around forever.
Quoted 5 lines
Reported-by Ralf Hildebrandt <[email protected]>Reported-by Niels <[email protected]>Reported-by Paweł Sikora <[email protected]>Liked-by Gergely Nagy <[email protected]>Signed-off-by Jonathan Nieder <[email protected]>
thanks,
-serge
Quoted 31 lines
---
Hi,Nothing urgent about this, but it seems to be a frequently[1] reported[2] source of unnecessary worry. Thoughts?
[1] http://thread.gmane.org/gmane.linux.kernel/1145040
[2] http://thread.gmane.org/gmane.linux.kernel/1153808Context: http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=32;bug=636501
kernel/printk.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)kernel/printk.c +2
-1@@ -318,7 +318,8 @@ static int check_syslog_permissions(int type, bool from_file)return 0 ;/* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ if (capable (CAP_SYS_ADMIN )) { -WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " +printk_once (KERN_WARNING +"Attempt to access syslog with CAP_SYS_ADMIN " "but no CAP_SYSLOG (deprecated).\n" );return 0 ; }Signature · 1 line
1.7.6
Re: [PATCH/RFC] cap_syslog: make CAP_SYS_ADMIN deprecation notice less alarming
In reply to Jonathan NiederQuoted 3 lines · Jonathan Nieder
Convert the
WARN_ONCEto aprintk_onceto avoid this while continuing to give userspace developers a hint that this is an unwanted backward-compatibility feature and won't be around forever.
Applied togit://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6#next-queue
Signature · 2 lines
James Morris <[email protected]>
Re: [PATCH/RFC] cap_syslog: make CAP_SYS_ADMIN deprecation notice less alarming
In reply to Jonathan NiederQuoted 4 lines · Jonathan Nieder
Convert the
WARN_ONCEto aprintk_onceto avoid this while continuing to give userspace developers a hint that this is an unwanted backward-compatibility feature and won't be around forever.
The problem with this one is that converting away from a warning doesn't just get rid of all the ugliness, it gets rid of some of the *useful* information in the warning too.
In particular, when you have a warning like "Attempting to access syslog", you'd better tell people *who* is attempting to access syslog, so that they can fix it or complain to the right person.
And the warning does show what process it is (in addition to stacktrace, tainting etc that we don't want). Your printk_once() conversion does not.
Linus
PATCH v2 1/1 cap_syslog: don't use WARN_ONCE for CAP_SYS_ADMIN deprecation warning
syslog-ng versions before 3.3.0beta1 (2011-05-12) assume that CAP_SYS_ADMIN is sufficient to access syslog, so ever since CAP_SYSLOG was introduced (2010-11-25) they have triggered a warning. v2.6.38-rc5~46 (cap_syslog: accept CAP_SYS_ADMIN for now, 2011-02-10) improved matters a little by making syslog-ng work again, just keeping the WARN_ONCE(). But still, this is a warning that writes a stack trace we don't care about to syslog, sets a taint flag, and alarms sysadmins when nothing worse has happened than use of an old userspace with a recent kernel.
Convert the WARN_ONCE to a printk_once to avoid that while continuing to give userspace developers a hint that this is an unwanted backward-compatibility feature and won't be around forever.
---
Quoted 7 lines · Linus Torvalds
The problem with this one is that converting away from a warning doesn't just get rid of all the ugliness, it gets rid of some of the *useful* information in the warning too.
In particular, when you have a warning like "Attempting to access syslog", you'd better tell people *who* is attempting to access syslog, so that they can fix it or complain to the right person.
True. I can't imagine people wanting to know much more than the process's command line and pid, which is basically what the WARN_ONCE gives (though it also gives registers). Here's an updated patch.
I've carried over the acks from last time; hopefully that's okay. Thanks for your help.
kernel/printk.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
kernel/printk.c +4 -2
@@ -318,8 +318,10 @@ static int check_syslog_permissions(int type, bool from_file)return 0 ;/* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ if (capable (CAP_SYS_ADMIN )) { -WARN_ONCE (1 ,"Attempt to access syslog with CAP_SYS_ADMIN " -"but no CAP_SYSLOG (deprecated).\n" ); +printk_once (KERN_WARNING "%s (%d): " +"Attempt to access syslog with CAP_SYS_ADMIN " +"but no CAP_SYSLOG (deprecated).\n" , + current->comm,task_pid_nr (current));return 0 ; }return -EPERM ;
Signature · 1 line
1.7.6