(root)/
strace-6.5/
tests-m32/
secontext.c
       1  /*
       2   * Copyright (c) 2020-2022 The strace developers.
       3   * All rights reserved.
       4   *
       5   * SPDX-License-Identifier: GPL-2.0-or-later
       6   */
       7  
       8  #include "tests.h"
       9  
      10  #ifdef HAVE_SELINUX_RUNTIME
      11  
      12  # include <assert.h>
      13  # include <errno.h>
      14  # include <stdlib.h>
      15  # include <string.h>
      16  # include <sys/stat.h>
      17  # include <unistd.h>
      18  # include <selinux/selinux.h>
      19  # include <selinux/label.h>
      20  
      21  # include "xmalloc.h"
      22  
      23  # define TEST_SECONTEXT
      24  # include "secontext.h"
      25  
      26  ATTRIBUTE_FORMAT((printf, 2, 0)) ATTRIBUTE_MALLOC
      27  static char *
      28  secontext_format(char *context, const char *fmt)
      29  {
      30  	int saved_errno = errno;
      31  	char *res = context ? xasprintf(fmt, context) : xstrdup("");
      32  	free(context);
      33  	errno = saved_errno;
      34  	return res;
      35  }
      36  
      37  # define FORMAT_SPACE_BEFORE(string)	secontext_format(string, " [%s]")
      38  # define FORMAT_SPACE_AFTER(string)	secontext_format(string, "[%s] ")
      39  
      40  static char *
      41  strip_trailing_newlines(char *context)
      42  {
      43  	/*
      44  	 * On the CI at least, the context may have a trailing \n,
      45  	 * let's remove it just in case.
      46  	 */
      47  	size_t len = strlen(context);
      48  	for (; len > 0; --len) {
      49  		if (context[len - 1] != '\n')
      50  			break;
      51  	}
      52  	context[len] = '\0';
      53  	return context;
      54  }
      55  
      56  char *
      57  get_secontext_field(const char *full_context, enum secontext_field field)
      58  {
      59  	int saved_errno = errno;
      60  
      61  	if (!full_context)
      62  		return NULL;
      63  
      64  	char *saveptr = NULL;
      65  	const char *token;
      66  	unsigned int i;
      67  
      68  	char *ctx_copy = xstrdup(full_context);
      69  	char *context = NULL;
      70  	for (token = strtok_r(ctx_copy, ":", &saveptr), i = 0;
      71  	     token; token = strtok_r(NULL, ":", &saveptr), i++) {
      72  		if (i == field) {
      73  			context = xstrdup(token);
      74  			break;
      75  		}
      76  	}
      77  	if (!context)
      78  		context = xstrdup(full_context);
      79  	free(ctx_copy);
      80  
      81  	errno = saved_errno;
      82  	return context;
      83  }
      84  
      85  static char *
      86  raw_expected_secontext_full_file(const char *filename)
      87  {
      88  	int saved_errno = errno;
      89  	char *secontext;
      90  
      91  	static struct selabel_handle *hdl;
      92  	if (!hdl) {
      93  		hdl = selabel_open(SELABEL_CTX_FILE, NULL, 0);
      94  		if (!hdl)
      95  			perror_msg_and_skip("selabel_open");
      96  	}
      97  
      98  	char *resolved = realpath(filename, NULL);
      99  	if (!resolved)
     100  		perror_msg_and_fail("realpath: %s", filename);
     101  
     102  	struct stat statbuf;
     103  	if (stat(resolved, &statbuf) < 0)
     104  		perror_msg_and_fail("stat: %s", resolved);
     105  
     106  	if (selabel_lookup(hdl, &secontext, resolved, statbuf.st_mode) < 0)
     107  		perror_msg_and_skip("selabel_lookup: %s", resolved);
     108  	free(resolved);
     109  
     110  	char *full_secontext = xstrdup(secontext);
     111  	freecon(secontext);
     112  	errno = saved_errno;
     113  	return full_secontext;
     114  }
     115  
     116  static char *
     117  raw_expected_secontext_short_file(const char *filename)
     118  {
     119  	int saved_errno = errno;
     120  
     121  	char *ctx = raw_expected_secontext_full_file(filename);
     122  	char *type = get_secontext_field(ctx, SECONTEXT_TYPE);
     123  	free(ctx);
     124  
     125  	errno = saved_errno;
     126  	return type;
     127  }
     128  
     129  static char *
     130  raw_secontext_full_file(const char *filename)
     131  {
     132  	int saved_errno = errno;
     133  	char *full_secontext = NULL;
     134  	char *secontext;
     135  
     136  	if (getfilecon(filename, &secontext) >= 0) {
     137  		full_secontext = strip_trailing_newlines(xstrdup(secontext));
     138  		freecon(secontext);
     139  	}
     140  	errno = saved_errno;
     141  	return full_secontext;
     142  }
     143  
     144  static char *
     145  raw_secontext_full_fd(int fd)
     146  {
     147  	int saved_errno = errno;
     148  	char *full_secontext = NULL;
     149  	char *secontext;
     150  
     151  	if (fgetfilecon(fd, &secontext) >= 0) {
     152  		full_secontext = strip_trailing_newlines(xstrdup(secontext));
     153  		freecon(secontext);
     154  	}
     155  	errno = saved_errno;
     156  	return full_secontext;
     157  }
     158  
     159  char *
     160  get_secontext_field_file(const char *file, enum secontext_field field)
     161  {
     162  	char *ctx = raw_secontext_full_file(file);
     163  	char *type =  get_secontext_field(ctx, field);
     164  	free(ctx);
     165  
     166  	return type;
     167  }
     168  
     169  char *
     170  get_secontext_field_fd(int fd, enum secontext_field field)
     171  {
     172  	char *ctx = raw_secontext_full_fd(fd);
     173  	char *type =  get_secontext_field(ctx, field);
     174  	free(ctx);
     175  
     176  	return type;
     177  }
     178  
     179  static char *
     180  raw_secontext_short_file(const char *filename)
     181  {
     182  	return get_secontext_field_file(filename, SECONTEXT_TYPE);
     183  }
     184  
     185  static char *
     186  raw_secontext_short_fd(int fd)
     187  {
     188  	return get_secontext_field_fd(fd, SECONTEXT_TYPE);
     189  }
     190  
     191  static char *
     192  raw_secontext_full_pid(pid_t pid)
     193  {
     194  	int saved_errno = errno;
     195  	char *full_secontext = NULL;
     196  	char *secontext;
     197  
     198  	if (getpidcon(pid, &secontext) == 0) {
     199  		full_secontext = strip_trailing_newlines(xstrdup(secontext));
     200  		freecon(secontext);
     201  	}
     202  	errno = saved_errno;
     203  	return full_secontext;
     204  }
     205  
     206  static char *
     207  raw_secontext_short_pid(pid_t pid)
     208  {
     209  	int saved_errno = errno;
     210  
     211  	char *ctx = raw_secontext_full_pid(pid);
     212  	char *type = get_secontext_field(ctx, SECONTEXT_TYPE);
     213  	free(ctx);
     214  
     215  	errno = saved_errno;
     216  	return type;
     217  }
     218  
     219  char *
     220  secontext_full_file(const char *filename, bool mismatch)
     221  {
     222  	int saved_errno = errno;
     223  	char *context = raw_secontext_full_file(filename);
     224  	if (context && mismatch) {
     225  		char *expected = raw_expected_secontext_full_file(filename);
     226  		if (expected && strcmp(context, expected)) {
     227  			char *context_mismatch =
     228  				xasprintf("%s!!%s", context, expected);
     229  			free(context);
     230  			context = context_mismatch;
     231  		}
     232  		free(expected);
     233  	}
     234  	errno = saved_errno;
     235  	return FORMAT_SPACE_BEFORE(context);
     236  }
     237  
     238  char *
     239  secontext_full_fd(int fd)
     240  {
     241  	int saved_errno = errno;
     242  	char *context = raw_secontext_full_fd(fd);
     243  	errno = saved_errno;
     244  	return FORMAT_SPACE_BEFORE(context);
     245  }
     246  
     247  char *
     248  secontext_full_pid(pid_t pid)
     249  {
     250  	return FORMAT_SPACE_AFTER(raw_secontext_full_pid(pid));
     251  }
     252  
     253  char *
     254  secontext_short_file(const char *filename, bool mismatch)
     255  {
     256  	int saved_errno = errno;
     257  	char *context = raw_secontext_short_file(filename);
     258  	if (context && mismatch) {
     259  		char *expected = raw_expected_secontext_short_file(filename);
     260  		if (expected && strcmp(context, expected)) {
     261  			char *context_mismatch =
     262  				xasprintf("%s!!%s", context, expected);
     263  			free(context);
     264  			context = context_mismatch;
     265  		}
     266  		free(expected);
     267  	}
     268  	errno = saved_errno;
     269  	return FORMAT_SPACE_BEFORE(context);
     270  }
     271  
     272  char *
     273  secontext_short_fd(int fd)
     274  {
     275  	int saved_errno = errno;
     276  	char *context = raw_secontext_short_fd(fd);
     277  	errno = saved_errno;
     278  	return FORMAT_SPACE_BEFORE(context);
     279  }
     280  
     281  char *
     282  secontext_short_pid(pid_t pid)
     283  {
     284  	return FORMAT_SPACE_AFTER(raw_secontext_short_pid(pid));
     285  }
     286  
     287  void reset_secontext_file(const char *file)
     288  {
     289  	char *proper_ctx = raw_expected_secontext_full_file(file);
     290  	(void) setfilecon(file, proper_ctx);
     291  	free(proper_ctx);
     292  }
     293  
     294  void
     295  update_secontext_field(const char *file, enum secontext_field field,
     296  		       const char *newvalue)
     297  {
     298  	int saved_errno = errno;
     299  	assert(field >= SECONTEXT_USER && field <= SECONTEXT_TYPE);
     300  
     301  	char *ctx = raw_secontext_full_file(file);
     302  	if (ctx == NULL)
     303  		return;
     304  
     305  	char *saveptr = NULL;
     306  	char *token;
     307  	int nfields;
     308  	char *split[4];
     309  
     310  	for (token = strtok_r(ctx, ":", &saveptr), nfields = 0;
     311  	     token; token = strtok_r(NULL, ":", &saveptr), nfields++) {
     312  		assert(nfields < 4);
     313  		split[nfields] = token;
     314  	}
     315  	assert(nfields == 4);
     316  
     317  	split[field] = (char *)newvalue;
     318  
     319  	char *newcontext = xasprintf("%s:%s:%s:%s", split[0], split[1],
     320  				     split[2], split[3]);
     321  
     322  	(void) setfilecon(file, newcontext);
     323  
     324  	free(newcontext);
     325  	free(ctx);
     326  	errno = saved_errno;
     327  }
     328  
     329  #endif /* HAVE_SELINUX_RUNTIME */