1818
1919#include < errno.h>
2020#include < fcntl.h>
21+ #include < linux/capability.h>
22+ #include < pwd.h>
2123#include < signal.h>
2224#include < stdio.h>
2325#include < string.h>
26+ #include < sys/prctl.h>
2427#include < unistd.h>
2528
2629#include < mutex>
@@ -34,6 +37,11 @@ namespace modelbox {
3437
3538static int kPidFileFd = -1 ;
3639
40+ extern " C" int capget (struct __user_cap_header_struct *header,
41+ struct __user_cap_data_struct *cap);
42+ extern " C" int capset (struct __user_cap_header_struct *header,
43+ struct __user_cap_data_struct *cap);
44+
3745std::once_flag root_dir_flag;
3846
3947const std::string &modelbox_root_dir () {
@@ -244,6 +252,90 @@ int modelbox_cpu_register_data(char *buf, int buf_size, ucontext_t *ucontext) {
244252 return 0 ;
245253}
246254
255+ Status GetUidGid (const std::string &user, uid_t &uid, gid_t &gid) {
256+ struct passwd *result = nullptr ;
257+ struct passwd pwd;
258+ std::vector<char > buff;
259+ ssize_t bufsize = 0 ;
260+ int ret = -1 ;
261+
262+ if (user == " " ) {
263+ return {STATUS_INVALID, " user is empty" };
264+ }
265+
266+ bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
267+ if (bufsize == -1 ) {
268+ bufsize = 1024 * 16 ;
269+ }
270+
271+ buff.reserve (bufsize);
272+ ret = getpwnam_r (user.c_str (), &pwd, buff.data (), bufsize, &result);
273+ if (ret != 0 ) {
274+ return {STATUS_FAULT, " get user " + user + " failed: " + StrError (errno)};
275+ }
276+
277+ if (result == nullptr ) {
278+ return {STATUS_NOTFOUND, " user " + user + " not found" };
279+ }
280+
281+ uid = result->pw_uid ;
282+ gid = result->pw_gid ;
283+
284+ return STATUS_OK;
285+ }
286+
287+ Status ChownToUser (const std::string &user, const std::string &path) {
288+ uid_t uid = 0 ;
289+ gid_t gid = 0 ;
290+ int unused __attribute__ ((unused)) = 0 ;
291+
292+ auto ret = GetUidGid (user, uid, gid);
293+ if (ret != STATUS_OK) {
294+ return ret;
295+ }
296+
297+ if (chown (path.c_str (), uid, gid) != 0 ) {
298+ return {STATUS_INVALID, " chown " + path + " failed: " + StrError (errno)};
299+ }
300+
301+ return STATUS_OK;
302+ }
303+
304+ Status RunAsUser (const std::string &user) {
305+ struct __user_cap_data_struct cap;
306+ struct __user_cap_header_struct header;
307+ header.version = _LINUX_CAPABILITY_VERSION;
308+ header.pid = 0 ;
309+ uid_t uid = 0 ;
310+ gid_t gid = 0 ;
311+ int unused __attribute__ ((unused)) = 0 ;
312+
313+ auto ret = GetUidGid (user, uid, gid);
314+ if (ret != STATUS_OK) {
315+ return ret;
316+ }
317+
318+ if (getuid () == uid) {
319+ return STATUS_OK;
320+ }
321+
322+ if (capget (&header, &cap) < 0 ) {
323+ return {STATUS_INVALID, " capget failed: " + StrError (errno)};
324+ }
325+
326+ prctl (PR_SET_KEEPCAPS, 1 , 0 , 0 , 0 );
327+ cap.effective |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
328+ cap.permitted |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
329+ unused = setgid (gid);
330+ unused = setuid (uid);
331+ if (capset (&header, &cap) < 0 ) {
332+ return {STATUS_INVALID, " capset failed: " + StrError (errno)};
333+ }
334+
335+ prctl (PR_SET_KEEPCAPS, 0 , 0 , 0 , 0 );
336+ return STATUS_OK;
337+ }
338+
247339Status SplitIPPort (const std::string &host, std::string &ip,
248340 std::string &port) {
249341 auto pos = host.find_last_of (' :' );
0 commit comments