Advertisement
Guest User

Untitled

a guest
Jun 26th, 2017
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.62 KB | None | 0 0
  1. /*
  2. * hashcheck_lsm.c - Steve Kemp
  3. *
  4. * This is a security module which is designed to prevent
  5. * the execution of unknown or (maliciously) altered binaries.
  6. *
  7. * This is achieved by computing an SHA1 digest of every
  8. * binary before it is executed, then comparing that to the
  9. * (assumed) known-good value which is stored as an extended
  10. * attribute alongside the binary.
  11. *
  12. * The intention is thus that a malicious binary will either
  13. * have a missing hash, or a bogus hash.
  14. *
  15. * Potential flaws in this approach include:
  16. *
  17. * * The use of scripting languages which can do arbitrary "stuff".
  18. *
  19. * * An attacker updating the hashes after replacing the binarie(s).
  20. *
  21. * * The need to update the hashes when there are security updates.
  22. *
  23. * * It kills all ad-hoc shell-scripts.
  24. *
  25. * That said it's a reasonably simple approach which doesn't have any major
  26. * downside.
  27. *
  28. *
  29. * Deploying
  30. * ---------
  31. *
  32. * To add the appropriate hashes you could do something like this:
  33. *
  34. * for i in /bin/?* /sbin/?*; do
  35. * setfattr -n security.hash -v $(sha1sum $i | awk '{print $1}') $i
  36. * done
  37. *
  38. * Steve
  39. * --
  40. *
  41. */
  42.  
  43. #include <linux/xattr.h>
  44. #include <linux/binfmts.h>
  45. #include <linux/lsm_hooks.h>
  46. #include <linux/sysctl.h>
  47. #include <linux/string_helpers.h>
  48. #include <linux/lsm_hooks.h>
  49. #include <linux/types.h>
  50. #include <linux/cred.h>
  51. #include <crypto/hash.h>
  52. #include <crypto/sha.h>
  53. #include <crypto/algapi.h>
  54.  
  55.  
  56. /*
  57. * Given a file and a blob of memory calculate the SHA1 hash
  58. * of the file contents, and store it in the memory.
  59. *
  60. * This is a hacky routine, but it does work :)
  61. *
  62. */
  63. int calc_sha1_hash(struct file *file, u8 *digest)
  64. {
  65. struct crypto_shash *tfm;
  66. struct shash_desc *desc;
  67. loff_t i_size, offset = 0;
  68. char *rbuf;
  69. int rc = 0;
  70.  
  71. // The target we're checking
  72. struct dentry *dentry = file->f_path.dentry;
  73. struct inode *inode = d_backing_inode(dentry);
  74.  
  75. // Allocate the hashing-helper.
  76. tfm = crypto_alloc_shash("sha1", 0, 0);
  77.  
  78. if (IS_ERR(tfm))
  79. {
  80. int error = PTR_ERR(tfm);
  81. printk(KERN_INFO "failed to setup sha1 hasher\n");
  82. return error;
  83. }
  84.  
  85. // Allocate the description.
  86. desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
  87.  
  88. if (!desc)
  89. {
  90. printk(KERN_INFO "Failed to kmalloc desc");
  91. goto out;
  92. }
  93.  
  94. // Setup the description
  95. desc->tfm = tfm;
  96. desc->flags = crypto_shash_get_flags(tfm);
  97.  
  98. // Init the hash
  99. rc = crypto_shash_init(desc);
  100.  
  101. if (rc)
  102. {
  103. printk(KERN_INFO "failed to crypto_shash_init");
  104. goto out2;
  105. }
  106.  
  107. // Allocate a buffer for reading the file contents
  108. rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
  109.  
  110. if (!rbuf)
  111. {
  112. printk(KERN_INFO "failed to kzalloc");
  113. rc = -ENOMEM;
  114. goto out2;
  115. }
  116.  
  117. // Find out how big the file is
  118. i_size = i_size_read(inode);
  119.  
  120. // Read it, in page-sized chunks.
  121. while (offset < i_size)
  122. {
  123.  
  124. int rbuf_len;
  125. rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
  126.  
  127. if (rbuf_len < 0)
  128. {
  129. rc = rbuf_len;
  130. break;
  131. }
  132.  
  133. if (rbuf_len == 0)
  134. break;
  135.  
  136. offset += rbuf_len;
  137.  
  138. rc = crypto_shash_update(desc, rbuf, rbuf_len);
  139.  
  140. if (rc)
  141. break;
  142. }
  143.  
  144. // Free the buffer we used for holding the file-contents
  145. kfree(rbuf);
  146.  
  147. // Finalise the SHA result.
  148. if (!rc)
  149. rc = crypto_shash_final(desc, digest);
  150.  
  151. out2:
  152. kfree(desc);
  153. out:
  154. crypto_free_shash(tfm);
  155. return rc;
  156. }
  157.  
  158.  
  159. /*
  160. * Perform a check of a program execution/map.
  161. *
  162. * Return 0 if it should be allowed, -EPERM on block.
  163. */
  164. static int hashcheck_bprm_check_security(struct linux_binprm *bprm)
  165. {
  166. u8 *digest;
  167. int i;
  168. char *hash = NULL;
  169. char *buffer = NULL;
  170. int rc = 0;
  171.  
  172. // The current task & the UID it is running as.
  173. const struct task_struct *task = current;
  174. kuid_t uid = task->cred->uid;
  175.  
  176. // The target we're checking
  177. struct dentry *dentry = bprm->file->f_path.dentry;
  178. struct inode *inode = d_backing_inode(dentry);
  179. int size = 0;
  180.  
  181. // Root can access everything.
  182. if (uid.val == 0)
  183. return 0;
  184.  
  185. // Allocate some RAM to hold the digest result
  186. digest = (u8*)kmalloc(SHA1_DIGEST_SIZE, GFP_TEMPORARY);
  187.  
  188. if (!digest)
  189. {
  190. printk(KERN_INFO "failed to allocate storage for digest");
  191. return 0;
  192. }
  193.  
  194. //
  195. // We're now going to calculate the hash.
  196. //
  197. memset(digest, 0, SHA1_DIGEST_SIZE);
  198. rc = calc_sha1_hash(bprm->file, digest);
  199.  
  200. //
  201. // Now allocate a second piece of RAM to store the human-readable hash.
  202. //
  203. hash = (char*)kmalloc(PAGE_SIZE, GFP_TEMPORARY);
  204.  
  205. if (!hash)
  206. {
  207. printk(KERN_INFO "failed to allocate storage for digest-pretty");
  208. rc = -ENOMEM;
  209. goto out;
  210. }
  211.  
  212. //
  213. // Create the human-readable result.
  214. //
  215. memset(hash, 0, PAGE_SIZE);
  216.  
  217. for (i = 0; i < SHA1_DIGEST_SIZE; i++)
  218. {
  219. snprintf(hash + (i * 2), 4, "%02x", digest[i]);
  220. }
  221.  
  222. //
  223. // Allocate the buffer for reading the xattr value
  224. //
  225. buffer = kzalloc(PAGE_SIZE, GFP_KERNEL);
  226.  
  227. if (buffer == NULL)
  228. {
  229. printk(KERN_INFO "failed to allocate buffer for xattr value\n");
  230. goto out2;
  231. }
  232.  
  233. //
  234. // Get the xattr value.
  235. //
  236. size = __vfs_getxattr(dentry, inode, "security.hash", buffer, PAGE_SIZE - 1);
  237.  
  238. //
  239. // This is the return-result from this function.
  240. //
  241. rc = 0;
  242.  
  243. //
  244. // No hash? Then the execution is denied.
  245. //
  246. if (size < 0)
  247. {
  248. printk(KERN_INFO "Missing `security.hash` value!\n");
  249. rc = -EPERM;
  250. }
  251. else
  252. {
  253. //
  254. // Using a constant-time comparison see if we got a match.
  255. //
  256. if (crypto_memneq(buffer, hash, strlen(hash)) == 0)
  257. {
  258. printk(KERN_INFO "Hash of %s matched expected result %s - allowing execution\n", bprm->filename, hash);
  259. rc = 0;
  260. }
  261. else
  262. {
  263. printk(KERN_INFO "Hash mismatch for %s - denying execution [%s != %s]\n", bprm->filename, hash, buffer);
  264. rc = -EPERM;
  265. }
  266. }
  267.  
  268. kfree(buffer);
  269.  
  270. out2:
  271. kfree(hash);
  272.  
  273. out:
  274. kfree(digest);
  275.  
  276. return (rc);
  277. }
  278.  
  279. /*
  280. * The hooks we wish to be installed.
  281. */
  282. static struct security_hook_list hashcheck_hooks[] =
  283. {
  284. LSM_HOOK_INIT(bprm_check_security, hashcheck_bprm_check_security),
  285. };
  286.  
  287. /*
  288. * Initialize our module.
  289. */
  290. static int __init hashcheck_init(void)
  291. {
  292. /* register ourselves with the security framework */
  293. security_add_hooks(hashcheck_hooks, ARRAY_SIZE(hashcheck_hooks), "hashcheck");
  294. printk(KERN_INFO "LSM initialized: hashcheck\n");
  295. return 0;
  296. }
  297.  
  298. security_initcall(hashcheck_init);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement