2007-07-19 16:22:40 +00:00
|
|
|
/*
|
2012-12-13 17:44:57 +00:00
|
|
|
* virutil.h: common, generic utility functions
|
2007-07-19 16:22:40 +00:00
|
|
|
*
|
2014-01-10 21:01:10 +00:00
|
|
|
* Copyright (C) 2010-2014 Red Hat, Inc.
|
2007-07-19 16:22:40 +00:00
|
|
|
* Copyright (C) 2006, 2007 Binary Karma
|
|
|
|
* Copyright (C) 2006 Shuveb Hussain
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2007-07-19 16:22:40 +00:00
|
|
|
*/
|
|
|
|
|
2019-06-18 16:13:08 +00:00
|
|
|
#pragma once
|
2007-12-03 14:30:46 +00:00
|
|
|
|
2019-06-18 16:13:08 +00:00
|
|
|
#include "internal.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
2007-12-03 14:30:46 +00:00
|
|
|
|
2019-06-18 16:13:08 +00:00
|
|
|
#ifndef MIN
|
|
|
|
# define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
#endif
|
|
|
|
#ifndef MAX
|
|
|
|
# define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
|
|
#endif
|
2010-04-14 15:40:14 +00:00
|
|
|
|
2014-06-27 15:16:54 +00:00
|
|
|
|
2011-03-08 18:04:06 +00:00
|
|
|
int virSetBlocking(int fd, bool blocking) ATTRIBUTE_RETURN_CHECK;
|
2009-10-16 10:09:13 +00:00
|
|
|
int virSetNonBlock(int fd) ATTRIBUTE_RETURN_CHECK;
|
2011-03-26 11:19:28 +00:00
|
|
|
int virSetInherit(int fd, bool inherit) ATTRIBUTE_RETURN_CHECK;
|
2009-10-16 10:09:13 +00:00
|
|
|
int virSetCloseExec(int fd) ATTRIBUTE_RETURN_CHECK;
|
2014-09-07 15:05:03 +00:00
|
|
|
int virSetSockReuseAddr(int fd, bool fatal) ATTRIBUTE_RETURN_CHECK;
|
2009-01-20 16:36:34 +00:00
|
|
|
|
util: make virSetUIDGID async-signal-safe
https://bugzilla.redhat.com/show_bug.cgi?id=964358
POSIX states that multi-threaded apps should not use functions
that are not async-signal-safe between fork and exec, yet we
were using getpwuid_r and initgroups. Although rare, it is
possible to hit deadlock in the child, when it tries to grab
a mutex that was already held by another thread in the parent.
I actually hit this deadlock when testing multiple domains
being started in parallel with a command hook, with the following
backtrace in the child:
Thread 1 (Thread 0x7fd56bbf2700 (LWP 3212)):
#0 __lll_lock_wait ()
at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:136
#1 0x00007fd5761e7388 in _L_lock_854 () from /lib64/libpthread.so.0
#2 0x00007fd5761e7257 in __pthread_mutex_lock (mutex=0x7fd56be00360)
at pthread_mutex_lock.c:61
#3 0x00007fd56bbf9fc5 in _nss_files_getpwuid_r (uid=0, result=0x7fd56bbf0c70,
buffer=0x7fd55c2a65f0 "", buflen=1024, errnop=0x7fd56bbf25b8)
at nss_files/files-pwd.c:40
#4 0x00007fd575aeff1d in __getpwuid_r (uid=0, resbuf=0x7fd56bbf0c70,
buffer=0x7fd55c2a65f0 "", buflen=1024, result=0x7fd56bbf0cb0)
at ../nss/getXXbyYY_r.c:253
#5 0x00007fd578aebafc in virSetUIDGID (uid=0, gid=0) at util/virutil.c:1031
#6 0x00007fd578aebf43 in virSetUIDGIDWithCaps (uid=0, gid=0, capBits=0,
clearExistingCaps=true) at util/virutil.c:1388
#7 0x00007fd578a9a20b in virExec (cmd=0x7fd55c231f10) at util/vircommand.c:654
#8 0x00007fd578a9dfa2 in virCommandRunAsync (cmd=0x7fd55c231f10, pid=0x0)
at util/vircommand.c:2247
#9 0x00007fd578a9d74e in virCommandRun (cmd=0x7fd55c231f10, exitstatus=0x0)
at util/vircommand.c:2100
#10 0x00007fd56326fde5 in qemuProcessStart (conn=0x7fd53c000df0,
driver=0x7fd55c0dc4f0, vm=0x7fd54800b100, migrateFrom=0x0, stdin_fd=-1,
stdin_path=0x0, snapshot=0x0, vmop=VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
flags=1) at qemu/qemu_process.c:3694
...
The solution is to split the work of getpwuid_r/initgroups into the
unsafe portions (getgrouplist, called pre-fork) and safe portions
(setgroups, called post-fork).
* src/util/virutil.h (virSetUIDGID, virSetUIDGIDWithCaps): Adjust
signature.
* src/util/virutil.c (virSetUIDGID): Add parameters.
(virSetUIDGIDWithCaps): Adjust clients.
* src/util/vircommand.c (virExec): Likewise.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* src/security/security_dac.c (virSecurityDACSetProcessLabel):
Likewise.
* src/lxc/lxc_container.c (lxcContainerSetID): Likewise.
* configure.ac (AC_CHECK_FUNCS_ONCE): Check for setgroups, not
initgroups.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-05-22 02:59:10 +00:00
|
|
|
int virSetUIDGID(uid_t uid, gid_t gid, gid_t *groups, int ngroups);
|
|
|
|
int virSetUIDGIDWithCaps(uid_t uid, gid_t gid, gid_t *groups, int ngroups,
|
|
|
|
unsigned long long capBits,
|
2013-03-13 19:26:35 +00:00
|
|
|
bool clearExistingCaps);
|
2010-12-23 06:44:02 +00:00
|
|
|
|
2017-02-20 12:00:51 +00:00
|
|
|
void virWaitForDevices(void);
|
|
|
|
|
2012-03-05 16:28:59 +00:00
|
|
|
int virScaleInteger(unsigned long long *value, const char *suffix,
|
|
|
|
unsigned long long scale, unsigned long long limit)
|
|
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
|
|
|
2010-08-27 21:13:45 +00:00
|
|
|
int virHexToBin(unsigned char c);
|
|
|
|
|
2011-07-01 13:23:02 +00:00
|
|
|
int virParseVersionString(const char *str, unsigned long *version,
|
|
|
|
bool allowMissing);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2012-09-25 17:31:01 +00:00
|
|
|
char *virFormatIntDecimal(char *buf, size_t buflen, int val)
|
|
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
2012-08-11 19:13:00 +00:00
|
|
|
|
2017-11-09 15:19:25 +00:00
|
|
|
unsigned long long
|
|
|
|
virFormatIntPretty(unsigned long long val,
|
|
|
|
const char **unit);
|
|
|
|
|
2015-11-13 13:14:44 +00:00
|
|
|
int virDiskNameParse(const char *name, int *disk, int *partition);
|
2008-05-09 16:41:19 +00:00
|
|
|
int virDiskNameToIndex(const char* str);
|
2009-12-03 16:17:40 +00:00
|
|
|
char *virIndexToDiskName(int idx, const char *prefix);
|
2008-06-24 15:00:15 +00:00
|
|
|
|
2014-01-10 21:01:10 +00:00
|
|
|
/* No-op workarounds for functionality missing in mingw. */
|
2019-06-18 16:13:08 +00:00
|
|
|
#ifndef HAVE_GETUID
|
2014-03-18 08:14:35 +00:00
|
|
|
static inline int getuid(void)
|
|
|
|
{ return 0; }
|
2019-06-18 16:13:08 +00:00
|
|
|
#endif
|
2008-09-05 12:03:45 +00:00
|
|
|
|
2019-06-18 16:13:08 +00:00
|
|
|
#ifndef HAVE_GETEUID
|
2014-03-18 08:14:35 +00:00
|
|
|
static inline int geteuid(void)
|
|
|
|
{ return 0; }
|
2019-06-18 16:13:08 +00:00
|
|
|
#endif
|
2011-03-11 15:49:39 +00:00
|
|
|
|
2019-06-18 16:13:08 +00:00
|
|
|
#ifndef HAVE_GETGID
|
2014-03-18 08:14:35 +00:00
|
|
|
static inline int getgid(void)
|
|
|
|
{ return 0; }
|
2019-06-18 16:13:08 +00:00
|
|
|
#endif
|
2008-09-05 12:03:45 +00:00
|
|
|
|
2019-06-18 16:13:08 +00:00
|
|
|
#ifndef HAVE_GETEGID
|
2014-03-18 08:14:35 +00:00
|
|
|
static inline int getegid(void)
|
|
|
|
{ return 0; }
|
2019-06-18 16:13:08 +00:00
|
|
|
#endif
|
2014-01-10 21:01:10 +00:00
|
|
|
|
2019-06-18 16:13:08 +00:00
|
|
|
#ifdef FUNC_PTHREAD_SIGMASK_BROKEN
|
|
|
|
# undef pthread_sigmask
|
2014-01-10 21:01:10 +00:00
|
|
|
static inline int pthread_sigmask(int how,
|
|
|
|
const void *set,
|
|
|
|
void *old)
|
|
|
|
{
|
|
|
|
(void) how;
|
|
|
|
(void) set;
|
|
|
|
(void) old;
|
|
|
|
return 0;
|
|
|
|
}
|
2019-06-18 16:13:08 +00:00
|
|
|
#endif
|
2013-10-17 13:51:32 +00:00
|
|
|
|
2013-04-26 16:39:11 +00:00
|
|
|
char *virGetHostname(void);
|
2015-12-04 17:35:54 +00:00
|
|
|
char *virGetHostnameQuiet(void);
|
2009-01-07 10:43:16 +00:00
|
|
|
|
2012-05-24 12:29:42 +00:00
|
|
|
char *virGetUserDirectory(void);
|
2013-07-30 19:55:44 +00:00
|
|
|
char *virGetUserDirectoryByUID(uid_t uid);
|
2012-05-24 12:29:42 +00:00
|
|
|
char *virGetUserConfigDirectory(void);
|
|
|
|
char *virGetUserCacheDirectory(void);
|
|
|
|
char *virGetUserRuntimeDirectory(void);
|
2016-04-12 17:11:20 +00:00
|
|
|
char *virGetUserShell(uid_t uid);
|
2017-07-12 10:07:17 +00:00
|
|
|
char *virGetUserName(uid_t uid) ATTRIBUTE_NOINLINE;
|
|
|
|
char *virGetGroupName(gid_t gid) ATTRIBUTE_NOINLINE;
|
2013-05-21 23:47:48 +00:00
|
|
|
int virGetGroupList(uid_t uid, gid_t group, gid_t **groups)
|
|
|
|
ATTRIBUTE_NONNULL(3);
|
2010-02-04 22:41:52 +00:00
|
|
|
int virGetUserID(const char *name,
|
2009-10-16 10:09:13 +00:00
|
|
|
uid_t *uid) ATTRIBUTE_RETURN_CHECK;
|
2010-02-04 22:41:52 +00:00
|
|
|
int virGetGroupID(const char *name,
|
2009-10-16 10:09:13 +00:00
|
|
|
gid_t *gid) ATTRIBUTE_RETURN_CHECK;
|
2009-01-22 19:41:48 +00:00
|
|
|
|
2018-11-19 21:31:01 +00:00
|
|
|
bool virDoesUserExist(const char *name);
|
|
|
|
bool virDoesGroupExist(const char *name);
|
2018-09-12 14:24:30 +00:00
|
|
|
|
|
|
|
|
2011-09-16 12:05:58 +00:00
|
|
|
bool virIsDevMapperDevice(const char *dev_name) ATTRIBUTE_NONNULL(1);
|
2011-04-29 09:28:28 +00:00
|
|
|
|
2012-09-11 08:57:02 +00:00
|
|
|
bool virValidateWWN(const char *wwn);
|
|
|
|
|
2013-01-02 14:37:06 +00:00
|
|
|
int virGetDeviceID(const char *path,
|
|
|
|
int *maj,
|
|
|
|
int *min);
|
|
|
|
int virSetDeviceUnprivSGIO(const char *path,
|
|
|
|
const char *sysfs_dir,
|
|
|
|
int unpriv_sgio);
|
|
|
|
int virGetDeviceUnprivSGIO(const char *path,
|
|
|
|
const char *sysfs_dir,
|
|
|
|
int *unpriv_sgio);
|
2013-03-25 16:43:40 +00:00
|
|
|
char *virGetUnprivSGIOSysfsPath(const char *path,
|
|
|
|
const char *sysfs_dir);
|
2013-03-25 16:43:42 +00:00
|
|
|
|
2013-05-24 15:35:01 +00:00
|
|
|
int virParseOwnershipIds(const char *label, uid_t *uidPtr, gid_t *gidPtr);
|
|
|
|
|
2013-10-09 09:52:39 +00:00
|
|
|
const char *virGetEnvBlockSUID(const char *name);
|
|
|
|
const char *virGetEnvAllowSUID(const char *name);
|
|
|
|
bool virIsSUID(void);
|
|
|
|
|
2014-03-05 17:20:50 +00:00
|
|
|
|
|
|
|
time_t virGetSelfLastChanged(void);
|
|
|
|
void virUpdateSelfLastChanged(const char *path);
|
|
|
|
|
2017-07-12 10:07:17 +00:00
|
|
|
long virGetSystemPageSize(void) ATTRIBUTE_NOINLINE;
|
|
|
|
long virGetSystemPageSizeKB(void) ATTRIBUTE_NOINLINE;
|
2015-02-02 10:26:49 +00:00
|
|
|
|
2015-03-04 14:08:09 +00:00
|
|
|
unsigned long long virMemoryLimitTruncate(unsigned long long value);
|
|
|
|
bool virMemoryLimitIsSet(unsigned long long value);
|
2017-07-12 10:07:17 +00:00
|
|
|
unsigned long long virMemoryMaxValue(bool ulong) ATTRIBUTE_NOINLINE;
|
2015-03-04 14:08:09 +00:00
|
|
|
|
2018-06-01 08:15:58 +00:00
|
|
|
bool virHostHasIOMMU(void);
|
|
|
|
|
2018-11-14 15:48:27 +00:00
|
|
|
char *virHostGetDRMRenderNode(void) ATTRIBUTE_NOINLINE;
|
2018-11-08 10:47:09 +00:00
|
|
|
|
2015-05-27 08:54:38 +00:00
|
|
|
/**
|
|
|
|
* VIR_ASSIGN_IS_OVERFLOW:
|
|
|
|
* @rvalue: value that is checked (evaluated twice)
|
|
|
|
* @lvalue: value that the check is against (used in typeof())
|
|
|
|
*
|
|
|
|
* This macro assigns @lvalue to @rvalue and evaluates as true if the value of
|
|
|
|
* @rvalue did not fit into the @lvalue.
|
|
|
|
*/
|
2019-06-18 16:13:08 +00:00
|
|
|
#define VIR_ASSIGN_IS_OVERFLOW(lvalue, rvalue) \
|
2015-05-27 08:54:38 +00:00
|
|
|
(((lvalue) = (rvalue)) != (rvalue))
|