]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/caps.c
clang: Remaining changes
[mirror_lxc.git] / src / lxc / caps.c
CommitLineData
b3357a6f
DL
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
b3357a6f
DL
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
b3357a6f
DL
22 */
23
24#define _GNU_SOURCE
25#include <unistd.h>
20d81659
CS
26#include <fcntl.h>
27#include <stdlib.h>
28#include <limits.h>
b3357a6f 29#include <sys/prctl.h>
2b657f10 30#include <errno.h>
b3357a6f 31
495d2046 32#include "config.h"
b3357a6f 33#include "log.h"
025ed0f3 34#include "lxclock.h"
b3357a6f
DL
35
36lxc_log_define(lxc_caps, lxc);
37
495d2046
SG
38#if HAVE_SYS_CAPABILITY_H
39#include <sys/capability.h>
40
cbec0030
SG
41#ifndef PR_CAPBSET_READ
42#define PR_CAPBSET_READ 23
43#endif
44
05cda563
DL
45int lxc_caps_reset(void)
46{
47 cap_t cap = cap_init();
48 int ret = 0;
49
50 if (!cap) {
51 ERROR("cap_init() failed : %m");
52 return -1;
53 }
54
55 if (cap_set_proc(cap)) {
56 ERROR("cap_set_proc() failed : %m");
57 ret = -1;
58 }
59
60 cap_free(cap);
61 return ret;
62}
63
b3357a6f
DL
64int lxc_caps_down(void)
65{
66 cap_t caps;
67 int ret;
68
7ee895e4
DL
69 /* when we are run as root, we don't want to play
70 * with the capabilities */
71 if (!getuid())
72 return 0;
73
b3357a6f
DL
74 caps = cap_get_proc();
75 if (!caps) {
76 ERROR("failed to cap_get_proc: %m");
77 return -1;
78 }
79
80 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
81 if (ret) {
82 ERROR("failed to cap_clear_flag: %m");
83 goto out;
84 }
85
86 ret = cap_set_proc(caps);
87 if (ret) {
88 ERROR("failed to cap_set_proc: %m");
89 goto out;
90 }
91
92out:
93 cap_free(caps);
94 return 0;
95}
96
97int lxc_caps_up(void)
98{
99 cap_t caps;
100 cap_value_t cap;
101 int ret;
102
7ee895e4
DL
103 /* when we are run as root, we don't want to play
104 * with the capabilities */
105 if (!getuid())
106 return 0;
107
b3357a6f
DL
108 caps = cap_get_proc();
109 if (!caps) {
110 ERROR("failed to cap_get_proc: %m");
111 return -1;
112 }
113
114 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
115
116 cap_flag_value_t flag;
117
118 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
119 if (ret) {
2b657f10
SH
120 if (errno == EINVAL) {
121 INFO("Last supported cap was %d\n", cap-1);
122 break;
123 } else {
124 ERROR("failed to cap_get_flag: %m");
125 goto out;
126 }
b3357a6f
DL
127 }
128
129 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
130 if (ret) {
131 ERROR("failed to cap_set_flag: %m");
132 goto out;
133 }
134 }
135
136 ret = cap_set_proc(caps);
137 if (ret) {
138 ERROR("failed to cap_set_proc: %m");
139 goto out;
140 }
141
142out:
143 cap_free(caps);
144 return 0;
145}
146
147int lxc_caps_init(void)
148{
149 uid_t uid = getuid();
150 gid_t gid = getgid();
151 uid_t euid = geteuid();
152
153 if (!uid) {
154 INFO("command is run as 'root'");
155 return 0;
156 }
157
158 if (uid && !euid) {
159 INFO("command is run as setuid root (uid : %d)", uid);
160
161 if (prctl(PR_SET_KEEPCAPS, 1)) {
162 ERROR("failed to 'PR_SET_KEEPCAPS': %m");
163 return -1;
164 }
165
166 if (setresgid(gid, gid, gid)) {
167 ERROR("failed to change gid to '%d': %m", gid);
168 return -1;
169 }
170
171 if (setresuid(uid, uid, uid)) {
172 ERROR("failed to change uid to '%d': %m", uid);
173 return -1;
174 }
175
176 if (lxc_caps_up()) {
177 ERROR("failed to restore capabilities: %m");
178 return -1;
179 }
180 }
181
182 if (uid == euid)
183 INFO("command is run as user '%d'", uid);
184
185 return 0;
186}
20d81659
CS
187
188static int _real_caps_last_cap(void)
189{
190 int fd;
191 int result = -1;
192
193 /* try to get the maximum capability over the kernel
194 * interface introduced in v3.2 */
025ed0f3 195 process_lock();
20d81659 196 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
025ed0f3 197 process_unlock();
20d81659
CS
198 if (fd >= 0) {
199 char buf[32];
200 char *ptr;
201 int n;
202
203 if ((n = read(fd, buf, 31)) >= 0) {
204 buf[n] = '\0';
205 result = strtol(buf, &ptr, 10);
206 if (!ptr || (*ptr != '\0' && *ptr != '\n') ||
f371aca9 207 result == INT_MIN || result == INT_MAX)
20d81659
CS
208 result = -1;
209 }
210
025ed0f3 211 process_lock();
20d81659 212 close(fd);
025ed0f3 213 process_unlock();
20d81659
CS
214 }
215
216 /* try to get it manually by trying to get the status of
217 * each capability indiviually from the kernel */
218 if (result < 0) {
219 int cap = 0;
220 while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++;
221 result = cap - 1;
222 }
223
224 return result;
225}
226
227int lxc_caps_last_cap(void)
228{
229 static int last_cap = -1;
230 if (last_cap < 0) last_cap = _real_caps_last_cap();
231
232 return last_cap;
233}
4a2ca8b2 234
495d2046 235#endif