Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  policy_fs.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
 */

#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/types.h>
#include <linux/dcache.h>
#include <linux/security.h>

#include "ipe.h"
#include "policy.h"
#include "eval.h"
#include "fs.h"
#include "audit.h"

#define MAX_VERSION_SIZE ARRAY_SIZE("65535.65535.65535")

/**
 * struct ipefs_file - defines a file in securityfs.
 *
 * @name: file name inside the policy subdirectory
 * @access: file permissions
 * @fops: &file_operations specific to this file
 */

struct ipefs_file {
 const char *name;
 umode_t access;
 const struct file_operations *fops;
};

/**
 * read_pkcs7() - Read handler for "ipe/policies/$name/pkcs7".
 * @f: Supplies a file structure representing the securityfs node.
 * @data: Supplies a buffer passed to the write syscall.
 * @len: Supplies the length of @data.
 * @offset: unused.
 *
 * @data will be populated with the pkcs7 blob representing the policy
 * on success. If the policy is unsigned (like the boot policy), this
 * will return -ENOENT.
 *
 * Return:
 * * Length of buffer written - Success
 * * %-ENOENT - Policy initializing/deleted or is unsigned
 */

static ssize_t read_pkcs7(struct file *f, char __user *data,
     size_t len, loff_t *offset)
{
 const struct ipe_policy *p = NULL;
 struct inode *root = NULL;
 int rc = 0;

 root = d_inode(f->f_path.dentry->d_parent);

 inode_lock_shared(root);
 p = (struct ipe_policy *)root->i_private;
 if (!p) {
  rc = -ENOENT;
  goto out;
 }

 if (!p->pkcs7) {
  rc = -ENOENT;
  goto out;
 }

 rc = simple_read_from_buffer(data, len, offset, p->pkcs7, p->pkcs7len);

out:
 inode_unlock_shared(root);

 return rc;
}

/**
 * read_policy() - Read handler for "ipe/policies/$name/policy".
 * @f: Supplies a file structure representing the securityfs node.
 * @data: Supplies a buffer passed to the write syscall.
 * @len: Supplies the length of @data.
 * @offset: unused.
 *
 * @data will be populated with the plain-text version of the policy
 * on success.
 *
 * Return:
 * * Length of buffer written - Success
 * * %-ENOENT - Policy initializing/deleted
 */

static ssize_t read_policy(struct file *f, char __user *data,
      size_t len, loff_t *offset)
{
 const struct ipe_policy *p = NULL;
 struct inode *root = NULL;
 int rc = 0;

 root = d_inode(f->f_path.dentry->d_parent);

 inode_lock_shared(root);
 p = (struct ipe_policy *)root->i_private;
 if (!p) {
  rc = -ENOENT;
  goto out;
 }

 rc = simple_read_from_buffer(data, len, offset, p->text, p->textlen);

out:
 inode_unlock_shared(root);

 return rc;
}

/**
 * read_name() - Read handler for "ipe/policies/$name/name".
 * @f: Supplies a file structure representing the securityfs node.
 * @data: Supplies a buffer passed to the write syscall.
 * @len: Supplies the length of @data.
 * @offset: unused.
 *
 * @data will be populated with the policy_name attribute on success.
 *
 * Return:
 * * Length of buffer written - Success
 * * %-ENOENT - Policy initializing/deleted
 */

static ssize_t read_name(struct file *f, char __user *data,
    size_t len, loff_t *offset)
{
 const struct ipe_policy *p = NULL;
 struct inode *root = NULL;
 int rc = 0;

 root = d_inode(f->f_path.dentry->d_parent);

 inode_lock_shared(root);
 p = (struct ipe_policy *)root->i_private;
 if (!p) {
  rc = -ENOENT;
  goto out;
 }

 rc = simple_read_from_buffer(data, len, offset, p->parsed->name,
         strlen(p->parsed->name));

out:
 inode_unlock_shared(root);

 return rc;
}

/**
 * read_version() - Read handler for "ipe/policies/$name/version".
 * @f: Supplies a file structure representing the securityfs node.
 * @data: Supplies a buffer passed to the write syscall.
 * @len: Supplies the length of @data.
 * @offset: unused.
 *
 * @data will be populated with the version string on success.
 *
 * Return:
 * * Length of buffer written - Success
 * * %-ENOENT - Policy initializing/deleted
 */

static ssize_t read_version(struct file *f, char __user *data,
       size_t len, loff_t *offset)
{
 char buffer[MAX_VERSION_SIZE] = { 0 };
 const struct ipe_policy *p = NULL;
 struct inode *root = NULL;
 size_t strsize = 0;
 ssize_t rc = 0;

 root = d_inode(f->f_path.dentry->d_parent);

 inode_lock_shared(root);
 p = (struct ipe_policy *)root->i_private;
 if (!p) {
  rc = -ENOENT;
  goto out;
 }

 strsize = scnprintf(buffer, ARRAY_SIZE(buffer), "%hu.%hu.%hu",
       p->parsed->version.major, p->parsed->version.minor,
       p->parsed->version.rev);

 rc = simple_read_from_buffer(data, len, offset, buffer, strsize);

out:
 inode_unlock_shared(root);

 return rc;
}

/**
 * setactive() - Write handler for "ipe/policies/$name/active".
 * @f: Supplies a file structure representing the securityfs node.
 * @data: Supplies a buffer passed to the write syscall.
 * @len: Supplies the length of @data.
 * @offset: unused.
 *
 * Return:
 * * Length of buffer written - Success
 * * %-EPERM - Insufficient permission
 * * %-EINVAL - Invalid input
 * * %-ENOENT - Policy initializing/deleted
 */

static ssize_t setactive(struct file *f, const char __user *data,
    size_t len, loff_t *offset)
{
 const struct ipe_policy *p = NULL;
 struct inode *root = NULL;
 bool value = false;
 int rc = 0;

 if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
  return -EPERM;

 rc = kstrtobool_from_user(data, len, &value);
 if (rc)
  return rc;

 if (!value)
  return -EINVAL;

 root = d_inode(f->f_path.dentry->d_parent);
 inode_lock(root);

 p = (struct ipe_policy *)root->i_private;
 if (!p) {
  rc = -ENOENT;
  goto out;
 }

 rc = ipe_set_active_pol(p);

out:
 inode_unlock(root);
 return (rc < 0) ? rc : len;
}

/**
 * getactive() - Read handler for "ipe/policies/$name/active".
 * @f: Supplies a file structure representing the securityfs node.
 * @data: Supplies a buffer passed to the write syscall.
 * @len: Supplies the length of @data.
 * @offset: unused.
 *
 * @data will be populated with the 1 or 0 depending on if the
 * corresponding policy is active.
 *
 * Return:
 * * Length of buffer written - Success
 * * %-ENOENT - Policy initializing/deleted
 */

static ssize_t getactive(struct file *f, char __user *data,
    size_t len, loff_t *offset)
{
 const struct ipe_policy *p = NULL;
 struct inode *root = NULL;
 const char *str;
 int rc = 0;

 root = d_inode(f->f_path.dentry->d_parent);

 inode_lock_shared(root);
 p = (struct ipe_policy *)root->i_private;
 if (!p) {
  inode_unlock_shared(root);
  return -ENOENT;
 }
 inode_unlock_shared(root);

 str = (p == rcu_access_pointer(ipe_active_policy)) ? "1" : "0";
 rc = simple_read_from_buffer(data, len, offset, str, 1);

 return rc;
}

/**
 * update_policy() - Write handler for "ipe/policies/$name/update".
 * @f: Supplies a file structure representing the securityfs node.
 * @data: Supplies a buffer passed to the write syscall.
 * @len: Supplies the length of @data.
 * @offset: unused.
 *
 * On success this updates the policy represented by $name,
 * in-place.
 *
 * Return:
 * * Length of buffer written - Success
 * * %-EPERM - Insufficient permission
 * * %-ENOMEM - Out of memory (OOM)
 * * %-ENOENT - Policy was deleted while updating
 * * %-EINVAL - Policy name mismatch
 * * %-ESTALE - Policy version too old
 */

static ssize_t update_policy(struct file *f, const char __user *data,
        size_t len, loff_t *offset)
{
 struct inode *root = NULL;
 char *copy = NULL;
 int rc = 0;

 if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) {
  rc = -EPERM;
  goto out;
 }

 copy = memdup_user(data, len);
 if (IS_ERR(copy)) {
  rc = PTR_ERR(copy);
  copy = NULL;
  goto out;
 }

 root = d_inode(f->f_path.dentry->d_parent);
 inode_lock(root);
 rc = ipe_update_policy(root, NULL, 0, copy, len);
 inode_unlock(root);

out:
 kfree(copy);
 if (rc) {
  ipe_audit_policy_load(ERR_PTR(rc));
  return rc;
 }

 return len;
}

/**
 * delete_policy() - write handler for  "ipe/policies/$name/delete".
 * @f: Supplies a file structure representing the securityfs node.
 * @data: Supplies a buffer passed to the write syscall.
 * @len: Supplies the length of @data.
 * @offset: unused.
 *
 * On success this deletes the policy represented by $name.
 *
 * Return:
 * * Length of buffer written - Success
 * * %-EPERM - Insufficient permission/deleting active policy
 * * %-EINVAL - Invalid input
 * * %-ENOENT - Policy initializing/deleted
 */

static ssize_t delete_policy(struct file *f, const char __user *data,
        size_t len, loff_t *offset)
{
 struct ipe_policy *ap = NULL;
 struct ipe_policy *p = NULL;
 struct inode *root = NULL;
 bool value = false;
 int rc = 0;

 if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
  return -EPERM;

 rc = kstrtobool_from_user(data, len, &value);
 if (rc)
  return rc;

 if (!value)
  return -EINVAL;

 root = d_inode(f->f_path.dentry->d_parent);
 inode_lock(root);
 p = (struct ipe_policy *)root->i_private;
 if (!p) {
  inode_unlock(root);
  return -ENOENT;
 }

 mutex_lock(&ipe_policy_lock);
 ap = rcu_dereference_protected(ipe_active_policy,
           lockdep_is_held(&ipe_policy_lock));
 if (p == ap) {
  mutex_unlock(&ipe_policy_lock);
  inode_unlock(root);
  return -EPERM;
 }
 mutex_unlock(&ipe_policy_lock);

 root->i_private = NULL;
 inode_unlock(root);

 synchronize_rcu();
 ipe_free_policy(p);

 return len;
}

static const struct file_operations content_fops = {
 .read = read_policy,
};

static const struct file_operations pkcs7_fops = {
 .read = read_pkcs7,
};

static const struct file_operations name_fops = {
 .read = read_name,
};

static const struct file_operations ver_fops = {
 .read = read_version,
};

static const struct file_operations active_fops = {
 .write = setactive,
 .read = getactive,
};

static const struct file_operations update_fops = {
 .write = update_policy,
};

static const struct file_operations delete_fops = {
 .write = delete_policy,
};

/*
 * policy_subdir - files under a policy subdirectory
 */

static const struct ipefs_file policy_subdir[] = {
 { "pkcs7", 0444, &pkcs7_fops },
 { "policy", 0444, &content_fops },
 { "name", 0444, &name_fops },
 { "version", 0444, &ver_fops },
 { "active", 0600, &active_fops },
 { "update", 0200, &update_fops },
 { "delete", 0200, &delete_fops },
};

/**
 * ipe_del_policyfs_node() - Delete a securityfs entry for @p.
 * @p: Supplies a pointer to the policy to delete a securityfs entry for.
 */

void ipe_del_policyfs_node(struct ipe_policy *p)
{
 securityfs_remove(p->policyfs);
 p->policyfs = NULL;
}

/**
 * ipe_new_policyfs_node() - Create a securityfs entry for @p.
 * @p: Supplies a pointer to the policy to create a securityfs entry for.
 *
 * Return: %0 on success. If an error occurs, the function will return
 * the -errno.
 */

int ipe_new_policyfs_node(struct ipe_policy *p)
{
 const struct ipefs_file *f = NULL;
 struct dentry *policyfs = NULL;
 struct inode *root = NULL;
 struct dentry *d = NULL;
 size_t i = 0;
 int rc = 0;

 if (p->policyfs)
  return 0;

 policyfs = securityfs_create_dir(p->parsed->name, policy_root);
 if (IS_ERR(policyfs))
  return PTR_ERR(policyfs);

 root = d_inode(policyfs);

 for (i = 0; i < ARRAY_SIZE(policy_subdir); ++i) {
  f = &policy_subdir[i];

  d = securityfs_create_file(f->name, f->access, policyfs,
        NULL, f->fops);
  if (IS_ERR(d)) {
   rc = PTR_ERR(d);
   goto err;
  }
 }

 inode_lock(root);
 p->policyfs = policyfs;
 root->i_private = p;
 inode_unlock(root);

 return 0;
err:
 securityfs_remove(policyfs);
 return rc;
}

Messung V0.5
C=89 H=95 G=91

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge