From patchwork Sun Jul 17 20:03:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Topi Miettinen X-Patchwork-Id: 9233827 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 225A460574 for ; Sun, 17 Jul 2016 20:05:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1139B205B0 for ; Sun, 17 Jul 2016 20:05:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 059CA209CD; Sun, 17 Jul 2016 20:05:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7A098205B0 for ; Sun, 17 Jul 2016 20:05:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751701AbcGQUFa (ORCPT ); Sun, 17 Jul 2016 16:05:30 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:34129 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751189AbcGQUFZ (ORCPT ); Sun, 17 Jul 2016 16:05:25 -0400 Received: by mail-wm0-f68.google.com with SMTP id q128so9810974wma.1; Sun, 17 Jul 2016 13:05:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BfL4mFpnw0oM1Dh6KXQe55M4Cn/Wo1IQJxNdAZyDlVM=; b=A3Q57aJPjdCkInpfBTCKuGx2DNzeHtPvmcp4fisRwA7/keGBxA7m/mjD/tHW25ubLw ACvjVv9hoeS9q3EkghF5urFsIORmNX548Iq/daMDib8eeGSllV/eK77ShQxRpE8HKCrL VVPD1q8aOnTfbouDMSn12V/PenVhG0xey6a0KzNaV486n6d+HKBe9q3RP6xq3768aCQI JUmcPth9U6vMVmvXDGeFHonIcKO1HnAeosK7kJhRlTDCbdzRK9G6WsGpk+79mB1qxp4C G72WZnyCE75gB1+tbebX9AL+89ma0/4Ge6UN5fUGsF+LkYTKqy8IgF3gIO1SwZ1bjX8r NNsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=BfL4mFpnw0oM1Dh6KXQe55M4Cn/Wo1IQJxNdAZyDlVM=; b=eVnKt1g5R7D/yvw4SaEQsUza9Py61q2UylcKMCxeJpWyRJLVhK3PGYz9DLLyWpcQqv qPNgUtw8L4DB5CSkMX1VwWCMqq8b+J9asXW4Y0+W5YaKF2IhgjGG4WNKHrJQA+0Y0lRd 5tgKIwbfa5PYYFyMRB37/4zzhVvFaKGWcmQ8BnVKz8MsnpAtswhTfyk165zZA4xonfby 7SGrvTcDqEtpjhQPWFJHz3wkZJoYjFGjoXIOF46YeFEmrOqsge9+LLfHo0xFvVprElpy 0CQKDSg8T3qfqvixgQvi+7fYS/5Y58uHB8ROGNnJ2cpvQflqip+baNV44EYhxp5yE7Pm HbFw== X-Gm-Message-State: ALyK8tLwtvOYTrQH2LRYJjFNCrFzcZAFBM5ftdOaYk9x4pruVwm5v6VLIxkpneKILid2Ug== X-Received: by 10.28.167.80 with SMTP id q77mr32480767wme.62.1468785924090; Sun, 17 Jul 2016 13:05:24 -0700 (PDT) Received: from localhost.localdomain ([2001:2003:f54a:b700:1cac:ceff:fed8:ae1c]) by smtp.gmail.com with ESMTPSA id q23sm10969226wme.17.2016.07.17.13.05.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 17 Jul 2016 13:05:23 -0700 (PDT) From: Topi Miettinen To: linux-kernel@vger.kernel.org Cc: Topi Miettinen , James Morris , "Serge E. Hallyn" , linux-security-module@vger.kernel.org (open list:SECURITY SUBSYSTEM) Subject: [PATCH 2/2] device_cgroup: track and present accessed devices Date: Sun, 17 Jul 2016 23:03:39 +0300 Message-Id: <1468785820-3960-4-git-send-email-toiwoton@gmail.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1468785820-3960-1-git-send-email-toiwoton@gmail.com> References: <1468785820-3960-1-git-send-email-toiwoton@gmail.com> Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Track what devices are accessed, to be able to configure device cgroup access lists. The information is available in cgroup FS as file devices.accessed. Example case demonstrating how to use the info for systemd configuration: root@debian:~# cat /sys/fs/cgroup/devices/system.slice/smartd.service/devices.accessed b 8:0 r c 1:3 rw root@debian:~# ls -l /dev/char/1\:3 /dev/block/8\:0 lrwxrwxrwx 1 root root 6 Jul 17 19:24 /dev/block/8:0 -> ../sda lrwxrwxrwx 1 root root 7 Jul 17 19:24 /dev/char/1:3 -> ../null root@debian:~# cat /etc/systemd/system/smartd.service.d/local.conf [Service] DevicePolicy=closed # implies /dev/null rwm DeviceAllow=/dev/sda r Signed-off-by: Topi Miettinen --- security/device_cgroup.c | 86 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 03c1652..d40a2b9 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -48,6 +48,7 @@ struct dev_exception_item { struct dev_cgroup { struct cgroup_subsys_state css; struct list_head exceptions; + struct list_head accessed; enum devcg_behavior behavior; }; @@ -90,18 +91,15 @@ free_and_exit: /* * called under devcgroup_mutex */ -static int dev_exception_add(struct dev_cgroup *dev_cgroup, - struct dev_exception_item *ex) +static int dev_list_add(struct list_head *exceptions, + struct dev_exception_item *ex) { struct dev_exception_item *excopy, *walk; + bool found = false; lockdep_assert_held(&devcgroup_mutex); - excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL); - if (!excopy) - return -ENOMEM; - - list_for_each_entry(walk, &dev_cgroup->exceptions, list) { + list_for_each_entry(walk, exceptions, list) { if (walk->type != ex->type) continue; if (walk->major != ex->major) @@ -110,12 +108,15 @@ static int dev_exception_add(struct dev_cgroup *dev_cgroup, continue; walk->access |= ex->access; - kfree(excopy); - excopy = NULL; + found = true; } - if (excopy != NULL) - list_add_tail_rcu(&excopy->list, &dev_cgroup->exceptions); + if (!found) { + excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL); + if (!excopy) + return -ENOMEM; + list_add_tail_rcu(&excopy->list, exceptions); + } return 0; } @@ -155,6 +156,16 @@ static void __dev_exception_clean(struct dev_cgroup *dev_cgroup) } } +static void dev_accessed_clean(struct dev_cgroup *dev_cgroup) +{ + struct dev_exception_item *ex, *tmp; + + list_for_each_entry_safe(ex, tmp, &dev_cgroup->accessed, list) { + list_del_rcu(&ex->list); + kfree_rcu(ex, rcu); + } +} + /** * dev_exception_clean - frees all entries of the exception list * @dev_cgroup: dev_cgroup with the exception list to be cleaned @@ -221,6 +232,7 @@ devcgroup_css_alloc(struct cgroup_subsys_state *parent_css) if (!dev_cgroup) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&dev_cgroup->exceptions); + INIT_LIST_HEAD(&dev_cgroup->accessed); dev_cgroup->behavior = DEVCG_DEFAULT_NONE; return &dev_cgroup->css; @@ -231,6 +243,7 @@ static void devcgroup_css_free(struct cgroup_subsys_state *css) struct dev_cgroup *dev_cgroup = css_to_devcgroup(css); __dev_exception_clean(dev_cgroup); + dev_accessed_clean(dev_cgroup); kfree(dev_cgroup); } @@ -272,9 +285,9 @@ static void set_majmin(char *str, unsigned m) sprintf(str, "%u", m); } -static int devcgroup_seq_show(struct seq_file *m, void *v) +static int devcgroup_seq_show_list(struct seq_file *m, struct dev_cgroup *devcgroup, + struct list_head *exceptions, bool allow) { - struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m)); struct dev_exception_item *ex; char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN]; @@ -285,14 +298,14 @@ static int devcgroup_seq_show(struct seq_file *m, void *v) * - List the exceptions in case the default policy is to deny * This way, the file remains as a "whitelist of devices" */ - if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) { + if (allow) { set_access(acc, ACC_MASK); set_majmin(maj, ~0); set_majmin(min, ~0); seq_printf(m, "%c %s:%s %s\n", type_to_char(DEV_ALL), maj, min, acc); } else { - list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) { + list_for_each_entry_rcu(ex, exceptions, list) { set_access(acc, ex->access); set_majmin(maj, ex->major); set_majmin(min, ex->minor); @@ -305,6 +318,36 @@ static int devcgroup_seq_show(struct seq_file *m, void *v) return 0; } +static int devcgroup_seq_show(struct seq_file *m, void *v) +{ + struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m)); + + return devcgroup_seq_show_list(m, devcgroup, &devcgroup->exceptions, + devcgroup->behavior == DEVCG_DEFAULT_ALLOW); +} + +static int devcgroup_seq_show_accessed(struct seq_file *m, void *v) +{ + struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m)); + + return devcgroup_seq_show_list(m, devcgroup, &devcgroup->accessed, false); +} + +static void devcgroup_add_accessed(struct dev_cgroup *dev_cgroup, short type, + u32 major, u32 minor, short access) +{ + struct dev_exception_item ex; + + ex.type = type; + ex.major = major; + ex.minor = minor; + ex.access = access; + + mutex_lock(&devcgroup_mutex); + dev_list_add(&dev_cgroup->accessed, &ex); + mutex_unlock(&devcgroup_mutex); +} + /** * match_exception - iterates the exception list trying to find a complete match * @exceptions: list of exceptions @@ -566,7 +609,7 @@ static int propagate_exception(struct dev_cgroup *devcg_root, */ if (devcg_root->behavior == DEVCG_DEFAULT_ALLOW && devcg->behavior == DEVCG_DEFAULT_ALLOW) { - rc = dev_exception_add(devcg, ex); + rc = dev_list_add(&devcg->exceptions, ex); if (rc) break; } else { @@ -736,7 +779,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, if (!parent_has_perm(devcgroup, &ex)) return -EPERM; - rc = dev_exception_add(devcgroup, &ex); + rc = dev_list_add(&devcgroup->exceptions, &ex); break; case DEVCG_DENY: /* @@ -747,7 +790,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, if (devcgroup->behavior == DEVCG_DEFAULT_DENY) dev_exception_rm(devcgroup, &ex); else - rc = dev_exception_add(devcgroup, &ex); + rc = dev_list_add(&devcgroup->exceptions, &ex); if (rc) break; @@ -788,6 +831,11 @@ static struct cftype dev_cgroup_files[] = { .seq_show = devcgroup_seq_show, .private = DEVCG_LIST, }, + { + .name = "accessed", + .seq_show = devcgroup_seq_show_accessed, + .private = DEVCG_LIST, + }, { } /* terminate */ }; @@ -830,6 +878,8 @@ static int __devcgroup_check_permission(short type, u32 major, u32 minor, if (!rc) return -EPERM; + devcgroup_add_accessed(dev_cgroup, type, major, minor, access); + return 0; }