2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2, or (at your option) any
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
12 * You should have received a copy of the GNU General Public License along
13 * with this program; if not, write to the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 #include <sys/prctl.h>
25 #include "pathnames.h"
29 static int test_cap(unsigned int cap
)
31 /* prctl returns 0 or 1 for valid caps, -1 otherwise */
32 return prctl(PR_CAPBSET_READ
, cap
, 0, 0, 0) >= 0;
35 static int cap_last_by_bsearch(int *ret
)
37 /* starting with cap=INT_MAX means we always know
38 * that cap1 is invalid after the first iteration */
40 unsigned int cap0
= 0, cap1
= INT_MAX
;
42 while ((int)cap0
< cap
) {
48 cap
= (cap0
+ cap1
) / 2U;
55 static int cap_last_by_procfs(int *ret
)
57 FILE *f
= fopen(_PATH_PROC_CAPLASTCAP
, "r");
62 if (f
&& fd_is_procfs(fileno(f
))) {
65 /* we check if the cap after this one really isn't valid */
66 if (fscanf(f
, "%d", &cap
) == 1 &&
67 cap
< INT_MAX
&& !test_cap(cap
+ 1)) {
79 int cap_last_cap(void)
85 if (cap_last_by_procfs(&cap
) < 0)
86 cap_last_by_bsearch(&cap
);
91 void cap_permitted_to_ambient(void)
93 /* We use capabilities system calls to propagate the permitted
94 * capabilities into the ambient set because we may have
95 * already forked so be in async-signal-safe context. */
96 struct __user_cap_header_struct header
= {
97 .version
= _LINUX_CAPABILITY_VERSION_3
,
100 struct __user_cap_data_struct payload
[_LINUX_CAPABILITY_U32S_3
] = {{ 0 }};
101 uint64_t effective
, cap
;
103 if (capget(&header
, payload
) < 0)
104 err(EXIT_FAILURE
, _("capget failed"));
106 /* In order the make capabilities ambient, we first need to ensure
107 * that they are all inheritable. */
108 payload
[0].inheritable
= payload
[0].permitted
;
109 payload
[1].inheritable
= payload
[1].permitted
;
111 if (capset(&header
, payload
) < 0)
112 err(EXIT_FAILURE
, _("capset failed"));
114 effective
= ((uint64_t)payload
[1].effective
<< 32) | (uint64_t)payload
[0].effective
;
116 for (cap
= 0; cap
< (sizeof(effective
) * 8); cap
++) {
117 /* This is the same check as cap_valid(), but using
118 * the runtime value for the last valid cap. */
119 if (cap
> (uint64_t) cap_last_cap())
122 if ((effective
& (1ULL << cap
))
123 && prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0) < 0)
124 err(EXIT_FAILURE
, _("prctl(PR_CAP_AMBIENT) failed"));
128 #ifdef TEST_PROGRAM_CAPUTILS
129 int main(int argc
, char *argv
[])
134 fprintf(stderr
, "usage: %1$s --last-by-procfs\n"
135 " %1$s --last-by-bsearch\n"
137 program_invocation_short_name
);
141 if (strcmp(argv
[1], "--last-by-procfs") == 0) {
142 rc
= cap_last_by_procfs(&cap
);
144 printf("last cap: %d\n", cap
);
146 } else if (strcmp(argv
[1], "--last-by-bsearch") == 0) {
147 rc
= cap_last_by_bsearch(&cap
);
149 printf("last cap: %d\n", cap
);
151 } else if (strcmp(argv
[1], "--last") == 0)
152 printf("last cap: %d\n", cap_last_cap());
154 return rc
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;