Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/security/landlock/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  domain.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Landlock - Domain management
 *
 * Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net>
 * Copyright © 2018-2020 ANSSI
 * Copyright © 2024-2025 Microsoft Corporation
 */


#include <kunit/test.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/cred.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/path.h>
#include <linux/pid.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/uidgid.h>

#include "access.h"
#include "common.h"
#include "domain.h"
#include "id.h"

#ifdef CONFIG_AUDIT

/**
 * get_current_exe - Get the current's executable path, if any
 *
 * @exe_str: Returned pointer to a path string with a lifetime tied to the
 *           returned buffer, if any.
 * @exe_size: Returned size of @exe_str (including the trailing null
 *            character), if any.
 *
 * Returns: A pointer to an allocated buffer where @exe_str point to, %NULL if
 * there is no executable path, or an error otherwise.
 */

static const void *get_current_exe(const char **const exe_str,
       size_t *const exe_size)
{
 const size_t buffer_size = LANDLOCK_PATH_MAX_SIZE;
 struct mm_struct *mm = current->mm;
 struct file *file __free(fput) = NULL;
 char *buffer __free(kfree) = NULL;
 const char *exe;
 ssize_t size;

 if (!mm)
  return NULL;

 file = get_mm_exe_file(mm);
 if (!file)
  return NULL;

 buffer = kmalloc(buffer_size, GFP_KERNEL);
 if (!buffer)
  return ERR_PTR(-ENOMEM);

 exe = d_path(&file->f_path, buffer, buffer_size);
 if (WARN_ON_ONCE(IS_ERR(exe)))
  /* Should never happen according to LANDLOCK_PATH_MAX_SIZE. */
  return ERR_CAST(exe);

 size = buffer + buffer_size - exe;
 if (WARN_ON_ONCE(size <= 0))
  return ERR_PTR(-ENAMETOOLONG);

 *exe_size = size;
 *exe_str = exe;
 return no_free_ptr(buffer);
}

/*
 * Returns: A newly allocated object describing a domain, or an error
 * otherwise.
 */

static struct landlock_details *get_current_details(void)
{
 /* Cf. audit_log_d_path_exe() */
 static const char null_path[] = "(null)";
 const char *path_str = null_path;
 size_t path_size = sizeof(null_path);
 const void *buffer __free(kfree) = NULL;
 struct landlock_details *details;

 buffer = get_current_exe(&path_str, &path_size);
 if (IS_ERR(buffer))
  return ERR_CAST(buffer);

 /*
 * Create the new details according to the path's length.  Do not
 * allocate with GFP_KERNEL_ACCOUNT because it is independent from the
 * caller.
 */

 details =
  kzalloc(struct_size(details, exe_path, path_size), GFP_KERNEL);
 if (!details)
  return ERR_PTR(-ENOMEM);

 memcpy(details->exe_path, path_str, path_size);
 details->pid = get_pid(task_tgid(current));
 details->uid = from_kuid(&init_user_ns, current_uid());
 get_task_comm(details->comm, current);
 return details;
}

/**
 * landlock_init_hierarchy_log - Partially initialize landlock_hierarchy
 *
 * @hierarchy: The hierarchy to initialize.
 *
 * The current task is referenced as the domain that is enforcing the
 * restriction.  The subjective credentials must not be in an overridden state.
 *
 * @hierarchy->parent and @hierarchy->usage should already be set.
 */

int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy)
{
 struct landlock_details *details;

 details = get_current_details();
 if (IS_ERR(details))
  return PTR_ERR(details);

 hierarchy->details = details;
 hierarchy->id = landlock_get_id_range(1);
 hierarchy->log_status = LANDLOCK_LOG_PENDING;
 hierarchy->log_same_exec = true;
 hierarchy->log_new_exec = false;
 atomic64_set(&hierarchy->num_denials, 0);
 return 0;
}

static deny_masks_t
get_layer_deny_mask(const access_mask_t all_existing_optional_access,
      const unsigned long access_bit, const size_t layer)
{
 unsigned long access_weight;

 /* This may require change with new object types. */
 WARN_ON_ONCE(all_existing_optional_access !=
       _LANDLOCK_ACCESS_FS_OPTIONAL);

 if (WARN_ON_ONCE(layer >= LANDLOCK_MAX_NUM_LAYERS))
  return 0;

 access_weight = hweight_long(all_existing_optional_access &
         GENMASK(access_bit, 0));
 if (WARN_ON_ONCE(access_weight < 1))
  return 0;

 return layer
        << ((access_weight - 1) * HWEIGHT(LANDLOCK_MAX_NUM_LAYERS - 1));
}

#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST

static void test_get_layer_deny_mask(struct kunit *const test)
{
 const unsigned long truncate = BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE);
 const unsigned long ioctl_dev = BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV);

 KUNIT_EXPECT_EQ(test, 0,
   get_layer_deny_mask(_LANDLOCK_ACCESS_FS_OPTIONAL,
         truncate, 0));
 KUNIT_EXPECT_EQ(test, 0x3,
   get_layer_deny_mask(_LANDLOCK_ACCESS_FS_OPTIONAL,
         truncate, 3));

 KUNIT_EXPECT_EQ(test, 0,
   get_layer_deny_mask(_LANDLOCK_ACCESS_FS_OPTIONAL,
         ioctl_dev, 0));
 KUNIT_EXPECT_EQ(test, 0xf0,
   get_layer_deny_mask(_LANDLOCK_ACCESS_FS_OPTIONAL,
         ioctl_dev, 15));
}

#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */

deny_masks_t
landlock_get_deny_masks(const access_mask_t all_existing_optional_access,
   const access_mask_t optional_access,
   const layer_mask_t (*const layer_masks)[],
   const size_t layer_masks_size)
{
 const unsigned long access_opt = optional_access;
 unsigned long access_bit;
 deny_masks_t deny_masks = 0;

 /* This may require change with new object types. */
 WARN_ON_ONCE(access_opt !=
       (optional_access & all_existing_optional_access));

 if (WARN_ON_ONCE(!layer_masks))
  return 0;

 if (WARN_ON_ONCE(!access_opt))
  return 0;

 for_each_set_bit(access_bit, &access_opt, layer_masks_size) {
  const layer_mask_t mask = (*layer_masks)[access_bit];

  if (!mask)
   continue;

  /* __fls(1) == 0 */
  deny_masks |= get_layer_deny_mask(all_existing_optional_access,
        access_bit, __fls(mask));
 }
 return deny_masks;
}

#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST

static void test_landlock_get_deny_masks(struct kunit *const test)
{
 const layer_mask_t layers1[BITS_PER_TYPE(access_mask_t)] = {
  [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0) |
         BIT_ULL(9),
  [BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = BIT_ULL(1),
  [BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = BIT_ULL(2) |
           BIT_ULL(0),
 };

 KUNIT_EXPECT_EQ(test, 0x1,
   landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL,
      LANDLOCK_ACCESS_FS_TRUNCATE,
      &layers1, ARRAY_SIZE(layers1)));
 KUNIT_EXPECT_EQ(test, 0x20,
   landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL,
      LANDLOCK_ACCESS_FS_IOCTL_DEV,
      &layers1, ARRAY_SIZE(layers1)));
 KUNIT_EXPECT_EQ(
  test, 0x21,
  landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL,
     LANDLOCK_ACCESS_FS_TRUNCATE |
      LANDLOCK_ACCESS_FS_IOCTL_DEV,
     &layers1, ARRAY_SIZE(layers1)));
}

#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */

#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST

static struct kunit_case test_cases[] = {
 /* clang-format off */
 KUNIT_CASE(test_get_layer_deny_mask),
 KUNIT_CASE(test_landlock_get_deny_masks),
 {}
 /* clang-format on */
};

static struct kunit_suite test_suite = {
 .name = "landlock_domain",
 .test_cases = test_cases,
};

kunit_test_suite(test_suite);

#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */

#endif /* CONFIG_AUDIT */

Messung V0.5
C=97 H=97 G=96

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.