]> git.ipfire.org Git - thirdparty/util-linux.git/blame - lib/caputils.c
Merge branch 'ci/meson-werror' of https://github.com/t-8ch/util-linux
[thirdparty/util-linux.git] / lib / caputils.c
CommitLineData
cef4decf
JP
1/*
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
5 * later version.
6 *
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.
11 *
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.
15 */
16
5d958187 17#include <sys/prctl.h>
cef4decf 18#include <stdio.h>
96642021 19#include <stdlib.h>
5d958187 20#include <limits.h>
96642021 21#include <errno.h>
cef4decf 22
96642021 23#include "c.h"
cef4decf
JP
24#include "caputils.h"
25#include "pathnames.h"
c0f40fe5 26#include "procfs.h"
acb72212 27#include "nls.h"
cef4decf 28
5d958187
ÉR
29static int test_cap(unsigned int cap)
30{
31 /* prctl returns 0 or 1 for valid caps, -1 otherwise */
32 return prctl(PR_CAPBSET_READ, cap, 0, 0, 0) >= 0;
33}
34
96642021
KZ
35static int cap_last_by_bsearch(int *ret)
36{
37 /* starting with cap=INT_MAX means we always know
38 * that cap1 is invalid after the first iteration */
39 int cap = INT_MAX;
40 unsigned int cap0 = 0, cap1 = INT_MAX;
41
42 while ((int)cap0 < cap) {
43 if (test_cap(cap))
44 cap0 = cap;
45 else
46 cap1 = cap;
47
48 cap = (cap0 + cap1) / 2U;
49 }
50
51 *ret = cap;
52 return 0;
53}
54
55static int cap_last_by_procfs(int *ret)
56{
57 FILE *f = fopen(_PATH_PROC_CAPLASTCAP, "r");
58 int rc = -EINVAL;
59
60 *ret = 0;
61
c0f40fe5 62 if (f && fd_is_procfs(fileno(f))) {
96642021
KZ
63 int cap;
64
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)) {
68
69 *ret = cap;
70 rc = 0;
71 }
72 }
73
74 if (f)
75 fclose(f);
76 return rc;
77}
78
cef4decf
JP
79int cap_last_cap(void)
80{
5d958187 81 static int cap = -1;
cef4decf 82
5d958187
ÉR
83 if (cap != -1)
84 return cap;
96642021
KZ
85 if (cap_last_by_procfs(&cap) < 0)
86 cap_last_by_bsearch(&cap);
cef4decf 87
96642021
KZ
88 return cap;
89}
5d958187 90
acb72212
DG
91void cap_permitted_to_ambient(void)
92{
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,
98 .pid = 0,
99 };
100 struct __user_cap_data_struct payload[_LINUX_CAPABILITY_U32S_3] = {{ 0 }};
101 uint64_t effective, cap;
102
103 if (capget(&header, payload) < 0)
104 err(EXIT_FAILURE, _("capget failed"));
105
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;
110
111 if (capset(&header, payload) < 0)
112 err(EXIT_FAILURE, _("capset failed"));
113
114 effective = ((uint64_t)payload[1].effective << 32) | (uint64_t)payload[0].effective;
115
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())
120 continue;
121
01a0a556 122 if ((effective & (1ULL << cap))
acb72212
DG
123 && prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0)
124 err(EXIT_FAILURE, _("prctl(PR_CAP_AMBIENT) failed"));
125 }
126}
127
96642021
KZ
128#ifdef TEST_PROGRAM_CAPUTILS
129int main(int argc, char *argv[])
130{
131 int rc = 0, cap;
5d958187 132
96642021
KZ
133 if (argc < 2) {
134 fprintf(stderr, "usage: %1$s --last-by-procfs\n"
135 " %1$s --last-by-bsearch\n"
136 " %1$s --last\n",
137 program_invocation_short_name);
138 return EXIT_FAILURE;
cef4decf
JP
139 }
140
96642021
KZ
141 if (strcmp(argv[1], "--last-by-procfs") == 0) {
142 rc = cap_last_by_procfs(&cap);
143 if (rc == 0)
144 printf("last cap: %d\n", cap);
cef4decf 145
96642021
KZ
146 } else if (strcmp(argv[1], "--last-by-bsearch") == 0) {
147 rc = cap_last_by_bsearch(&cap);
148 if (rc == 0)
149 printf("last cap: %d\n", cap);
cef4decf 150
96642021
KZ
151 } else if (strcmp(argv[1], "--last") == 0)
152 printf("last cap: %d\n", cap_last_cap());
153
154 return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
cef4decf 155}
96642021 156#endif