lockdown.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Lock down the kernel
  3. *
  4. * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
  5. * Written by David Howells ([email protected])
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public Licence
  9. * as published by the Free Software Foundation; either version
  10. * 2 of the Licence, or (at your option) any later version.
  11. */
  12. #include <linux/security.h>
  13. #include <linux/export.h>
  14. #include <linux/lsm_hooks.h>
  15. static enum lockdown_reason kernel_locked_down;
  16. static const enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE,
  17. LOCKDOWN_INTEGRITY_MAX,
  18. LOCKDOWN_CONFIDENTIALITY_MAX};
  19. /*
  20. * Put the kernel into lock-down mode.
  21. */
  22. static int lock_kernel_down(const char *where, enum lockdown_reason level)
  23. {
  24. if (kernel_locked_down >= level)
  25. return -EPERM;
  26. kernel_locked_down = level;
  27. pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n",
  28. where);
  29. return 0;
  30. }
  31. static int __init lockdown_param(char *level)
  32. {
  33. if (!level)
  34. return -EINVAL;
  35. if (strcmp(level, "integrity") == 0)
  36. lock_kernel_down("command line", LOCKDOWN_INTEGRITY_MAX);
  37. else if (strcmp(level, "confidentiality") == 0)
  38. lock_kernel_down("command line", LOCKDOWN_CONFIDENTIALITY_MAX);
  39. else
  40. return -EINVAL;
  41. return 0;
  42. }
  43. early_param("lockdown", lockdown_param);
  44. /**
  45. * lockdown_is_locked_down - Find out if the kernel is locked down
  46. * @what: Tag to use in notice generated if lockdown is in effect
  47. */
  48. static int lockdown_is_locked_down(enum lockdown_reason what)
  49. {
  50. if (WARN(what >= LOCKDOWN_CONFIDENTIALITY_MAX,
  51. "Invalid lockdown reason"))
  52. return -EPERM;
  53. if (kernel_locked_down >= what) {
  54. if (lockdown_reasons[what])
  55. pr_notice_ratelimited("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
  56. current->comm, lockdown_reasons[what]);
  57. return -EPERM;
  58. }
  59. return 0;
  60. }
  61. static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = {
  62. LSM_HOOK_INIT(locked_down, lockdown_is_locked_down),
  63. };
  64. static int __init lockdown_lsm_init(void)
  65. {
  66. #if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY)
  67. lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY_MAX);
  68. #elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY)
  69. lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX);
  70. #endif
  71. security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks),
  72. "lockdown");
  73. return 0;
  74. }
  75. static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count,
  76. loff_t *ppos)
  77. {
  78. char temp[80];
  79. int i, offset = 0;
  80. for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
  81. enum lockdown_reason level = lockdown_levels[i];
  82. if (lockdown_reasons[level]) {
  83. const char *label = lockdown_reasons[level];
  84. if (kernel_locked_down == level)
  85. offset += sprintf(temp+offset, "[%s] ", label);
  86. else
  87. offset += sprintf(temp+offset, "%s ", label);
  88. }
  89. }
  90. /* Convert the last space to a newline if needed. */
  91. if (offset > 0)
  92. temp[offset-1] = '\n';
  93. return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
  94. }
  95. static ssize_t lockdown_write(struct file *file, const char __user *buf,
  96. size_t n, loff_t *ppos)
  97. {
  98. char *state;
  99. int i, len, err = -EINVAL;
  100. state = memdup_user_nul(buf, n);
  101. if (IS_ERR(state))
  102. return PTR_ERR(state);
  103. len = strlen(state);
  104. if (len && state[len-1] == '\n') {
  105. state[len-1] = '\0';
  106. len--;
  107. }
  108. for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
  109. enum lockdown_reason level = lockdown_levels[i];
  110. const char *label = lockdown_reasons[level];
  111. if (label && !strcmp(state, label))
  112. err = lock_kernel_down("securityfs", level);
  113. }
  114. kfree(state);
  115. return err ? err : n;
  116. }
  117. static const struct file_operations lockdown_ops = {
  118. .read = lockdown_read,
  119. .write = lockdown_write,
  120. };
  121. static int __init lockdown_secfs_init(void)
  122. {
  123. struct dentry *dentry;
  124. dentry = securityfs_create_file("lockdown", 0644, NULL, NULL,
  125. &lockdown_ops);
  126. return PTR_ERR_OR_ZERO(dentry);
  127. }
  128. core_initcall(lockdown_secfs_init);
  129. #ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
  130. DEFINE_EARLY_LSM(lockdown) = {
  131. #else
  132. DEFINE_LSM(lockdown) = {
  133. #endif
  134. .name = "lockdown",
  135. .init = lockdown_lsm_init,
  136. };