Ambient capabilities for setpriv
cover Ambient capabilities for setpriv
Hi,
this patch series implements support for ambient capabilities in setpriv(1). Ambient capabilities have been implemented with Linux 4.3 by Andy Lutomirski [1]. Quoting from capabilities(7):
This is a set of capabilities that are preserved across an execve(2) of a program that is not privileged.
The patches are inspired and squarely based on published patches for util-linux by Andy [2]. As these commits seem to never have been upstreamed, I've contacted Andy a few days ago whether he intends to do so in the near future, but got no response. Anyway, as I would like to have ambient capabilities available in setpriv, I took up the baton and wrote this patch series.
Regards
Patrick
[1]: https://lwn.net/Articles/636533/
[2]: https://git.kernel.org/pub/scm/linux/kernel/git/luto/util-linux-playground.git/commit/?h=cap_ambient&id=860c73ac1acaaae976bdd3bb83b89b0180f0702a
Patrick Steinhardt (5):
setpriv: introduce indirection for capng_type enum
setpriv: proxy function checking whether a capability is set
setpriv: proxy function to update capabilities
setpriv: support dumping ambient capabilities
setpriv: support modifying the set of ambient capabilities
sys-utils/setpriv.1 | 8 ++-- sys-utils/setpriv.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 14 deletions(-)
Signature · 1 line
2.13.1
PATCH 1/5 setpriv: introduce indirection for `capng_type` enum
The capng_type is used to distinguish the different types of capability sets, that is the effective, inheratibale, permitted capabilities as well as the capability bounding set. In Linux 4.3, a new set of capabilities was introduced with ambient capabilities. Unfortunately, libcap-ng does not provide any support for these kind of capabilities and as such, we will have to roll our own support.
As a first step, we introduce an indirection for the capng_type enum, allowing us to add the ambient capability type later on. Right now, no functional change is expected from this change and in fact, each of the newly introduce enums should have the same value as respective enum of libcap-ng.
--- sys-utils/setpriv.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-)
sys-utils/setpriv.c +19 -11
@@ -48,6 +48,13 @@#define SETPRIV_EXIT_PRIVERR 127/* how we exit when we fail to set privs */ +enum cap_type { +CAP_TYPE_EFFECTIVE =CAPNG_EFFECTIVE , +CAP_TYPE_PERMITTED =CAPNG_PERMITTED , +CAP_TYPE_INHERITABLE =CAPNG_INHERITABLE , +CAP_TYPE_BOUNDING =CAPNG_BOUNDING_SET +}; +/* * Note: We are subject to https://bugzilla.redhat.com/show_bug.cgi?id=895105 * and we will therefore have problems if new capabilities are added. Once
@@ -156,12 +163,12 @@ static int real_cap_last_cap(void) }/* Returns the number of capabilities printed. */ -static int print_caps (FILE *f,capng_type_t which) +static int print_caps (FILE *f,enum cap_type which) {int i, n =0 , max =real_cap_last_cap ();for (i =0 ; i <= max; i++) { -if (capng_have_capability (which, i)) { +if (capng_have_capability ((capng_type_t ) which, i)) {const char *name =capng_capability_to_name (i);if (n)fputc (',' , f);
@@ -175,6 +182,7 @@ static int print_caps(FILE *f, capng_type_t which) n++; } } +return n; }
@@ -323,23 +331,23 @@ static void dump(int dumplevel)if (2 <= dumplevel) {printf (_ ("Effective capabilities: " )); -if (print_caps (stdout,CAPNG_EFFECTIVE ) ==0 ) +if (print_caps (stdout,CAP_TYPE_EFFECTIVE ) ==0 )printf (_ ("[none]" ));printf ("\n" );printf (_ ("Permitted capabilities: " )); -if (print_caps (stdout,CAPNG_PERMITTED ) ==0 ) +if (print_caps (stdout,CAP_TYPE_PERMITTED ) ==0 )printf (_ ("[none]" ));printf ("\n" ); }printf (_ ("Inheritable capabilities: " )); -if (print_caps (stdout,CAPNG_INHERITABLE ) ==0 ) +if (print_caps (stdout,CAP_TYPE_INHERITABLE ) ==0 )printf (_ ("[none]" ));printf ("\n" );printf (_ ("Capability bounding set: " )); -if (print_caps (stdout,CAPNG_BOUNDING_SET ) ==0 ) +if (print_caps (stdout,CAP_TYPE_BOUNDING ) ==0 )printf (_ ("[none]" ));printf ("\n" );
@@ -426,7 +434,7 @@ static void bump_cap(unsigned int cap)capng_update (CAPNG_ADD ,CAPNG_EFFECTIVE , cap); } -static void do_caps (capng_type_t type,const char *caps) +static void do_caps (enum cap_type type,const char *caps) {char *my_caps =xstrdup (caps);char *c;
@@ -448,11 +456,11 @@ static void do_caps(capng_type_t type, const char *caps)errx (SETPRIV_EXIT_PRIVERR ,_ ("libcap-ng is too old for \"all\" caps" ));for (i =0 ; i <=CAP_LAST_CAP ; i++) -capng_update (action, type, i); +capng_update (action, (capng_type_t ) type, i); }else {int cap =capng_name_to_capability (c +1 );if (0 <= cap) -capng_update (action, type, cap); +capng_update (action, (capng_type_t ) type, cap);else errx (EXIT_FAILURE ,_ ("unknown capability \"%s\"" ), c +1 );
@@ -886,14 +894,14 @@ int main(int argc, char **argv)err (SETPRIV_EXIT_PRIVERR ,_ ("set process securebits failed" ));if (opts.bounding_set) { -do_caps (CAPNG_BOUNDING_SET , opts.bounding_set); +do_caps (CAP_TYPE_BOUNDING , opts.bounding_set); errno =EPERM ;/* capng doesn't set errno if we're missing CAP_SETPCAP */ if (capng_apply (CAPNG_SELECT_BOUNDS ) !=0 )err (SETPRIV_EXIT_PRIVERR ,_ ("apply bounding set" )); }if (opts.caps_to_inherit) { -do_caps (CAPNG_INHERITABLE , opts.caps_to_inherit); +do_caps (CAP_TYPE_INHERITABLE , opts.caps_to_inherit);if (capng_apply (CAPNG_SELECT_CAPS ) !=0 )err (SETPRIV_EXIT_PRIVERR ,_ ("apply capabilities" )); }
Signature · 1 line
2.13.1
Re: [PATCH 1/5] setpriv: introduce indirection for `capng_type` enum
Quoted 7 lines · Patrick Steinhardt
The
capng_typeis used to distinguish the different types of capability sets, that is the effective, inheratibale, permitted capabilities as well as the capability bounding set. In Linux 4.3, a new set of capabilities was introduced with ambient capabilities. Unfortunately, libcap-ng does not provide any support for these kind of capabilities and as such, we will have to roll our own support.
Quoted 5 lines
As a first step, we introduce an indirection for the
capng_typeenum, allowing us to add the ambient capability type later on. Right now, no functional change is expected from this change and in fact, each of the newly introduce enums should have the same value as respective enum of libcap-ng.
Looks good to me.
PATCH 2/5 setpriv: proxy function checking whether a capability is set
In reply to Patrick SteinhardtThe loop in print_caps iterates over every capability, checks whether it is set and, if so, prints out its name. Currently, the checking and printing is rather intertwined, making it harder to extend the check whether we own a capability.
Prepare code for the introduction of ambient capabilities by disentangling the code checking for a capability and printing code. A new function has_cap is introduced and print_caps will now simply call out to it and only handle printing itself. This easily allows to extend the capability check based on which capability set is queried.
--- sys-utils/setpriv.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
sys-utils/setpriv.c +20 -1
@@ -162,13 +162,32 @@ static int real_cap_last_cap(void)return ret; } +static int has_cap (enum cap_type which,unsigned int i) +{ +switch (which) { +case CAP_TYPE_EFFECTIVE : +case CAP_TYPE_BOUNDING : +case CAP_TYPE_INHERITABLE : +case CAP_TYPE_PERMITTED : +return capng_have_capability (which, i); +default : +warnx (_ ("invalid capability type" )); +return -1 ; + } +} +/* Returns the number of capabilities printed. */ static int print_caps (FILE *f,enum cap_type which) {int i, n =0 , max =real_cap_last_cap ();for (i =0 ; i <= max; i++) { -if (capng_have_capability ((capng_type_t ) which, i)) { +int ret =has_cap (which, i); + +if (i ==0 && ret <0 ) +return -1 ; + +if (ret ==1 ) {const char *name =capng_capability_to_name (i);if (n)fputc (',' , f);
Signature · 1 line
2.13.1
Re: [PATCH 2/5] setpriv: proxy function checking whether a capability is set
Quoted 11 lines · Patrick Steinhardt
The loop in
print_capsiterates over every capability, checks whether it is set and, if so, prints out its name. Currently, the checking and printing is rather intertwined, making it harder to extend the check whether we own a capability.Prepare code for the introduction of ambient capabilities by disentangling the code checking for a capability and printing code. A new function
has_capis introduced andprint_capswill now simply call out to it and only handle printing itself. This easily allows to extend the capability check based on which capability set is queried.
PATCH 3/5 setpriv: proxy function to update capabilities
In reply to Patrick Steinhardtlibcap-ng provides a function to update capabilities with capng_update. As libcap-ng has not yet been updated to enable modification of ambient capabilities, we cannot use it to update this set, though. In order to allow easily extending the logic to also handle ambient capability sets, we create a new function cap_update. Right now, it simply calls out to capng_update for all supported capability types.
--- sys-utils/setpriv.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
sys-utils/setpriv.c +17 -2
@@ -453,6 +453,21 @@ static void bump_cap(unsigned int cap)capng_update (CAPNG_ADD ,CAPNG_EFFECTIVE , cap); } +static int cap_update (capng_act_t action, +enum cap_type type,unsigned int cap) +{ +switch (type) { +case CAP_TYPE_EFFECTIVE : +case CAP_TYPE_BOUNDING : +case CAP_TYPE_INHERITABLE : +case CAP_TYPE_PERMITTED : +return capng_update (action, (capng_type_t ) type, cap); +default : +errx (EXIT_FAILURE ,_ ("unsupported capability type" )); +return -1 ; + } +} +static void do_caps (enum cap_type type,const char *caps) {char *my_caps =xstrdup (caps);
@@ -475,11 +490,11 @@ static void do_caps(enum cap_type type, const char *caps)errx (SETPRIV_EXIT_PRIVERR ,_ ("libcap-ng is too old for \"all\" caps" ));for (i =0 ; i <=CAP_LAST_CAP ; i++) -capng_update (action, (capng_type_t ) type, i); +cap_update (action, type, i); }else {int cap =capng_name_to_capability (c +1 );if (0 <= cap) -capng_update (action, (capng_type_t ) type, cap); +cap_update (action, type, cap);else errx (EXIT_FAILURE ,_ ("unknown capability \"%s\"" ), c +1 );
Signature · 1 line
2.13.1
Re: [PATCH 3/5] setpriv: proxy function to update capabilities
Quoted 8 lines · Patrick Steinhardt
libcap-ng provides a function to update capabilities with
capng_update. As libcap-ng has not yet been updated to enable modification of ambient capabilities, we cannot use it to update this set, though. In order to allow easily extending the logic to also handle ambient capability sets, we create a new functioncap_update. Right now, it simply calls out tocapng_updatefor all supported capability types.
PATCH 4/5 setpriv: support dumping ambient capabilities
In reply to Patrick SteinhardtOur code dumping owned capabilities does not yet handle ambient capabilities, which were only recently introduced with Linux 4.3. This commit implements printing ambient capabilities if they're supported by the system.
Based on a patch by Andy Lutomirski.
--- sys-utils/setpriv.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
sys-utils/setpriv.c +18 -1
@@ -46,13 +46,19 @@# define PR_GET_NO_NEW_PRIVS 39#endif +#ifndef PR_CAP_AMBIENT +# define PR_CAP_AMBIENT 47 +# define PR_CAP_AMBIENT_IS_SET 1 +#endif +#define SETPRIV_EXIT_PRIVERR 127/* how we exit when we fail to set privs */ enum cap_type {CAP_TYPE_EFFECTIVE =CAPNG_EFFECTIVE ,CAP_TYPE_PERMITTED =CAPNG_PERMITTED ,CAP_TYPE_INHERITABLE =CAPNG_INHERITABLE , -CAP_TYPE_BOUNDING =CAPNG_BOUNDING_SET +CAP_TYPE_BOUNDING =CAPNG_BOUNDING_SET , +CAP_TYPE_AMBIENT = (1 <<4 ) };/*
@@ -170,6 +176,9 @@ static int has_cap(enum cap_type which, unsigned int i)case CAP_TYPE_INHERITABLE :case CAP_TYPE_PERMITTED :return capng_have_capability (which, i); +case CAP_TYPE_AMBIENT : +return prctl (PR_CAP_AMBIENT ,PR_CAP_AMBIENT_IS_SET , + (unsigned long ) i,0UL ,0UL );default :warnx (_ ("invalid capability type" ));return -1 ;
@@ -365,6 +374,14 @@ static void dump(int dumplevel)printf (_ ("[none]" ));printf ("\n" ); +printf (_ ("Ambient capabilities: " )); + x =print_caps (stdout,CAP_TYPE_AMBIENT ); +if (x ==0 ) +printf (_ ("[none]" )); +if (x <0 ) +printf (_ ("[unsupported]" )); +printf ("\n" ); +printf (_ ("Capability bounding set: " ));if (print_caps (stdout,CAP_TYPE_BOUNDING ) ==0 )printf (_ ("[none]" ));
Signature · 1 line
2.13.1
Re: [PATCH 4/5] setpriv: support dumping ambient capabilities
Quoted 7 lines · Patrick Steinhardt
Our code dumping owned capabilities does not yet handle ambient capabilities, which were only recently introduced with Linux 4.3. This commit implements printing ambient capabilities if they're supported by the system.
Based on a patch by Andy Lutomirski.
PATCH 5/5 setpriv: support modifying the set of ambient capabilities
In reply to Patrick SteinhardtRight now, we do not support modifying the set of ambient capabilities, which has been introduced quite recently with Linux 4.3. As libcap-ng does not yet provide any ability to modify this set, we do have to roll our own support via prctl, which is now easy to do due to the indirections introduced in the preceding commits. We add a new command line argument "--ambient-caps", which uses the same syntax as both "--inh-caps" and "--bounding-set" to specify either adding or dropping capabilities.
This commit also adjusts documentation to mention the newly introduced ability to modify the ambient capability set.
Based on a patch by Andy Lutomirski.
--- sys-utils/setpriv.1 | 8 +++++--- sys-utils/setpriv.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-)
sys-utils/setpriv.1 +5 -3
@@ -27,8 +27,8 @@ mostly useless, information. Incompatible with all other options. .B \-\-groups \fIgroup\fR... Set supplementary groups. The argument is a comma-separated list. .TP -.BR \-\-inh\-caps " (" + | \- ) \fIcap "... or " \-\-bounding\-set " (" + | \- ) \fIcap ... -Set the inheritable capabilities or the capability bounding set. See +.BR \-\-inh\-caps " (" + | \- ) \fIcap "... or " \-\-ambient-caps " (" + | \- ) \fIcap "... or " \-\-bounding\-set " (" + | \- ) \fIcap ... +Set the inheritable capabilities, ambient capabilities or the capability bounding set. See .BR capabilities (7). The argument is a comma-separated list of .BI + cap
@@ -40,7 +40,9 @@ and .B \-all can be used to add or remove all caps. The set of capabilities starts out as the current inheritable set for -.B \-\-inh\-caps +.BR \-\-inh\-caps , +the current ambient set for +.B \-\-ambient\-caps and the current bounding set for .BR \-\-bounding\-set . If you drop something from the bounding set without also dropping it from the
sys-utils/setpriv.c +28 -0
@@ -49,6 +49,8 @@#ifndef PR_CAP_AMBIENT # define PR_CAP_AMBIENT 47# define PR_CAP_AMBIENT_IS_SET 1 +# define PR_CAP_AMBIENT_RAISE 2 +# define PR_CAP_AMBIENT_LOWER 3#endif #define SETPRIV_EXIT_PRIVERR 127/* how we exit when we fail to set privs */
@@ -95,6 +97,7 @@ struct privctx {/* caps */ const char *caps_to_inherit; +const char *ambient_caps;const char *bounding_set;/* securebits */
@@ -479,6 +482,19 @@ static int cap_update(capng_act_t action,case CAP_TYPE_INHERITABLE :case CAP_TYPE_PERMITTED :return capng_update (action, (capng_type_t ) type, cap); +case CAP_TYPE_AMBIENT : + { +int ret; + +if (action ==CAPNG_ADD ) + ret =prctl (PR_CAP_AMBIENT ,PR_CAP_AMBIENT_RAISE , + (unsigned long ) cap,0UL ,0UL ); +else + ret =prctl (PR_CAP_AMBIENT ,PR_CAP_AMBIENT_LOWER , + (unsigned long ) cap,0UL ,0UL ); + +return ret; + }default :errx (EXIT_FAILURE ,_ ("unsupported capability type" ));return -1 ;
@@ -687,6 +703,7 @@ int main(int argc, char **argv)INIT_GROUPS ,GROUPS ,INHCAPS , +AMBCAPS ,LISTCAPS ,CAPBSET , SECUREBITS,
@@ -699,6 +716,7 @@ int main(int argc, char **argv) { "nnp", no_argument, NULL, NNP }, { "no-new-privs", no_argument, NULL, NNP }, { "inh-caps", required_argument, NULL, INHCAPS }, + { "ambient-caps", required_argument, NULL, AMBCAPS }, { "list-caps", no_argument, NULL, LISTCAPS }, { "ruid", required_argument, NULL, RUID }, { "euid", required_argument, NULL, EUID },
@@ -831,6 +849,12 @@ int main(int argc, char **argv) _("duplicate --inh-caps option")); opts.caps_to_inherit = optarg;break ; +case AMBCAPS : +if (opts.ambient_caps) +errx (EXIT_FAILURE , +_ ("duplicate --ambient-caps option" )); + opts.ambient_caps = optarg; +break ;case CAPBSET :if (opts.bounding_set) errx(EXIT_FAILURE,
@@ -957,6 +981,10 @@ int main(int argc, char **argv)err (SETPRIV_EXIT_PRIVERR ,_ ("apply capabilities" )); } +if (opts.ambient_caps) { +do_caps (CAP_TYPE_AMBIENT , opts.ambient_caps); + } +execvp (argv[optind], argv + optind);err (EXIT_FAILURE ,_ ("cannot execute: %s" ), argv[optind]);
Signature · 1 line
2.13.1
Re: [PATCH 5/5] setpriv: support modifying the set of ambient capabilities
Quoted 9 lines · Patrick Steinhardt
Right now, we do not support modifying the set of ambient capabilities, which has been introduced quite recently with Linux 4.3. As libcap-ng does not yet provide any ability to modify this set, we do have to roll our own support via
prctl, which is now easy to do due to the indirections introduced in the preceding commits. We add a new command line argument "--ambient-caps", which uses the same syntax as both "--inh-caps" and "--bounding-set" to specify either adding or dropping capabilities.
Quoted 3 lines
This commit also adjusts documentation to mention the newly introduced ability to modify the ambient capability set.
One question here: should requesting an ambient cap also implicitly put it in the inheritable set, at least if --inh-caps isn't specified?
--Andy
Re: [PATCH 5/5] setpriv: support modifying the set of ambient capabilities
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines · Patrick Steinhardt
Right now, we do not support modifying the set of ambient capabilities, which has been introduced quite recently with Linux 4.3. As libcap-ng does not yet provide any ability to modify this set, we do have to roll our own support via
prctl, which is now easy to do due to the indirections introduced in the preceding commits. We add a new command line argument "--ambient-caps", which uses the same syntax as both "--inh-caps" and "--bounding-set" to specify either adding or dropping capabilities.
Quoted 6 lines
Quoted 3 lines
This commit also adjusts documentation to mention the newly introduced ability to modify the ambient capability set.
One question here: should requesting an ambient cap also implicitly put it in the inheritable set, at least if --inh-caps isn't specified?
Good question. By itself, it doesn't make any sense to have an ambient capability without having it set in the inheratibale capabilities, as otherwise the ambient capability wouldn't be granted at all. This is due to the invariant (quoting from your message at [1]):
pA obeys the invariant that no bit can ever be set in pA if it is not set in both pP and pI. Dropping a bit from pP or pI drops that bit from pA. This ensures that existing programs that try to drop capabilities still do so, with a complication.
With pA being ambient capabilities, pP being the permitted capabilities and pI being inheritable capabilities.
But given that you were being conservative here, we should probably err on the conservative side, as well. Meaning we force the user to be explicit and not automatically set the inheritable capability.
Quoted 9 lines · Patrick Steinhardt
Hi,
this patch series implements support for ambient capabilities in setpriv(1). Ambient capabilities have been implemented with Linux 4.3 by Andy Lutomirski [1]. Quoting from capabilities(7):
This is a set of capabilities that are preserved across an execve(2) of a program that is not privileged.
Quoted 6 lines
The patches are inspired and squarely based on published patches for util-linux by Andy [2]. As these commits seem to never have been upstreamed, I've contacted Andy a few days ago whether he intends to do so in the near future, but got no response. Anyway, as I would like to have ambient capabilities available in setpriv, I took up the baton and wrote this patch series.
Sorry, was swamped. I very much appreciate your doing this.
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines · Patrick Steinhardt
Hi,
this patch series implements support for ambient capabilities in setpriv(1). Ambient capabilities have been implemented with Linux 4.3 by Andy Lutomirski [1]. Quoting from capabilities(7):
This is a set of capabilities that are preserved across an execve(2) of a program that is not privileged.
Quoted 8 lines
Quoted 6 lines
The patches are inspired and squarely based on published patches for util-linux by Andy [2]. As these commits seem to never have been upstreamed, I've contacted Andy a few days ago whether he intends to do so in the near future, but got no response. Anyway, as I would like to have ambient capabilities available in setpriv, I took up the baton and wrote this patch series.
Sorry, was swamped. I very much appreciate your doing this.
No problem, and thanks for having a look!
Patrick
Quoted 10 lines · Patrick Steinhardt
Patrick Steinhardt (5):
setpriv: introduce indirection forcapng_typeenum
setpriv: proxy function checking whether a capability is set
setpriv: proxy function to update capabilities
setpriv: support dumping ambient capabilities
setpriv: support modifying the set of ambient capabilitiessys-utils/setpriv.1 | 8 ++-- sys-utils/setpriv.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 14 deletions(-)
Applied. (You've forgot to add --ambient-caps to usage(), fixed by additional commit.)
Thanks!
Karel
Signature · 2 lines
Karel Zak <[email protected]> http://karelzak.blogspot.com
Quoted 8 lines · Karel Zak
Quoted 7 lines · Patrick Steinhardt
Patrick Steinhardt (5):
setpriv: introduce indirection forcapng_typeenum
setpriv: proxy function checking whether a capability is set
setpriv: proxy function to update capabilities
setpriv: support dumping ambient capabilities
setpriv: support modifying the set of ambient capabilities
Quoted 8 lines
Quoted 3 lines
sys-utils/setpriv.1 | 8 ++-- sys-utils/setpriv.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 14 deletions(-)Applied. (You've forgot to add --ambient-caps to
usage(), fixed by additional commit.)Thanks!
Thanks for applying and the fixup!
Regards
Patrick