1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
From: Christian Kastner <ckk@kvr.at>
Date: Sat, 26 Dec 2015 00:02:08 +0100
Subject: Improve mode checks for crontabs
Improve mode checks for crontabs to improve security. Specifically, check for:
* Invalid owner
* Invalid filetype
* Insecure mode
* Hard links
Forwarded: no
Last-Update: 2015-12-26
---
cron.8 | 2 ++
database.c | 28 +++++++++++++++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/cron.8 b/cron.8
index 2f3e7a4..eaca890 100644
--- a/cron.8
+++ b/cron.8
@@ -41,6 +41,8 @@ command should be used to access and update them.
.I cron
also reads /etc/crontab, which is in a slightly different format (see
.IR crontab (5)).
+/etc/crontab must be owned by root, and must not
+be group-or other-writable.
.I cron
then wakes up every minute, examining all stored crontabs, checking
each command to see if it should be run in the current minute. When
diff --git a/database.c b/database.c
index 09f44a4..fceb578 100644
--- a/database.c
+++ b/database.c
@@ -222,7 +222,7 @@ process_crontab(uname, fname, tabname, statbuf, new_db, old_db)
goto next_crontab;
}
- if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
+ if ((crontab_fd = open(tabname, O_RDONLY|O_NOFOLLOW, 0)) < OK) {
/* crontab not accessible?
*/
log_it(fname, getpid(), "CAN'T OPEN", tabname);
@@ -233,6 +233,32 @@ process_crontab(uname, fname, tabname, statbuf, new_db, old_db)
log_it(fname, getpid(), "FSTAT FAILED", tabname);
goto next_crontab;
}
+ /* Check to make sure that the crontab is owned by the correct user
+ (or root) */
+
+ if (statbuf->st_uid != pw->pw_uid &&
+ statbuf->st_uid != ROOT_UID) {
+ log_it(fname, getpid(), "WRONG FILE OWNER", tabname);
+ goto next_crontab;
+ }
+
+ /* Check to make sure that the crontab is a regular file */
+ if (!S_ISREG(statbuf->st_mode)) {
+ log_it(fname, getpid(), "NOT A REGULAR FILE", tabname);
+ goto next_crontab;
+ }
+
+ /* Check to make sure that the crontab's permissions are secure */
+ if ((statbuf->st_mode & 07777) != 0600) {
+ log_it(fname, getpid(), "INSECURE MODE (mode 0600 expected)", tabname);
+ goto next_crontab;
+ }
+
+ /* Check to make sure that there are no hardlinks to the crontab */
+ if (statbuf->st_nlink != 1) {
+ log_it(fname, getpid(), "NUMBER OF HARD LINKS > 1", tabname);
+ goto next_crontab;
+ }
Debug(DLOAD, ("\t%s:", fname))
u = find_user(old_db, fname);
|