selinux/policycoreutils/sestatus/sestatus.c
Christian Göttsche d8b9bd5c2a policycoreutils: free memory on lstat failure in sestatus
In case lstat(3) fails the memory is not free'd at the end of the for
loop, due to the control flow change by continue.

Found by scan-build.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-07-19 10:42:45 -04:00

489 lines
9.4 KiB
C

/*
* Copyright 1999-2004 Gentoo Technologies, Inc.
* Distributed under the terms of the GNU General Public License v2
* $Header: /home/cvsroot/gentoo-projects/hardened/policycoreutils-extra/src/sestatus.c,v 1.10 2004/03/26 19:25:52 pebenito Exp $
* Patch provided by Steve Grubb
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <selinux/selinux.h>
#include <selinux/get_default_type.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <libgen.h>
#include <ctype.h>
#include <limits.h>
#define PROC_BASE "/proc"
#define MAX_CHECK 50
#define CONF "/etc/sestatus.conf"
/* conf file sections */
#define PROCS "[process]"
#define FILES "[files]"
/* buffer size for cmp_cmdline */
#define BUFSIZE 255
/* column to put the output (must be a multiple of 8) */
static unsigned int COL = 32;
extern char *selinux_mnt;
int cmp_cmdline(const char *command, int pid)
{
char buf[BUFSIZE];
char filename[BUFSIZE];
memset(buf, '\0', BUFSIZE);
/* first read the proc entry */
sprintf(filename, "%s/%d/exe", PROC_BASE, pid);
if (readlink(filename, buf, BUFSIZE) < 0)
return 0;
if (buf[BUFSIZE - 1] != '\0')
buf[BUFSIZE - 1] = '\0';
/* check if this is the command we're looking for. */
if (strcmp(command, buf) == 0)
return 1;
else
return 0;
}
int pidof(const char *command)
{
/* inspired by killall5.c from psmisc */
char stackpath[PATH_MAX + 1], *p;
DIR *dir;
struct dirent *de;
int pid, ret = -1, self = getpid();
if (!(dir = opendir(PROC_BASE))) {
perror(PROC_BASE);
return -1;
}
/* Resolve the path if it contains symbolic links */
p = realpath(command, stackpath);
if (p)
command = p;
while ((de = readdir(dir)) != NULL) {
errno = 0;
pid = (int)strtol(de->d_name, (char **)NULL, 10);
if (errno || pid == 0 || pid == self)
continue;
if (cmp_cmdline(command, pid)) {
ret = pid;
break;
}
}
closedir(dir);
return ret;
}
void load_checks(char *pc[], int *npc, char *fc[], int *nfc)
{
FILE *fp = fopen(CONF, "r");
char buf[255], *bufp;
int buf_len, section = -1;
int proclen = strlen(PROCS);
int filelen = strlen(FILES);
if (fp == NULL) {
printf("\nUnable to open %s.\n", CONF);
return;
}
while (!feof(fp)) {
if (!fgets(buf, sizeof buf, fp))
break;
buf_len = strlen(buf);
if (buf[buf_len - 1] == '\n')
buf[buf_len - 1] = 0;
bufp = buf;
while (*bufp && isspace(*bufp)) {
bufp++;
buf_len--;
}
if (*bufp == '#')
/* skip comments */
continue;
if (*bufp) {
if (!(*bufp))
goto out;
if (strncmp(bufp, PROCS, proclen) == 0)
section = 0;
else if (strncmp(bufp, FILES, filelen) == 0)
section = 1;
else {
switch (section) {
case 0:
if (*npc >= MAX_CHECK)
break;
pc[*npc] =
(char *)malloc((buf_len) *
sizeof(char));
memcpy(pc[*npc], bufp, buf_len);
(*npc)++;
bufp = NULL;
break;
case 1:
if (*nfc >= MAX_CHECK)
break;
fc[*nfc] =
(char *)malloc((buf_len) *
sizeof(char));
memcpy(fc[*nfc], bufp, buf_len);
(*nfc)++;
bufp = NULL;
break;
default:
/* ignore lines before a section */
printf("Line not in a section: %s.\n",
buf);
break;
}
}
}
}
out:
fclose(fp);
return;
}
void printf_tab(const char *outp)
{
char buf[20];
snprintf(buf, sizeof(buf), "%%-%us", COL);
printf(buf, outp);
}
int main(int argc, char **argv)
{
/* these vars are reused several times */
int rc, opt, i, c;
char *context, *root_path;
/* files that need context checks */
char *fc[MAX_CHECK];
char *cterm = ttyname(0);
int nfc = 0;
struct stat m;
/* processes that need context checks */
char *pc[MAX_CHECK];
int npc = 0;
/* booleans */
char **bools;
int nbool;
int verbose = 0;
int show_bools = 0;
/* policy */
const char *pol_name, *root_dir;
char *pol_path;
while (1) {
opt = getopt(argc, argv, "vb");
if (opt == -1)
break;
switch (opt) {
case 'v':
verbose = 1;
break;
case 'b':
show_bools = 1;
break;
default:
/* invalid option */
printf("\nUsage: %s [OPTION]\n\n", basename(argv[0]));
printf(" -v Verbose check of process and file contexts.\n");
printf(" -b Display current state of booleans.\n");
printf("\nWithout options, show SELinux status.\n");
return -1;
}
}
printf_tab("SELinux status:");
rc = is_selinux_enabled();
switch (rc) {
case 1:
printf("enabled\n");
break;
case 0:
printf("disabled\n");
return 0;
break;
default:
printf("unknown (%s)\n", strerror(errno));
return 0;
break;
}
printf_tab("SELinuxfs mount:");
if (selinux_mnt != NULL) {
printf("%s\n", selinux_mnt);
} else {
printf("not mounted\n\n");
printf("Please mount selinuxfs for proper results.\n");
return -1;
}
printf_tab("SELinux root directory:");
root_dir = selinux_path();
if (root_dir == NULL) {
printf("error (%s)\n", strerror(errno));
return -1;
}
/* The path has a trailing '/' so duplicate to edit */
root_path = strdup(root_dir);
if (!root_path) {
printf("malloc error (%s)\n", strerror(errno));
return -1;
}
/* actually blank the '/' */
root_path[strlen(root_path) - 1] = '\0';
printf("%s\n", root_path);
free(root_path);
/* Dump all the path information */
printf_tab("Loaded policy name:");
pol_path = strdup(selinux_policy_root());
if (pol_path) {
pol_name = basename(pol_path);
puts(pol_name);
free(pol_path);
} else {
printf("error (%s)\n", strerror(errno));
}
printf_tab("Current mode:");
rc = security_getenforce();
switch (rc) {
case 1:
printf("enforcing\n");
break;
case 0:
printf("permissive\n");
break;
default:
printf("unknown (%s)\n", strerror(errno));
break;
}
printf_tab("Mode from config file:");
if (selinux_getenforcemode(&rc) == 0) {
switch (rc) {
case 1:
printf("enforcing\n");
break;
case 0:
printf("permissive\n");
break;
case -1:
printf("disabled\n");
break;
}
} else {
printf("error (%s)\n", strerror(errno));
}
printf_tab("Policy MLS status:");
rc = is_selinux_mls_enabled();
switch (rc) {
case 0:
printf("disabled\n");
break;
case 1:
printf("enabled\n");
break;
default:
printf("error (%s)\n", strerror(errno));
break;
}
printf_tab("Policy deny_unknown status:");
rc = security_deny_unknown();
switch (rc) {
case 0:
printf("allowed\n");
break;
case 1:
printf("denied\n");
break;
default:
printf("error (%s)\n", strerror(errno));
break;
}
printf_tab("Memory protection checking:");
rc = security_get_checkreqprot();
switch (rc) {
case 0:
printf("actual (secure)\n");
break;
case 1:
printf("requested (insecure)\n");
break;
default:
printf("error (%s)\n", strerror(errno));
break;
}
rc = security_policyvers();
printf_tab("Max kernel policy version:");
if (rc < 0)
printf("unknown (%s)\n", strerror(errno));
else
printf("%d\n", rc);
if (show_bools) {
/* show booleans */
if (security_get_boolean_names(&bools, &nbool) >= 0) {
printf("\nPolicy booleans:\n");
for (i = 0; i < nbool; i++) {
if (strlen(bools[i]) + 1 > COL)
COL = strlen(bools[i]) + 1;
}
for (i = 0; i < nbool; i++) {
printf_tab(bools[i]);
rc = security_get_boolean_active(bools[i]);
switch (rc) {
case 1:
printf("on");
break;
case 0:
printf("off");
break;
default:
printf("unknown (%s)", strerror(errno));
break;
}
c = security_get_boolean_pending(bools[i]);
if (c != rc)
switch (c) {
case 1:
printf(" (activate pending)");
break;
case 0:
printf(" (inactivate pending)");
break;
default:
printf(" (pending error: %s)",
strerror(errno));
break;
}
printf("\n");
/* free up the booleans */
free(bools[i]);
}
free(bools);
}
}
/* only show contexts if -v is given */
if (!verbose)
return 0;
load_checks(pc, &npc, fc, &nfc);
printf("\nProcess contexts:\n");
printf_tab("Current context:");
if (getcon(&context) >= 0) {
printf("%s\n", context);
freecon(context);
} else
printf("unknown (%s)\n", strerror(errno));
printf_tab("Init context:");
if (getpidcon(1, &context) >= 0) {
printf("%s\n", context);
freecon(context);
} else
printf("unknown (%s)\n", strerror(errno));
for (i = 0; i < npc; i++) {
rc = pidof(pc[i]);
if (rc > 0) {
if (getpidcon(rc, &context) < 0)
continue;
printf_tab(pc[i]);
printf("%s\n", context);
freecon(context);
}
free(pc[i]);
}
printf("\nFile contexts:\n");
/* controlling term */
printf_tab("Controlling terminal:");
if (lgetfilecon(cterm, &context) >= 0) {
printf("%s\n", context);
freecon(context);
} else {
printf("unknown (%s)\n", strerror(errno));
}
for (i = 0; i < nfc; i++) {
if (lgetfilecon(fc[i], &context) >= 0) {
printf_tab(fc[i]);
/* check if this is a symlink */
if (lstat(fc[i], &m)) {
printf
("%s (could not check link status (%s)!)\n",
context, strerror(errno));
freecon(context);
free(fc[i]);
continue;
}
if (S_ISLNK(m.st_mode)) {
/* print link target context */
printf("%s -> ", context);
freecon(context);
if (getfilecon(fc[i], &context) >= 0) {
printf("%s\n", context);
freecon(context);
} else {
printf("unknown (%s)\n",
strerror(errno));
}
} else {
printf("%s\n", context);
freecon(context);
}
}
free(fc[i]);
}
return 0;
}