lockdown.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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 (dhowells@redhat.com)
  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. #include <uapi/linux/lsm.h>
  16. static enum lockdown_reason kernel_locked_down;
  17. static const enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE,
  18. LOCKDOWN_INTEGRITY_MAX,
  19. LOCKDOWN_CONFIDENTIALITY_MAX};
  20. /*
  21. * Put the kernel into lock-down mode.
  22. */
  23. static int lock_kernel_down(const char *where, enum lockdown_reason level)
  24. {
  25. if (kernel_locked_down >= level)
  26. return -EPERM;
  27. kernel_locked_down = level;
  28. pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n",
  29. where);
  30. return 0;
  31. }
  32. static int __init lockdown_param(char *level)
  33. {
  34. if (!level)
  35. return -EINVAL;
  36. if (strcmp(level, "integrity") == 0)
  37. lock_kernel_down("command line", LOCKDOWN_INTEGRITY_MAX);
  38. else if (strcmp(level, "confidentiality") == 0)
  39. lock_kernel_down("command line", LOCKDOWN_CONFIDENTIALITY_MAX);
  40. else
  41. return -EINVAL;
  42. return 0;
  43. }
  44. early_param("lockdown", lockdown_param);
  45. /**
  46. * lockdown_is_locked_down - Find out if the kernel is locked down
  47. * @what: Tag to use in notice generated if lockdown is in effect
  48. */
  49. static int lockdown_is_locked_down(enum lockdown_reason what)
  50. {
  51. if (WARN(what >= LOCKDOWN_CONFIDENTIALITY_MAX,
  52. "Invalid lockdown reason"))
  53. return -EPERM;
  54. if (kernel_locked_down >= what) {
  55. if (lockdown_reasons[what])
  56. pr_notice_ratelimited("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
  57. current->comm, lockdown_reasons[what]);
  58. return -EPERM;
  59. }
  60. return 0;
  61. }
  62. static struct security_hook_list lockdown_hooks[] __ro_after_init = {
  63. LSM_HOOK_INIT(locked_down, lockdown_is_locked_down),
  64. };
  65. static const struct lsm_id lockdown_lsmid = {
  66. .name = "lockdown",
  67. .id = LSM_ID_LOCKDOWN,
  68. };
  69. static int __init lockdown_lsm_init(void)
  70. {
  71. #if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY)
  72. lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY_MAX);
  73. #elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY)
  74. lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX);
  75. #endif
  76. security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks),
  77. &lockdown_lsmid);
  78. return 0;
  79. }
  80. static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count,
  81. loff_t *ppos)
  82. {
  83. char temp[80] = "";
  84. int i, offset = 0;
  85. for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
  86. enum lockdown_reason level = lockdown_levels[i];
  87. if (lockdown_reasons[level]) {
  88. const char *label = lockdown_reasons[level];
  89. if (kernel_locked_down == level)
  90. offset += sprintf(temp+offset, "[%s] ", label);
  91. else
  92. offset += sprintf(temp+offset, "%s ", label);
  93. }
  94. }
  95. /* Convert the last space to a newline if needed. */
  96. if (offset > 0)
  97. temp[offset-1] = '\n';
  98. return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
  99. }
  100. static ssize_t lockdown_write(struct file *file, const char __user *buf,
  101. size_t n, loff_t *ppos)
  102. {
  103. char *state;
  104. int i, len, err = -EINVAL;
  105. state = memdup_user_nul(buf, n);
  106. if (IS_ERR(state))
  107. return PTR_ERR(state);
  108. len = strlen(state);
  109. if (len && state[len-1] == '\n') {
  110. state[len-1] = '\0';
  111. len--;
  112. }
  113. for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
  114. enum lockdown_reason level = lockdown_levels[i];
  115. const char *label = lockdown_reasons[level];
  116. if (label && !strcmp(state, label))
  117. err = lock_kernel_down("securityfs", level);
  118. }
  119. kfree(state);
  120. return err ? err : n;
  121. }
  122. static const struct file_operations lockdown_ops = {
  123. .read = lockdown_read,
  124. .write = lockdown_write,
  125. };
  126. static int __init lockdown_secfs_init(void)
  127. {
  128. struct dentry *dentry;
  129. dentry = securityfs_create_file("lockdown", 0644, NULL, NULL,
  130. &lockdown_ops);
  131. return PTR_ERR_OR_ZERO(dentry);
  132. }
  133. #ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
  134. DEFINE_EARLY_LSM(lockdown) = {
  135. #else
  136. DEFINE_LSM(lockdown) = {
  137. #endif
  138. .id = &lockdown_lsmid,
  139. .init = lockdown_lsm_init,
  140. .initcall_core = lockdown_secfs_init,
  141. };