mirror_zfs/lib/libspl/os/linux/gethostid.c
Richard Yao 72a366f018
Linux: Fix big endian and partial read bugs in get_system_hostid()
Coverity made two complaints about this function. The first is that we
ignore the number of bytes read. The second is that we have a sizeof
mismatch.

On 64-bit systems, long is a 64-bit type. Paradoxically, the standard
says that hostid is 32-bit, yet is also a long type. On 64-bit big
endian systems, reading into the long would cause us to return 0 as our
hostid after the mask. This is wrong.

Also, if a partial read were to happen (it should not), we would return
a partial hostid, which is also wrong.

We introduce a uint32_t system_hostid stack variable and ensure that the
read is done into it and check the read's return value. Then we set the
value based on whether the read was successful. This should fix both of
coverity's complaints.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Neal Gompa <ngompa@datto.com>
Signed-off-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
Closes #13968
2022-10-20 14:52:35 -07:00

84 lines
2.0 KiB
C

/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2017, Lawrence Livermore National Security, LLC.
*/
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/systeminfo.h>
static unsigned long
get_spl_hostid(void)
{
FILE *f;
unsigned long hostid;
char *env;
/*
* Allow the hostid to be subverted for testing.
*/
env = getenv("ZFS_HOSTID");
if (env)
return (strtoull(env, NULL, 0));
f = fopen("/proc/sys/kernel/spl/hostid", "re");
if (!f)
return (0);
if (fscanf(f, "%lx", &hostid) != 1)
hostid = 0;
fclose(f);
return (hostid);
}
unsigned long
get_system_hostid(void)
{
unsigned long hostid = get_spl_hostid();
uint32_t system_hostid;
/*
* We do not use gethostid(3) because it can return a bogus ID,
* depending on the libc and /etc/hostid presence,
* and the kernel and userspace must agree.
* See comments above hostid_read() in the SPL.
*/
if (hostid == 0) {
int fd = open("/etc/hostid", O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
if (read(fd, &system_hostid, sizeof (system_hostid))
!= sizeof (system_hostid))
hostid = 0;
else
hostid = system_hostid;
(void) close(fd);
}
}
return (hostid & HOSTID_MASK);
}