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
|
|
|
|
2014-06-27 15:16:54 +00:00
|
|
|
|
2019-10-14 12:25:14 +00:00
|
|
|
int virSetBlocking(int fd, bool blocking) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virSetNonBlock(int fd) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virSetInherit(int fd, bool inherit) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virSetCloseExec(int fd) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virSetSockReuseAddr(int fd, bool fatal) G_GNUC_WARN_UNUSED_RESULT;
|
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)
|
2019-10-14 12:25:14 +00:00
|
|
|
ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT;
|
2012-03-05 16:28:59 +00:00
|
|
|
|
2012-09-25 17:31:01 +00:00
|
|
|
char *virFormatIntDecimal(char *buf, size_t buflen, int val)
|
2019-10-14 12:25:14 +00:00
|
|
|
ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT;
|
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);
|
2021-03-03 09:20:00 +00:00
|
|
|
char *virIndexToDiskName(unsigned 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. */
|
2020-09-01 11:27:44 +00:00
|
|
|
#ifndef WITH_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
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#ifndef WITH_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
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#ifndef WITH_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
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#ifndef WITH_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
|
|
|
|
2022-07-18 11:02:19 +00:00
|
|
|
char *virGetHostname(void) G_NO_INLINE;
|
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);
|
2022-07-18 11:02:19 +00:00
|
|
|
char *virGetUserRuntimeDirectory(void) G_NO_INLINE;
|
2016-04-12 17:11:20 +00:00
|
|
|
char *virGetUserShell(uid_t uid);
|
2022-07-18 11:02:19 +00:00
|
|
|
char *virGetUserName(uid_t uid) G_NO_INLINE;
|
|
|
|
char *virGetGroupName(gid_t gid) G_NO_INLINE;
|
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,
|
2019-10-14 12:25:14 +00:00
|
|
|
uid_t *uid) G_GNUC_WARN_UNUSED_RESULT;
|
2010-02-04 22:41:52 +00:00
|
|
|
int virGetGroupID(const char *name,
|
2019-10-14 12:25:14 +00:00
|
|
|
gid_t *gid) G_GNUC_WARN_UNUSED_RESULT;
|
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
|
|
|
|
|
|
|
|
2012-09-11 08:57:02 +00:00
|
|
|
bool virValidateWWN(const char *wwn);
|
|
|
|
|
2013-05-24 15:35:01 +00:00
|
|
|
int virParseOwnershipIds(const char *label, uid_t *uidPtr, gid_t *gidPtr);
|
|
|
|
|
2014-03-05 17:20:50 +00:00
|
|
|
|
|
|
|
time_t virGetSelfLastChanged(void);
|
|
|
|
void virUpdateSelfLastChanged(const char *path);
|
|
|
|
|
2022-07-18 11:02:19 +00:00
|
|
|
long virGetSystemPageSize(void) G_NO_INLINE;
|
|
|
|
long virGetSystemPageSizeKB(void) G_NO_INLINE;
|
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);
|
2022-07-18 11:02:19 +00:00
|
|
|
unsigned long long virMemoryMaxValue(bool ulong) G_NO_INLINE;
|
2015-03-04 14:08:09 +00:00
|
|
|
|
2018-06-01 08:15:58 +00:00
|
|
|
bool virHostHasIOMMU(void);
|
|
|
|
|
2022-07-18 11:02:19 +00:00
|
|
|
char *virHostGetDRMRenderNode(void) G_NO_INLINE;
|
2018-11-08 10:47:09 +00:00
|
|
|
|
2020-06-15 08:28:06 +00:00
|
|
|
/* Kernel cmdline match and comparison strategy for arg=value pairs */
|
|
|
|
typedef enum {
|
|
|
|
/* substring comparison of argument values */
|
|
|
|
VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX = 1,
|
|
|
|
|
|
|
|
/* strict string comparison of argument values */
|
|
|
|
VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ = 2,
|
|
|
|
|
|
|
|
/* look for any occurrence of the argument with the expected value,
|
|
|
|
* this should be used when an argument set to the expected value overrides
|
|
|
|
* all the other occurrences of the argument, e.g. when looking for 'arg=1'
|
|
|
|
* in 'arg=0 arg=1 arg=0' the search would succeed with this flag
|
|
|
|
*/
|
|
|
|
VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST = 4,
|
|
|
|
|
|
|
|
/* look for the last occurrence of argument with the expected value,
|
|
|
|
* this should be used when the last occurrence of the argument overrides
|
|
|
|
* all the other ones, e.g. when looking for 'arg=1' in 'arg=0 arg=1' the
|
|
|
|
* search would succeed with this flag, but in 'arg=1 arg=0' it would not,
|
|
|
|
* because 'arg=0' overrides all the previous occurrences of 'arg'
|
|
|
|
*/
|
|
|
|
VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST = 8,
|
|
|
|
} virKernelCmdlineFlags;
|
|
|
|
|
|
|
|
const char *virKernelCmdlineNextParam(const char *cmdline,
|
|
|
|
char **param,
|
|
|
|
char **val);
|
|
|
|
|
|
|
|
bool virKernelCmdlineMatchParam(const char *cmdline,
|
|
|
|
const char *arg,
|
|
|
|
const char **values,
|
|
|
|
size_t len_values,
|
|
|
|
virKernelCmdlineFlags flags);
|
|
|
|
|
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))
|
2020-01-14 10:40:52 +00:00
|
|
|
|
|
|
|
char *virGetPassword(void);
|
2020-01-24 15:21:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* virPipe:
|
|
|
|
*
|
|
|
|
* Open a pair of FDs which can be used to communicate
|
|
|
|
* with each other. The FDs will have O_CLOEXEC set.
|
|
|
|
* This will report a libvirt error on failure.
|
|
|
|
*
|
|
|
|
* Returns: -1 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int virPipe(int fds[2]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* virPipeQuiet:
|
|
|
|
*
|
|
|
|
* Open a pair of FDs which can be used to communicate
|
|
|
|
* with each other. The FDs will have O_CLOEXEC set.
|
|
|
|
* This will set errno on failure.
|
|
|
|
*
|
|
|
|
* Returns: -1 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int virPipeQuiet(int fds[2]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* virPipe:
|
|
|
|
*
|
|
|
|
* Open a pair of FDs which can be used to communicate
|
|
|
|
* with each other. The FDs will have O_CLOEXEC and
|
|
|
|
* O_NONBLOCK set.
|
|
|
|
* This will report a libvirt error on failure.
|
|
|
|
*
|
|
|
|
* Returns: -1 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int virPipeNonBlock(int fds[2]);
|