* [RFC v4 12/18] bpf: Cosmetic change for bpf_prog_attach()
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
Move code outside a switch/case to ease code factoring (cf. next
commit).
This apply on Daniel Mack's "Add eBPF hooks for cgroups" v7:
https://lkml.kernel.org/r/1477390454-12553-1-git-send-email-daniel@zonque.org
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Daniel Mack <daniel@zonque.org>
---
kernel/bpf/syscall.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0f7faa9d2262..ac4cbb98596d 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -843,23 +843,24 @@ static int bpf_prog_attach(const union bpf_attr *attr)
case BPF_CGROUP_INET_EGRESS:
prog = bpf_prog_get_type(attr->attach_bpf_fd,
BPF_PROG_TYPE_CGROUP_SKB);
- if (IS_ERR(prog))
- return PTR_ERR(prog);
-
- cgrp = cgroup_get_from_fd(attr->target_fd);
- if (IS_ERR(cgrp)) {
- bpf_prog_put(prog);
- return PTR_ERR(cgrp);
- }
-
- cgroup_bpf_update(cgrp, prog, attr->attach_type);
- cgroup_put(cgrp);
break;
default:
return -EINVAL;
}
+ if (IS_ERR(prog))
+ return PTR_ERR(prog);
+
+ cgrp = cgroup_get_from_fd(attr->target_fd);
+ if (IS_ERR(cgrp)) {
+ bpf_prog_put(prog);
+ return PTR_ERR(cgrp);
+ }
+
+ cgroup_bpf_update(cgrp, prog, attr->attach_type);
+ cgroup_put(cgrp);
+
return 0;
}
--
2.9.3
^ permalink raw reply related
* [RFC v4 11/18] seccomp,landlock: Handle Landlock hooks per process hierarchy
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry,
kernel-hardening-ZwoEplunGu1jrUoiu81ncdBPR1lH4CV8,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, cgroups
In-Reply-To: <20161026065654.19166-1-mic-WFhQfpSGs3bR7s880joybQ@public.gmane.org>
The seccomp(2) syscall can be use to apply a Landlock rule to the
current process. As with a seccomp filter, the Landlock rule is enforced
for all its future children. An inherited rule tree can be updated
(append-only) by the owner of inherited Landlock nodes (e.g. a parent
process that create a new rule). However, an intermediate task, which
did not create a rule, will not be able to update its children's rules.
Changes since v3:
* remove the hard link with seccomp (suggested by Andy Lutomirski and
Kees Cook):
* remove the cookie which could imply multiple evaluation of Landlock
rules
* remove the origin field in struct landlock_data
* remove documentation fix (merged upstream)
* rename the new seccomp command to SECCOMP_ADD_LANDLOCK_RULE
* internal renaming
Changes since v2:
* Landlock programs can now be run without seccomp filter but for any
syscall (from the process) or interruption
* move Landlock related functions and structs into security/landlock/*
(to manage cgroups as well)
* fix seccomp filter handling: run Landlock programs for each of their
legitimate seccomp filter
* properly clean up all seccomp results
* cosmetic changes to ease the understanding
* fix some ifdef
Signed-off-by: Mickaël Salaün <mic-WFhQfpSGs3bR7s880joybQ@public.gmane.org>
Cc: Kees Cook <keescook-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Cc: Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org>
Cc: Will Drewry <wad-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Cc: Andrew Morton <akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
Link: https://lkml.kernel.org/r/CAGXu5j+qowiyQuhifOBtupfPxp6XevdgF08BW4yzkVDTCha0xA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org
---
include/linux/landlock.h | 5 +++++
include/linux/seccomp.h | 8 +++++++
include/uapi/linux/seccomp.h | 1 +
kernel/fork.c | 13 +++++++++--
kernel/seccomp.c | 8 +++++++
security/landlock/lsm.c | 8 +++++--
security/landlock/manager.c | 51 ++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 90 insertions(+), 4 deletions(-)
diff --git a/include/linux/landlock.h b/include/linux/landlock.h
index 263be3cf0b48..72b4235d255f 100644
--- a/include/linux/landlock.h
+++ b/include/linux/landlock.h
@@ -74,5 +74,10 @@ struct landlock_hooks {
void put_landlock_hooks(struct landlock_hooks *hooks);
+#ifdef CONFIG_SECCOMP_FILTER
+int landlock_seccomp_append_prog(unsigned int flags,
+ const char __user *user_bpf_fd);
+#endif /* CONFIG_SECCOMP_FILTER */
+
#endif /* CONFIG_SECURITY_LANDLOCK */
#endif /* _LINUX_LANDLOCK_H */
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index e25aee2cdfc0..4a8ccc7ff976 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -10,6 +10,10 @@
#include <linux/thread_info.h>
#include <asm/seccomp.h>
+#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_SECURITY_LANDLOCK)
+#include <linux/landlock.h>
+#endif /* CONFIG_SECCOMP_FILTER && CONFIG_SECURITY_LANDLOCK */
+
struct seccomp_filter;
/**
* struct seccomp - the state of a seccomp'ed process
@@ -18,6 +22,7 @@ struct seccomp_filter;
* system calls available to a process.
* @filter: must always point to a valid seccomp-filter or NULL as it is
* accessed without locking during system call entry.
+ * @landlock_hooks: contains an array of Landlock programs.
*
* @filter must only be accessed from the context of current as there
* is no read locking.
@@ -25,6 +30,9 @@ struct seccomp_filter;
struct seccomp {
int mode;
struct seccomp_filter *filter;
+#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_SECURITY_LANDLOCK)
+ struct landlock_hooks *landlock_hooks;
+#endif /* CONFIG_SECCOMP_FILTER && CONFIG_SECURITY_LANDLOCK */
};
#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index 0f238a43ff1e..56dd692cddac 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -13,6 +13,7 @@
/* Valid operations for seccomp syscall. */
#define SECCOMP_SET_MODE_STRICT 0
#define SECCOMP_SET_MODE_FILTER 1
+#define SECCOMP_ADD_LANDLOCK_RULE 2
/* Valid flags for SECCOMP_SET_MODE_FILTER */
#define SECCOMP_FILTER_FLAG_TSYNC 1
diff --git a/kernel/fork.c b/kernel/fork.c
index 0690e43bdda5..d8af3ba554fa 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -510,7 +510,10 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
* the usage counts on the error path calling free_task.
*/
tsk->seccomp.filter = NULL;
-#endif
+#ifdef CONFIG_SECURITY_LANDLOCK
+ tsk->seccomp.landlock_hooks = NULL;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+#endif /* CONFIG_SECCOMP */
setup_thread_stack(tsk, orig);
clear_user_return_notifier(tsk);
@@ -1378,7 +1381,13 @@ static void copy_seccomp(struct task_struct *p)
/* Ref-count the new filter user, and assign it. */
get_seccomp_filter(current);
- p->seccomp = current->seccomp;
+ p->seccomp.mode = current->seccomp.mode;
+ p->seccomp.filter = current->seccomp.filter;
+#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_SECURITY_LANDLOCK)
+ p->seccomp.landlock_hooks = current->seccomp.landlock_hooks;
+ if (p->seccomp.landlock_hooks)
+ atomic_inc(&p->seccomp.landlock_hooks->usage);
+#endif /* CONFIG_SECCOMP_FILTER && CONFIG_SECURITY_LANDLOCK */
/*
* Explicitly enable no_new_privs here in case it got set
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index e741a82eab4d..f967ddf9d4b5 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -32,6 +32,7 @@
#include <linux/security.h>
#include <linux/tracehook.h>
#include <linux/uaccess.h>
+#include <linux/landlock.h>
/**
* struct seccomp_filter - container for seccomp BPF programs
@@ -493,6 +494,9 @@ static void put_seccomp_filter(struct seccomp_filter *filter)
void put_seccomp(struct task_struct *tsk)
{
put_seccomp_filter(tsk->seccomp.filter);
+#ifdef CONFIG_SECURITY_LANDLOCK
+ put_landlock_hooks(tsk->seccomp.landlock_hooks);
+#endif /* CONFIG_SECURITY_LANDLOCK */
}
/**
@@ -797,6 +801,10 @@ static long do_seccomp(unsigned int op, unsigned int flags,
return seccomp_set_mode_strict();
case SECCOMP_SET_MODE_FILTER:
return seccomp_set_mode_filter(flags, uargs);
+#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_SECURITY_LANDLOCK)
+ case SECCOMP_ADD_LANDLOCK_RULE:
+ return landlock_seccomp_append_prog(flags, uargs);
+#endif /* CONFIG_SECCOMP_FILTER && CONFIG_SECURITY_LANDLOCK */
default:
return -EINVAL;
}
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index b3c107244df9..572f4f7f9f19 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
+#include <asm/current.h>
#include <linux/bpf.h> /* enum bpf_reg_type, struct landlock_data */
#include <linux/cred.h>
#include <linux/err.h> /* MAX_ERRNO */
@@ -15,6 +16,7 @@
#include <linux/kernel.h> /* FIELD_SIZEOF() */
#include <linux/landlock.h>
#include <linux/lsm_hooks.h>
+#include <linux/seccomp.h> /* struct seccomp_* */
#include <linux/types.h> /* uintptr_t */
/* hook arguments */
@@ -161,8 +163,10 @@ static int landlock_enforce(enum landlock_hook hook, __u64 args[6])
.args[5] = args[5],
};
- /* placeholder for seccomp and cgroup managers */
- ret = landlock_run_prog(hook_idx, &ctx, NULL);
+#ifdef CONFIG_SECCOMP_FILTER
+ ret = landlock_run_prog(hook_idx, &ctx,
+ current->seccomp.landlock_hooks);
+#endif /* CONFIG_SECCOMP_FILTER */
return -ret;
}
diff --git a/security/landlock/manager.c b/security/landlock/manager.c
index f3f03b64ebef..56e99ccd5708 100644
--- a/security/landlock/manager.c
+++ b/security/landlock/manager.c
@@ -14,8 +14,11 @@
#include <linux/filter.h> /* struct bpf_prog */
#include <linux/kernel.h> /* round_up() */
#include <linux/landlock.h>
+#include <linux/sched.h> /* current_cred(), task_no_new_privs() */
+#include <linux/security.h> /* security_capable_noaudit() */
#include <linux/slab.h> /* alloc(), kfree() */
#include <linux/types.h> /* atomic_t */
+#include <linux/uaccess.h> /* copy_from_user() */
#include "common.h"
@@ -263,3 +266,51 @@ static struct landlock_hooks *landlock_append_prog(
put_landlock_rule(rule);
return new_hooks;
}
+
+/**
+ * landlock_seccomp_append_prog - attach a Landlock program to the current process
+ *
+ * current->seccomp.landlock_hooks is lazily allocated. When a process fork,
+ * only a pointer is copied. When a new hook is added by a process, if there is
+ * other references to this process' landlock_hooks, then a new allocation is
+ * made to contains an array pointing to Landlock program lists. This design
+ * has low-performance impact and memory efficiency while keeping the property
+ * of append-only programs.
+ *
+ * @flags: not used for now, but could be used for TSYNC
+ * @user_bpf_fd: file descriptor pointing to a loaded/checked eBPF program
+ * dedicated to Landlock
+ */
+#ifdef CONFIG_SECCOMP_FILTER
+int landlock_seccomp_append_prog(unsigned int flags, const char __user *user_bpf_fd)
+{
+ struct landlock_hooks *new_hooks;
+ struct bpf_prog *prog;
+ int bpf_fd;
+
+ if (!task_no_new_privs(current) &&
+ security_capable_noaudit(current_cred(),
+ current_user_ns(), CAP_SYS_ADMIN) != 0)
+ return -EPERM;
+ if (!user_bpf_fd)
+ return -EINVAL;
+ if (flags)
+ return -EINVAL;
+ if (copy_from_user(&bpf_fd, user_bpf_fd, sizeof(user_bpf_fd)))
+ return -EFAULT;
+ prog = bpf_prog_get(bpf_fd);
+ if (IS_ERR(prog))
+ return PTR_ERR(prog);
+
+ /*
+ * We don't need to lock anything for the current process hierarchy,
+ * everything is guarded by the atomic counters.
+ */
+ new_hooks = landlock_append_prog(current->seccomp.landlock_hooks, prog);
+ /* @prog is managed/freed by landlock_append_prog() */
+ if (IS_ERR(new_hooks))
+ return PTR_ERR(new_hooks);
+ current->seccomp.landlock_hooks = new_hooks;
+ return 0;
+}
+#endif /* CONFIG_SECCOMP_FILTER */
--
2.9.3
^ permalink raw reply related
* [RFC v4 10/18] seccomp: Split put_seccomp_filter() with put_seccomp()
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
The semantic is unchanged. This will be useful for the Landlock
integration with seccomp (next commit).
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Will Drewry <wad@chromium.org>
---
include/linux/seccomp.h | 4 ++--
kernel/fork.c | 2 +-
kernel/seccomp.c | 18 +++++++++++++-----
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index ecc296c137cd..e25aee2cdfc0 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -77,10 +77,10 @@ static inline int seccomp_mode(struct seccomp *s)
#endif /* CONFIG_SECCOMP */
#ifdef CONFIG_SECCOMP_FILTER
-extern void put_seccomp_filter(struct task_struct *tsk);
+extern void put_seccomp(struct task_struct *tsk);
extern void get_seccomp_filter(struct task_struct *tsk);
#else /* CONFIG_SECCOMP_FILTER */
-static inline void put_seccomp_filter(struct task_struct *tsk)
+static inline void put_seccomp(struct task_struct *tsk)
{
return;
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 623259fc794d..0690e43bdda5 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -349,7 +349,7 @@ void free_task(struct task_struct *tsk)
#endif
rt_mutex_debug_task_free(tsk);
ftrace_graph_exit_task(tsk);
- put_seccomp_filter(tsk);
+ put_seccomp(tsk);
arch_release_task_struct(tsk);
free_task_struct(tsk);
}
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 0db7c8a2afe2..e741a82eab4d 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -63,6 +63,8 @@ struct seccomp_filter {
/* Limit any path through the tree to 256KB worth of instructions. */
#define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
+static void put_seccomp_filter(struct seccomp_filter *filter);
+
/*
* Endianness is explicitly ignored and left for BPF program authors to manage
* as per the specific architecture.
@@ -313,7 +315,7 @@ static inline void seccomp_sync_threads(void)
* current's path will hold a reference. (This also
* allows a put before the assignment.)
*/
- put_seccomp_filter(thread);
+ put_seccomp_filter(thread->seccomp.filter);
smp_store_release(&thread->seccomp.filter,
caller->seccomp.filter);
@@ -475,10 +477,11 @@ static inline void seccomp_filter_free(struct seccomp_filter *filter)
}
}
-/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
-void put_seccomp_filter(struct task_struct *tsk)
+/* put_seccomp_filter - decrements the ref count of a filter */
+static void put_seccomp_filter(struct seccomp_filter *filter)
{
- struct seccomp_filter *orig = tsk->seccomp.filter;
+ struct seccomp_filter *orig = filter;
+
/* Clean up single-reference branches iteratively. */
while (orig && atomic_dec_and_test(&orig->usage)) {
struct seccomp_filter *freeme = orig;
@@ -487,6 +490,11 @@ void put_seccomp_filter(struct task_struct *tsk)
}
}
+void put_seccomp(struct task_struct *tsk)
+{
+ put_seccomp_filter(tsk->seccomp.filter);
+}
+
/**
* seccomp_send_sigsys - signals the task to allow in-process syscall emulation
* @syscall: syscall number to send to userland
@@ -898,7 +906,7 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
ret = -EFAULT;
- put_seccomp_filter(task);
+ put_seccomp_filter(task->seccomp.filter);
return ret;
out:
--
2.9.3
^ permalink raw reply related
* [RFC v4 09/18] landlock: Add manager functions
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
This is the main code usable by the seccomp and cgroup managers. This
allow to manage the landlock_hooks, landlock_node and landlock_rule
structs.
Landlock rules can be tied to a LSM hook. When such a hook is triggered,
a tree of rules can be evaluated. A tree is created with a first node.
This node reference a list of rules and an optional parent node. Each
rule return a 32-bit value which can interrupt the evaluation with a
non-zero value. This value is then returned by the syscall as an ERRNO
code. If every rules returned zero, the evaluation continues with the
rule list of the parent node, until the end of the tree.
Changes since v3:
* split commit
* new design to be able to inherit on the fly the parent rules
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Serge E. Hallyn <serge@hallyn.com>
---
include/linux/landlock.h | 2 +
security/landlock/Makefile | 2 +-
security/landlock/manager.c | 265 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 268 insertions(+), 1 deletion(-)
create mode 100644 security/landlock/manager.c
diff --git a/include/linux/landlock.h b/include/linux/landlock.h
index 2ab2be8e3e6e..263be3cf0b48 100644
--- a/include/linux/landlock.h
+++ b/include/linux/landlock.h
@@ -72,5 +72,7 @@ struct landlock_hooks {
struct landlock_node *nodes[_LANDLOCK_HOOK_LAST];
};
+void put_landlock_hooks(struct landlock_hooks *hooks);
+
#endif /* CONFIG_SECURITY_LANDLOCK */
#endif /* _LINUX_LANDLOCK_H */
diff --git a/security/landlock/Makefile b/security/landlock/Makefile
index 27f359a8cfaa..1a77e54d8041 100644
--- a/security/landlock/Makefile
+++ b/security/landlock/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o
-landlock-y := lsm.o checker_fs.o
+landlock-y := lsm.o checker_fs.o manager.o
diff --git a/security/landlock/manager.c b/security/landlock/manager.c
new file mode 100644
index 000000000000..f3f03b64ebef
--- /dev/null
+++ b/security/landlock/manager.c
@@ -0,0 +1,265 @@
+/*
+ * Landlock LSM - seccomp and cgroups managers
+ *
+ * Copyright (C) 2016 Mickaël Salaün <mic@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/page.h> /* PAGE_SIZE */
+#include <linux/atomic.h> /* atomic_*(), smp_store_release() */
+#include <linux/bpf.h> /* bpf_prog_put() */
+#include <linux/filter.h> /* struct bpf_prog */
+#include <linux/kernel.h> /* round_up() */
+#include <linux/landlock.h>
+#include <linux/slab.h> /* alloc(), kfree() */
+#include <linux/types.h> /* atomic_t */
+
+#include "common.h"
+
+static void put_landlock_rule(struct landlock_rule *rule)
+{
+ struct landlock_rule *orig = rule;
+
+ /* clean up single-reference branches iteratively */
+ while (orig && atomic_dec_and_test(&orig->usage)) {
+ struct landlock_rule *freeme = orig;
+
+ bpf_prog_put(orig->prog);
+ orig = orig->prev;
+ kfree(freeme);
+ }
+}
+
+static void put_landlock_node(struct landlock_node *node)
+{
+ struct landlock_node *orig = node;
+
+ /* clean up single-reference branches iteratively */
+ while (orig && atomic_dec_and_test(&orig->usage)) {
+ struct landlock_node *freeme = orig;
+
+ put_landlock_rule(orig->rule);
+ orig = orig->prev;
+ kfree(freeme);
+ }
+}
+
+void put_landlock_hooks(struct landlock_hooks *hooks)
+{
+ if (hooks && atomic_dec_and_test(&hooks->usage)) {
+ size_t i;
+
+ /* XXX: Do we need to use lockless_dereference() here? */
+ for (i = 0; i < ARRAY_SIZE(hooks->nodes); i++) {
+ if (!hooks->nodes[i])
+ continue;
+ /* Are we the owner of this node? */
+ if (hooks->nodes[i]->owner == &hooks->nodes[i])
+ hooks->nodes[i]->owner = NULL;
+ put_landlock_node(hooks->nodes[i]);
+ }
+ kfree(hooks);
+ }
+}
+
+static struct landlock_hooks *new_raw_landlock_hooks(void)
+{
+ struct landlock_hooks *ret;
+
+ /* array filled with NULL values */
+ ret = kzalloc(sizeof(*ret), GFP_KERNEL);
+ if (!ret)
+ return ERR_PTR(-ENOMEM);
+ atomic_set(&ret->usage, 1);
+ return ret;
+}
+
+static struct landlock_hooks *new_filled_landlock_hooks(void)
+{
+ size_t i;
+ struct landlock_hooks *ret;
+
+ ret = new_raw_landlock_hooks();
+ if (IS_ERR(ret))
+ return ret;
+ /*
+ * We need to initially allocate every nodes to be able to update the
+ * rules they are pointing to, across every (future) children of the
+ * current task.
+ */
+ for (i = 0; i < ARRAY_SIZE(ret->nodes); i++) {
+ struct landlock_node *node;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ goto put_hooks;
+ atomic_set(&node->usage, 1);
+ /* We are the owner of this node. */
+ node->owner = &ret->nodes[i];
+ ret->nodes[i] = node;
+ }
+ return ret;
+
+put_hooks:
+ put_landlock_hooks(ret);
+ return ERR_PTR(-ENOMEM);
+}
+
+static void add_landlock_rule(struct landlock_hooks *hooks,
+ struct landlock_rule *rule)
+{
+ /* subtype.landlock_rule.hook > 0 for loaded programs */
+ u32 hook_idx = get_index(rule->prog->subtype.landlock_rule.hook);
+
+ rule->prev = hooks->nodes[hook_idx]->rule;
+ WARN_ON(atomic_read(&rule->usage));
+ atomic_set(&rule->usage, 1);
+ /* do not increment the previous rule usage */
+ smp_store_release(&hooks->nodes[hook_idx]->rule, rule);
+}
+
+/* Limit Landlock hooks to 256KB. */
+#define LANDLOCK_HOOKS_MAX_PAGES (1 << 6)
+
+/**
+ * landlock_append_prog - attach a Landlock program to @current_hooks
+ *
+ * @current_hooks: landlock_hooks pointer, must be locked (if needed) to
+ * prevent a concurrent put/free. This pointer must not be
+ * freed after the call.
+ * @prog: non-NULL Landlock program to append to @current_hooks. @prog will be
+ * owned by landlock_append_prog() and freed if an error happened.
+ *
+ * Return @current_hooks or a new pointer when OK. Return a pointer error
+ * otherwise.
+ */
+static struct landlock_hooks *landlock_append_prog(
+ struct landlock_hooks *current_hooks, struct bpf_prog *prog)
+{
+ struct landlock_hooks *new_hooks = current_hooks;
+ unsigned long pages;
+ struct landlock_rule *rule;
+ u32 hook_idx;
+
+ if (prog->type != BPF_PROG_TYPE_LANDLOCK) {
+ new_hooks = ERR_PTR(-EINVAL);
+ goto put_prog;
+ }
+
+ /* validate memory size allocation */
+ pages = prog->pages;
+ if (current_hooks) {
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(current_hooks->nodes); i++) {
+ struct landlock_node *walker_n;
+
+ for (walker_n = current_hooks->nodes[i];
+ walker_n;
+ walker_n = walker_n->prev) {
+ struct landlock_rule *walker_r;
+
+ for (walker_r = walker_n->rule;
+ walker_r;
+ walker_r = walker_r->prev)
+ pages += walker_r->prog->pages;
+ }
+ }
+ /* count a struct landlock_hooks if we need to allocate one */
+ if (atomic_read(¤t_hooks->usage) != 1)
+ pages += round_up(sizeof(*current_hooks), PAGE_SIZE) /
+ PAGE_SIZE;
+ }
+ if (pages > LANDLOCK_HOOKS_MAX_PAGES) {
+ new_hooks = ERR_PTR(-E2BIG);
+ goto put_prog;
+ }
+
+ rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ if (!rule) {
+ new_hooks = ERR_PTR(-ENOMEM);
+ goto put_prog;
+ }
+ rule->prog = prog;
+
+ /* subtype.landlock_rule.hook > 0 for loaded programs */
+ hook_idx = get_index(rule->prog->subtype.landlock_rule.hook);
+
+ if (!current_hooks) {
+ /* add a new landlock_hooks, if needed */
+ new_hooks = new_filled_landlock_hooks();
+ if (IS_ERR(new_hooks))
+ goto put_rule;
+ add_landlock_rule(new_hooks, rule);
+ } else {
+ if (new_hooks->nodes[hook_idx]->owner == &new_hooks->nodes[hook_idx]) {
+ /* We are the owner, we can then update the node. */
+ add_landlock_rule(new_hooks, rule);
+ } else if (atomic_read(¤t_hooks->usage) == 1) {
+ WARN_ON(new_hooks->nodes[hook_idx]->owner);
+ /*
+ * We can become the new owner if no other task use it.
+ * This avoid an unnecessary allocation.
+ */
+ new_hooks->nodes[hook_idx]->owner =
+ &new_hooks->nodes[hook_idx];
+ add_landlock_rule(new_hooks, rule);
+ } else {
+ /*
+ * We are not the owner, we need to fork current_hooks
+ * and then add a new node.
+ */
+ struct landlock_node *node;
+ size_t i;
+
+ node = kmalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ new_hooks = ERR_PTR(-ENOMEM);
+ goto put_rule;
+ }
+ atomic_set(&node->usage, 1);
+ /* set the previous node after the new_hooks allocation */
+ node->prev = NULL;
+ /* do not increment the previous node usage */
+ node->owner = &new_hooks->nodes[hook_idx];
+ /* rule->prev is already NULL */
+ atomic_set(&rule->usage, 1);
+ node->rule = rule;
+
+ new_hooks = new_raw_landlock_hooks();
+ if (IS_ERR(new_hooks)) {
+ /* put the rule as well */
+ put_landlock_node(node);
+ return ERR_PTR(-ENOMEM);
+ }
+ for (i = 0; i < ARRAY_SIZE(new_hooks->nodes); i++) {
+ new_hooks->nodes[i] = lockless_dereference(current_hooks->nodes[i]);
+ if (i == hook_idx)
+ node->prev = new_hooks->nodes[i];
+ if (!WARN_ON(!new_hooks->nodes[i]))
+ atomic_inc(&new_hooks->nodes[i]->usage);
+ }
+ new_hooks->nodes[hook_idx] = node;
+
+ /*
+ * @current_hooks will not be freed here because it's usage
+ * field is > 1. It is only prevented to be freed by another
+ * subject thanks to the caller of landlock_append_prog() which
+ * should be locked if needed.
+ */
+ put_landlock_hooks(current_hooks);
+ }
+ }
+ return new_hooks;
+
+put_prog:
+ bpf_prog_put(prog);
+ return new_hooks;
+
+put_rule:
+ put_landlock_rule(rule);
+ return new_hooks;
+}
--
2.9.3
^ permalink raw reply related
* [RFC v4 08/18] landlock: Handle file comparisons
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
Add eBPF functions to compare file system access with a Landlock file
system handle:
* bpf_landlock_cmp_fs_beneath(opt, map, map_op, fs_arg)
This function allows an eBPF program to check if the current accessed
file is the same or in the hierarchy of a reference handle.
* bpf_landlock_get_fs_mode(arg_fs)
This function return the mode of a file. This is useful to check if
a process try to walk through a directory.
The goal of file system handle is to abstract kernel objects such as a
struct file or a struct inode. Userland can create this kind of handle
thanks to the BPF_MAP_UPDATE_ELEM command. The element is a struct
landlock_handle containing the handle type (e.g.
BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD) and a file descriptor. This could
also be any descriptions able to match a struct file or a struct inode
(e.g. path or glob string).
Changes since v3:
* remove bpf_landlock_cmp_fs_prop() (suggested by Alexie Starovoitov)
* add hooks dealing with struct inode and struct path pointers:
inode_permission and inode_getattr
* add abstraction over eBPF helper arguments thanks to wrapping structs
* add bpf_landlock_get_fs_mode() helper to check file type and mode
* merge WARN_ON() (suggested by Kees Cook)
* fix and update bpf_helpers.h
* use BPF_CALL_* for eBPF helpers (suggested by Alexie Starovoitov)
* make handle arraymap safe (RCU) and remove buggy synchronize_rcu()
* factor out the arraymay walk
* use size_t to index array (suggested by Jann Horn)
Changes since v2:
* add MNT_INTERNAL check to only add file handle from user-visible FS
(e.g. no anonymous inode)
* replace struct file* with struct path* in map_landlock_handle
* add BPF protos
* fix bpf_landlock_cmp_fs_prop_with_struct_file()
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Serge E. Hallyn <serge@hallyn.com>
Cc: Jann Horn <jann@thejh.net>
Link: https://lkml.kernel.org/r/CALCETrWwTiz3kZTkEgOW24-DvhQq6LftwEXh77FD2G5o71yD7g@mail.gmail.com
Link: https://lkml.kernel.org/r/20160914190723.GB5617@pc.thejh.net
---
include/linux/bpf.h | 5 ++
include/uapi/linux/bpf.h | 35 ++++++++++
samples/bpf/bpf_helpers.h | 5 ++
security/landlock/Makefile | 2 +-
security/landlock/checker_fs.c | 152 +++++++++++++++++++++++++++++++++++++++++
security/landlock/checker_fs.h | 20 ++++++
security/landlock/common.h | 13 ++++
security/landlock/lsm.c | 6 ++
8 files changed, 237 insertions(+), 1 deletion(-)
create mode 100644 security/landlock/checker_fs.c
create mode 100644 security/landlock/checker_fs.h
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index e7ce49642f50..50fbeaac03fe 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -363,6 +363,11 @@ extern const struct bpf_func_proto bpf_skb_vlan_push_proto;
extern const struct bpf_func_proto bpf_skb_vlan_pop_proto;
extern const struct bpf_func_proto bpf_get_stackid_proto;
+#ifdef CONFIG_SECURITY_LANDLOCK
+extern const struct bpf_func_proto bpf_landlock_cmp_fs_beneath_proto;
+extern const struct bpf_func_proto bpf_landlock_get_fs_mode_proto;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
/* Shared helpers among cBPF and eBPF. */
void bpf_user_rnd_init_once(void);
u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index b6b531a868c0..5f09eda3ab68 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -101,6 +101,13 @@ enum bpf_map_handle_type {
/* BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_GLOB, */
};
+enum bpf_map_array_op {
+ BPF_MAP_ARRAY_OP_UNSPEC,
+ BPF_MAP_ARRAY_OP_OR,
+ BPF_MAP_ARRAY_OP_AND,
+ BPF_MAP_ARRAY_OP_XOR,
+};
+
enum bpf_prog_type {
BPF_PROG_TYPE_UNSPEC,
BPF_PROG_TYPE_SOCKET_FILTER,
@@ -465,6 +472,30 @@ enum bpf_func_id {
*/
BPF_FUNC_set_hash_invalid,
+ /**
+ * bpf_landlock_cmp_fs_beneath(opt, map, map_op, arg_fs)
+ * Check if a struct inode is a leaf of file system handles
+ *
+ * @opt: check options (e.g. LANDLOCK_FLAG_OPT_REVERSE)
+ * @map: handles to compare against
+ * @map_op: which elements of the map to use (e.g. BPF_MAP_ARRAY_OP_OR)
+ * @arg_fs: struct landlock_arg_fs address to compare with
+ *
+ * Return: 0 if the file is the same or beneath the handles,
+ * 1 otherwise, or a negative value if an error occurred.
+ */
+ BPF_FUNC_landlock_cmp_fs_beneath,
+
+ /**
+ * bpf_landlock_get_fs_mode(arg_fs)
+ * Get the mode of a struct landlock_arg_fs
+ *
+ * @arg_fs: struct landlock_arg_fs address
+ *
+ * Return: the file mode
+ */
+ BPF_FUNC_landlock_get_fs_mode,
+
__BPF_FUNC_MAX_ID,
};
@@ -583,6 +614,10 @@ enum landlock_hook {
*/
#define _LANDLOCK_SUBTYPE_OPTION_MASK ((1ULL << 0) - 1)
+/* Handle option flags */
+#define LANDLOCK_FLAG_OPT_REVERSE (1<<0)
+#define _LANDLOCK_FLAG_OPT_MASK ((1ULL << 1) - 1)
+
/* Map handle entry */
struct landlock_handle {
__u32 type; /* enum bpf_map_handle_type */
diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h
index 90f44bd2045e..52fa1ab1c0c4 100644
--- a/samples/bpf/bpf_helpers.h
+++ b/samples/bpf/bpf_helpers.h
@@ -57,6 +57,11 @@ static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) =
(void *) BPF_FUNC_skb_set_tunnel_opt;
static unsigned long long (*bpf_get_prandom_u32)(void) =
(void *) BPF_FUNC_get_prandom_u32;
+static unsigned long long (*bpf_landlock_cmp_fs_beneath)
+ (int option, void *map, int map_op, void *arg_fs) =
+ (void *) BPF_FUNC_landlock_cmp_fs_beneath;
+static unsigned long long (*bpf_landlock_get_fs_mode)(void *arg_fs) =
+ (void *) BPF_FUNC_landlock_get_fs_mode;
/* llvm builtin functions that eBPF C program may use to
* emit BPF_LD_ABS and BPF_LD_IND instructions
diff --git a/security/landlock/Makefile b/security/landlock/Makefile
index 59669d70bc7e..27f359a8cfaa 100644
--- a/security/landlock/Makefile
+++ b/security/landlock/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o
-landlock-y := lsm.o
+landlock-y := lsm.o checker_fs.o
diff --git a/security/landlock/checker_fs.c b/security/landlock/checker_fs.c
new file mode 100644
index 000000000000..01a929a269e6
--- /dev/null
+++ b/security/landlock/checker_fs.c
@@ -0,0 +1,152 @@
+/*
+ * Landlock LSM - File System Checkers
+ *
+ * Copyright (C) 2016 Mickaël Salaün <mic@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bpf.h> /* enum bpf_map_array_op */
+#include <linux/errno.h>
+#include <linux/filter.h> /* BPF_CALL*() */
+#include <linux/fs.h> /* path_is_under() */
+#include <linux/path.h> /* struct path */
+
+#include "common.h" /* struct landlock_arg_fs */
+#include "checker_fs.h"
+
+/*
+ * bpf_landlock_cmp_fs_beneath
+ *
+ * Cf. include/uapi/linux/bpf.h
+ */
+BPF_CALL_4(bpf_landlock_cmp_fs_beneath, u8, option, struct bpf_map *, map,
+ enum bpf_map_array_op, map_op,
+ struct landlock_arg_fs *, arg_fs)
+{
+ struct bpf_array *array = container_of(map, struct bpf_array, map);
+ const struct path *p1 = NULL, *p2 = NULL;
+ struct dentry *d1 = NULL, *d2 = NULL;
+ struct map_landlock_handle *handle;
+ size_t i;
+
+ if (WARN_ON(!map))
+ return -EFAULT;
+ if (WARN_ON(!arg_fs))
+ return -EFAULT;
+ if (unlikely((option | _LANDLOCK_FLAG_OPT_MASK) != _LANDLOCK_FLAG_OPT_MASK))
+ return -EINVAL;
+
+ if (!arg_fs->file) {
+ /* file can be null for anonymous mmap */
+ WARN_ON(arg_fs->type != LANDLOCK_ARGTYPE_FILE);
+ return -ENOENT;
+ }
+
+ /* for now, only handle OP_OR */
+ switch (map_op) {
+ case BPF_MAP_ARRAY_OP_OR:
+ break;
+ case BPF_MAP_ARRAY_OP_UNSPEC:
+ case BPF_MAP_ARRAY_OP_AND:
+ case BPF_MAP_ARRAY_OP_XOR:
+ default:
+ return -EINVAL;
+ }
+ switch (arg_fs->type) {
+ case LANDLOCK_ARGTYPE_FILE:
+ p1 = &arg_fs->file->f_path;
+ break;
+ case LANDLOCK_ARGTYPE_PATH:
+ p1 = arg_fs->path;
+ break;
+ case LANDLOCK_ARGTYPE_INODE:
+ d1 = d_find_alias(arg_fs->inode);
+ if (WARN_ON(!d1))
+ return -ENOENT;
+ break;
+ case LANDLOCK_ARGTYPE_NONE:
+ default:
+ WARN_ON(1);
+ return -EFAULT;
+ }
+ /* {p,d}1 and {p,d}2 will be set correctly in the loop */
+ p2 = p1;
+ d2 = d1;
+
+ if (p1) {
+ for_each_handle(i, handle, array) {
+ if (WARN_ON(handle->type != BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD))
+ return -EINVAL;
+
+ if (option & LANDLOCK_FLAG_OPT_REVERSE)
+ p2 = &handle->path;
+ else
+ p1 = &handle->path;
+
+ if (path_is_under(p2, p1))
+ return 0;
+ }
+ } else if (d1) {
+ for_each_handle(i, handle, array) {
+ if (WARN_ON(handle->type != BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD))
+ return -EINVAL;
+
+ if (option & LANDLOCK_FLAG_OPT_REVERSE)
+ d2 = handle->path.dentry;
+ else
+ d1 = handle->path.dentry;
+
+ if (is_subdir(d2, d1))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+const struct bpf_func_proto bpf_landlock_cmp_fs_beneath_proto = {
+ .func = bpf_landlock_cmp_fs_beneath,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_ANYTHING,
+ .arg2_type = ARG_CONST_PTR_TO_LANDLOCK_HANDLE_FS,
+ .arg3_type = ARG_ANYTHING,
+ .arg4_type = ARG_CONST_PTR_TO_LANDLOCK_ARG_FS,
+};
+
+BPF_CALL_1(bpf_landlock_get_fs_mode, struct landlock_arg_fs *, arg_fs)
+{
+ if (WARN_ON(!arg_fs))
+ return -EFAULT;
+ if (!arg_fs->file) {
+ /* file can be null for anonymous mmap */
+ WARN_ON(arg_fs->type != LANDLOCK_ARGTYPE_FILE);
+ return -ENOENT;
+ }
+ switch (arg_fs->type) {
+ case LANDLOCK_ARGTYPE_FILE:
+ if (WARN_ON(!arg_fs->file->f_inode))
+ return -ENOENT;
+ return arg_fs->file->f_inode->i_mode;
+ case LANDLOCK_ARGTYPE_INODE:
+ return arg_fs->inode->i_mode;
+ case LANDLOCK_ARGTYPE_PATH:
+ if (WARN_ON(!arg_fs->path->dentry ||
+ !arg_fs->path->dentry->d_inode))
+ return -ENOENT;
+ return arg_fs->path->dentry->d_inode->i_mode;
+ case LANDLOCK_ARGTYPE_NONE:
+ default:
+ WARN_ON(1);
+ return -EFAULT;
+ }
+}
+
+const struct bpf_func_proto bpf_landlock_get_fs_mode_proto = {
+ .func = bpf_landlock_get_fs_mode,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_CONST_PTR_TO_LANDLOCK_ARG_FS,
+};
diff --git a/security/landlock/checker_fs.h b/security/landlock/checker_fs.h
new file mode 100644
index 000000000000..8bcdc9cba2b8
--- /dev/null
+++ b/security/landlock/checker_fs.h
@@ -0,0 +1,20 @@
+/*
+ * Landlock LSM - File System Checkers
+ *
+ * Copyright (C) 2016 Mickaël Salaün <mic@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _SECURITY_LANDLOCK_CHECKER_FS_H
+#define _SECURITY_LANDLOCK_CHECKER_FS_H
+
+#include <linux/fs.h>
+#include <linux/seccomp.h>
+
+extern const struct bpf_func_proto bpf_landlock_cmp_fs_beneath_proto;
+extern const struct bpf_func_proto bpf_landlock_get_fs_mode_proto;
+
+#endif /* _SECURITY_LANDLOCK_CHECKER_FS_H */
diff --git a/security/landlock/common.h b/security/landlock/common.h
index dd64e6391dd8..a30aa93dc1ae 100644
--- a/security/landlock/common.h
+++ b/security/landlock/common.h
@@ -15,6 +15,19 @@
#include <linux/fs.h> /* struct file, struct inode */
#include <linux/path.h> /* struct path */
+/**
+ * for_each_handle - iterate over all handles of an arraymap
+ *
+ * @i: index in the arraymap
+ * @handle: struct map_landlock_handle pointer
+ * @array: struct bpf_array pointer to walk through
+ */
+#define for_each_handle(i, handle, array) \
+ for (i = 0; i < atomic_read(&array->n_entries) && \
+ (handle = *((struct map_landlock_handle **) \
+ (array->value + array->elem_size * i)));\
+ i++)
+
enum landlock_argtype {
LANDLOCK_ARGTYPE_NONE,
LANDLOCK_ARGTYPE_FILE,
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index b3d154275be6..b3c107244df9 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -22,6 +22,7 @@
#include <linux/fs.h> /* struct inode */
#include <linux/path.h> /* struct path */
+#include "checker_fs.h"
#include "common.h"
#define MAP0(s, m, ...)
@@ -170,6 +171,11 @@ static const struct bpf_func_proto *bpf_landlock_func_proto(
enum bpf_func_id func_id, union bpf_prog_subtype *prog_subtype)
{
switch (func_id) {
+ case BPF_FUNC_landlock_get_fs_mode:
+ return &bpf_landlock_get_fs_mode_proto;
+ case BPF_FUNC_landlock_cmp_fs_beneath:
+ return &bpf_landlock_cmp_fs_beneath_proto;
+
default:
return NULL;
}
--
2.9.3
^ permalink raw reply related
* [RFC v4 07/18] landlock: Add LSM hooks
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
Add 8 file system-related hooks:
* file_open
* file_permission
* mmap_file
* inode_create
* inode_link
* inode_unlink
* inode_permission
* inode_getattr
This hook arguments are available to the Landlock rules in the eBPF
context as pointers. This pointers are an abstraction over the
underlying raw types. For now, the ARG_CONST_PTR_TO_LANDLOCK_ARG_FS type
is used for struct file, struct inode and struct path pointers.
Changes since v3:
* split commit
* add hooks dealing with struct inode and struct path pointers:
inode_permission and inode_getattr
* add abstraction over eBPF helper arguments thanks to wrapping structs
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Serge E. Hallyn <serge@hallyn.com>
---
include/linux/bpf.h | 2 +
include/linux/lsm_hooks.h | 5 ++
include/uapi/linux/bpf.h | 10 ++-
kernel/bpf/verifier.c | 6 ++
security/landlock/common.h | 18 +++++
security/landlock/lsm.c | 173 +++++++++++++++++++++++++++++++++++++++++++++
security/security.c | 1 +
7 files changed, 214 insertions(+), 1 deletion(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 2cca9fc8b72b..e7ce49642f50 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -88,6 +88,7 @@ enum bpf_arg_type {
ARG_ANYTHING, /* any (initialized) argument is ok */
ARG_CONST_PTR_TO_LANDLOCK_HANDLE_FS, /* pointer to Landlock FS map handle */
+ ARG_CONST_PTR_TO_LANDLOCK_ARG_FS, /* pointer to Landlock FS hook argument */
};
/* type of values returned from helper functions */
@@ -157,6 +158,7 @@ enum bpf_reg_type {
/* Landlock */
CONST_PTR_TO_LANDLOCK_HANDLE_FS,
+ CONST_PTR_TO_LANDLOCK_ARG_FS,
};
struct bpf_prog;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 558adfa5c8a8..069af34301d4 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1933,5 +1933,10 @@ void __init loadpin_add_hooks(void);
#else
static inline void loadpin_add_hooks(void) { };
#endif
+#ifdef CONFIG_SECURITY_LANDLOCK
+extern void __init landlock_add_hooks(void);
+#else
+static inline void __init landlock_add_hooks(void) { }
+#endif /* CONFIG_SECURITY_LANDLOCK */
#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 335616ab63ff..b6b531a868c0 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -563,8 +563,16 @@ struct xdp_md {
/* LSM hooks */
enum landlock_hook {
LANDLOCK_HOOK_UNSPEC,
+ LANDLOCK_HOOK_FILE_OPEN,
+ LANDLOCK_HOOK_FILE_PERMISSION,
+ LANDLOCK_HOOK_MMAP_FILE,
+ LANDLOCK_HOOK_INODE_CREATE,
+ LANDLOCK_HOOK_INODE_LINK,
+ LANDLOCK_HOOK_INODE_UNLINK,
+ LANDLOCK_HOOK_INODE_PERMISSION,
+ LANDLOCK_HOOK_INODE_GETATTR,
};
-#define _LANDLOCK_HOOK_LAST LANDLOCK_HOOK_UNSPEC
+#define _LANDLOCK_HOOK_LAST LANDLOCK_HOOK_INODE_GETATTR
/* eBPF context and functions allowed for a rule */
#define _LANDLOCK_SUBTYPE_ACCESS_MASK ((1ULL << 0) - 1)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 9b921a9afa3c..32b7941476ec 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -189,6 +189,7 @@ static const char * const reg_type_str[] = {
[PTR_TO_PACKET] = "pkt",
[PTR_TO_PACKET_END] = "pkt_end",
[CONST_PTR_TO_LANDLOCK_HANDLE_FS] = "landlock_handle_fs",
+ [CONST_PTR_TO_LANDLOCK_ARG_FS] = "landlock_arg_fs",
};
static void print_verifier_state(struct bpf_verifier_state *state)
@@ -515,6 +516,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
case FRAME_PTR:
case CONST_PTR_TO_MAP:
case CONST_PTR_TO_LANDLOCK_HANDLE_FS:
+ case CONST_PTR_TO_LANDLOCK_ARG_FS:
return true;
default:
return false;
@@ -980,6 +982,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
expected_type = CONST_PTR_TO_LANDLOCK_HANDLE_FS;
if (type != expected_type)
goto err_type;
+ } else if (arg_type == ARG_CONST_PTR_TO_LANDLOCK_ARG_FS) {
+ expected_type = CONST_PTR_TO_LANDLOCK_ARG_FS;
+ if (type != expected_type)
+ goto err_type;
} else if (arg_type == ARG_PTR_TO_STACK ||
arg_type == ARG_PTR_TO_RAW_STACK) {
expected_type = PTR_TO_STACK;
diff --git a/security/landlock/common.h b/security/landlock/common.h
index 0b5aad4a7aaa..dd64e6391dd8 100644
--- a/security/landlock/common.h
+++ b/security/landlock/common.h
@@ -12,6 +12,24 @@
#define _SECURITY_LANDLOCK_COMMON_H
#include <linux/bpf.h> /* enum landlock_hook */
+#include <linux/fs.h> /* struct file, struct inode */
+#include <linux/path.h> /* struct path */
+
+enum landlock_argtype {
+ LANDLOCK_ARGTYPE_NONE,
+ LANDLOCK_ARGTYPE_FILE,
+ LANDLOCK_ARGTYPE_INODE,
+ LANDLOCK_ARGTYPE_PATH,
+};
+
+struct landlock_arg_fs {
+ enum landlock_argtype type;
+ union {
+ struct file *file;
+ struct inode *inode;
+ const struct path *path;
+ };
+};
/**
* get_index - get an index for the rules of struct landlock_hooks
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index d7564540c493..b3d154275be6 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -15,9 +15,99 @@
#include <linux/kernel.h> /* FIELD_SIZEOF() */
#include <linux/landlock.h>
#include <linux/lsm_hooks.h>
+#include <linux/types.h> /* uintptr_t */
+
+/* hook arguments */
+#include <linux/dcache.h> /* struct dentry */
+#include <linux/fs.h> /* struct inode */
+#include <linux/path.h> /* struct path */
#include "common.h"
+#define MAP0(s, m, ...)
+#define MAP1(s, m, d, t, a) m(d, t, a)
+#define MAP2(s, m, d, t, a, ...) m(d, t, a) s() MAP1(s, m, __VA_ARGS__)
+#define MAP3(s, m, d, t, a, ...) m(d, t, a) s() MAP2(s, m, __VA_ARGS__)
+#define MAP4(s, m, d, t, a, ...) m(d, t, a) s() MAP3(s, m, __VA_ARGS__)
+#define MAP5(s, m, d, t, a, ...) m(d, t, a) s() MAP4(s, m, __VA_ARGS__)
+#define MAP6(s, m, d, t, a, ...) m(d, t, a) s() MAP5(s, m, __VA_ARGS__)
+
+/* separators */
+#define SEP_COMMA() ,
+#define SEP_NONE()
+
+/* arguments */
+#define ARG_MAP(n, ...) MAP##n(SEP_COMMA, __VA_ARGS__)
+#define ARG_REGTYPE(d, t, a) d##_REGTYPE
+#define ARG_TA(d, t, a) t a
+#define ARG_GET(d, t, a) ((u64) d##_GET(a))
+
+/* declarations */
+#define DEC_MAP(n, ...) MAP##n(SEP_NONE, DEC, __VA_ARGS__)
+#define DEC(d, t, a) d##_DEC(a)
+
+#define LANDLOCK_HOOKx(X, NAME, CNAME, ...) \
+ static inline int landlock_hook_##NAME( \
+ ARG_MAP(X, ARG_TA, __VA_ARGS__)) \
+ { \
+ DEC_MAP(X, __VA_ARGS__) \
+ __u64 args[6] = { \
+ ARG_MAP(X, ARG_GET, __VA_ARGS__) \
+ }; \
+ return landlock_enforce(LANDLOCK_HOOK_##CNAME, args); \
+ } \
+ static inline bool __is_valid_access_hook_##CNAME( \
+ int off, int size, enum bpf_access_type type, \
+ enum bpf_reg_type *reg_type, \
+ union bpf_prog_subtype *prog_subtype) \
+ { \
+ enum bpf_reg_type arg_types[6] = { \
+ ARG_MAP(X, ARG_REGTYPE, __VA_ARGS__) \
+ }; \
+ return __is_valid_access(off, size, type, reg_type, \
+ arg_types, prog_subtype); \
+ } \
+
+#define LANDLOCK_HOOK1(NAME, ...) LANDLOCK_HOOKx(1, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK2(NAME, ...) LANDLOCK_HOOKx(2, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK3(NAME, ...) LANDLOCK_HOOKx(3, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK4(NAME, ...) LANDLOCK_HOOKx(4, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK5(NAME, ...) LANDLOCK_HOOKx(5, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK6(NAME, ...) LANDLOCK_HOOKx(6, NAME, __VA_ARGS__)
+
+#define LANDLOCK_HOOK_INIT(NAME) LSM_HOOK_INIT(NAME, landlock_hook_##NAME)
+
+/* LANDLOCK_WRAPARG_NONE */
+#define LANDLOCK_WRAPARG_NONE_REGTYPE NOT_INIT
+#define LANDLOCK_WRAPARG_NONE_DEC(arg)
+#define LANDLOCK_WRAPARG_NONE_GET(arg) 0
+
+/* LANDLOCK_WRAPARG_RAW */
+#define LANDLOCK_WRAPARG_RAW_REGTYPE UNKNOWN_VALUE
+#define LANDLOCK_WRAPARG_RAW_DEC(arg)
+#define LANDLOCK_WRAPARG_RAW_GET(arg) arg
+
+/* LANDLOCK_WRAPARG_FILE */
+#define LANDLOCK_WRAPARG_FILE_REGTYPE CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_FILE_DEC(arg) \
+ const struct landlock_arg_fs wrap_##arg = \
+ { .type = LANDLOCK_ARGTYPE_FILE, .file = arg };
+#define LANDLOCK_WRAPARG_FILE_GET(arg) (uintptr_t)&wrap_##arg
+
+/* LANDLOCK_WRAPARG_INODE */
+#define LANDLOCK_WRAPARG_INODE_REGTYPE CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_INODE_DEC(arg) \
+ const struct landlock_arg_fs wrap_##arg = \
+ { .type = LANDLOCK_ARGTYPE_INODE, .inode = arg };
+#define LANDLOCK_WRAPARG_INODE_GET(arg) (uintptr_t)&wrap_##arg
+
+/* LANDLOCK_WRAPARG_PATH */
+#define LANDLOCK_WRAPARG_PATH_REGTYPE CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_PATH_DEC(arg) \
+ const struct landlock_arg_fs wrap_##arg = \
+ { .type = LANDLOCK_ARGTYPE_PATH, .path = arg };
+#define LANDLOCK_WRAPARG_PATH_GET(arg) (uintptr_t)&wrap_##arg
+
/**
* landlock_run_prog - run Landlock program for a syscall
*
@@ -127,6 +217,72 @@ static bool __is_valid_access(int off, int size, enum bpf_access_type type,
return true;
}
+LANDLOCK_HOOK2(file_open, FILE_OPEN,
+ LANDLOCK_WRAPARG_FILE, struct file *, file,
+ LANDLOCK_WRAPARG_NONE, const struct cred *, cred
+)
+
+LANDLOCK_HOOK2(file_permission, FILE_PERMISSION,
+ LANDLOCK_WRAPARG_FILE, struct file *, file,
+ LANDLOCK_WRAPARG_RAW, int, mask
+)
+
+LANDLOCK_HOOK4(mmap_file, MMAP_FILE,
+ LANDLOCK_WRAPARG_FILE, struct file *, file,
+ LANDLOCK_WRAPARG_RAW, unsigned long, reqprot,
+ LANDLOCK_WRAPARG_RAW, unsigned long, prot,
+ LANDLOCK_WRAPARG_RAW, unsigned long, flags
+)
+
+/* a directory inode contains only one dentry */
+LANDLOCK_HOOK3(inode_create, INODE_CREATE,
+ LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+ LANDLOCK_WRAPARG_NONE, struct dentry *, dentry,
+ LANDLOCK_WRAPARG_RAW, umode_t, mode
+)
+
+LANDLOCK_HOOK3(inode_link, INODE_LINK,
+ LANDLOCK_WRAPARG_NONE, struct dentry *, old_dentry,
+ LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+ LANDLOCK_WRAPARG_NONE, struct dentry *, new_dentry
+)
+
+LANDLOCK_HOOK2(inode_unlink, INODE_UNLINK,
+ LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+ LANDLOCK_WRAPARG_NONE, struct dentry *, dentry
+)
+
+LANDLOCK_HOOK2(inode_permission, INODE_PERMISSION,
+ LANDLOCK_WRAPARG_INODE, struct inode *, inode,
+ LANDLOCK_WRAPARG_RAW, int, mask
+)
+
+LANDLOCK_HOOK1(inode_getattr, INODE_GETATTR,
+ LANDLOCK_WRAPARG_PATH, const struct path *, path
+)
+
+static struct security_hook_list landlock_hooks[] = {
+ LANDLOCK_HOOK_INIT(file_open),
+ LANDLOCK_HOOK_INIT(file_permission),
+ LANDLOCK_HOOK_INIT(mmap_file),
+ LANDLOCK_HOOK_INIT(inode_create),
+ LANDLOCK_HOOK_INIT(inode_link),
+ LANDLOCK_HOOK_INIT(inode_unlink),
+ LANDLOCK_HOOK_INIT(inode_permission),
+ LANDLOCK_HOOK_INIT(inode_getattr),
+};
+
+void __init landlock_add_hooks(void)
+{
+ pr_info("landlock: Becoming ready to sandbox with seccomp\n");
+ security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks));
+}
+
+#define LANDLOCK_CASE_ACCESS_HOOK(CNAME) \
+ case LANDLOCK_HOOK_##CNAME: \
+ return __is_valid_access_hook_##CNAME( \
+ off, size, type, reg_type, prog_subtype);
+
static inline bool bpf_landlock_is_valid_access(int off, int size,
enum bpf_access_type type, enum bpf_reg_type *reg_type,
union bpf_prog_subtype *prog_subtype)
@@ -134,6 +290,14 @@ static inline bool bpf_landlock_is_valid_access(int off, int size,
enum landlock_hook hook = prog_subtype->landlock_rule.hook;
switch (hook) {
+ LANDLOCK_CASE_ACCESS_HOOK(FILE_OPEN)
+ LANDLOCK_CASE_ACCESS_HOOK(FILE_PERMISSION)
+ LANDLOCK_CASE_ACCESS_HOOK(MMAP_FILE)
+ LANDLOCK_CASE_ACCESS_HOOK(INODE_CREATE)
+ LANDLOCK_CASE_ACCESS_HOOK(INODE_LINK)
+ LANDLOCK_CASE_ACCESS_HOOK(INODE_UNLINK)
+ LANDLOCK_CASE_ACCESS_HOOK(INODE_PERMISSION)
+ LANDLOCK_CASE_ACCESS_HOOK(INODE_GETATTR)
case LANDLOCK_HOOK_UNSPEC:
default:
return false;
@@ -146,6 +310,15 @@ static inline bool bpf_landlock_is_valid_subtype(
enum landlock_hook hook = prog_subtype->landlock_rule.hook;
switch (hook) {
+ case LANDLOCK_HOOK_FILE_OPEN:
+ case LANDLOCK_HOOK_FILE_PERMISSION:
+ case LANDLOCK_HOOK_MMAP_FILE:
+ case LANDLOCK_HOOK_INODE_CREATE:
+ case LANDLOCK_HOOK_INODE_LINK:
+ case LANDLOCK_HOOK_INODE_UNLINK:
+ case LANDLOCK_HOOK_INODE_PERMISSION:
+ case LANDLOCK_HOOK_INODE_GETATTR:
+ break;
case LANDLOCK_HOOK_UNSPEC:
default:
return false;
diff --git a/security/security.c b/security/security.c
index f825304f04a7..92f0f1f209b6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -61,6 +61,7 @@ int __init security_init(void)
capability_add_hooks();
yama_add_hooks();
loadpin_add_hooks();
+ landlock_add_hooks();
/*
* Load all the remaining security modules.
--
2.9.3
^ permalink raw reply related
* [RFC v4 06/18] fs: Constify path_is_under()'s arguments
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry,
kernel-hardening-ZwoEplunGu1jrUoiu81ncdBPR1lH4CV8,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, cgroups
In-Reply-To: <20161026065654.19166-1-mic-WFhQfpSGs3bR7s880joybQ@public.gmane.org>
Signed-off-by: Mickaël Salaün <mic-WFhQfpSGs3bR7s880joybQ@public.gmane.org>
Cc: Alexander Viro <viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn@public.gmane.org>
---
fs/namespace.c | 2 +-
include/linux/fs.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index e6c234b1a645..4d80a5066a1f 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2997,7 +2997,7 @@ bool is_path_reachable(struct mount *mnt, struct dentry *dentry,
return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry);
}
-bool path_is_under(struct path *path1, struct path *path2)
+bool path_is_under(const struct path *path1, const struct path *path2)
{
bool res;
read_seqlock_excl(&mount_lock);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 16d2b6e874d6..abbaf162f70e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2709,7 +2709,7 @@ extern struct file * open_exec(const char *);
/* fs/dcache.c -- generic fs support functions */
extern bool is_subdir(struct dentry *, struct dentry *);
-extern bool path_is_under(struct path *, struct path *);
+extern bool path_is_under(const struct path *, const struct path *);
extern char *file_path(struct file *, char *, int);
--
2.9.3
^ permalink raw reply related
* [RFC v4 05/18] bpf,landlock: Define an eBPF program type for Landlock
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
Add a new type of eBPF program used by Landlock rules and the functions
to verify and evaluate them.
Changes since v3:
* split commit
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Serge E. Hallyn <serge@hallyn.com>
---
include/linux/landlock.h | 76 +++++++++++++++++++
include/uapi/linux/bpf.h | 20 +++++
kernel/bpf/syscall.c | 10 ++-
security/Makefile | 2 +
security/landlock/Makefile | 3 +
security/landlock/common.h | 27 +++++++
security/landlock/lsm.c | 181 +++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 317 insertions(+), 2 deletions(-)
create mode 100644 include/linux/landlock.h
create mode 100644 security/landlock/Makefile
create mode 100644 security/landlock/common.h
create mode 100644 security/landlock/lsm.c
diff --git a/include/linux/landlock.h b/include/linux/landlock.h
new file mode 100644
index 000000000000..2ab2be8e3e6e
--- /dev/null
+++ b/include/linux/landlock.h
@@ -0,0 +1,76 @@
+/*
+ * Landlock LSM - Public headers
+ *
+ * Copyright (C) 2016 Mickaël Salaün <mic@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_LANDLOCK_H
+#define _LINUX_LANDLOCK_H
+#ifdef CONFIG_SECURITY_LANDLOCK
+
+#include <linux/bpf.h> /* _LANDLOCK_HOOK_LAST */
+#include <linux/types.h> /* atomic_t */
+
+#ifdef CONFIG_SECCOMP_FILTER
+#include <linux/seccomp.h> /* struct seccomp_filter */
+#endif /* CONFIG_SECCOMP_FILTER */
+
+struct landlock_rule;
+
+/**
+ * struct landlock_node - node in the rule hierarchy
+ *
+ * This is created when a task insert its first rule in the Landlock rule
+ * hierarchy. The set of Landlock rules referenced by this node is then
+ * enforced for all the task that inherit this node. However, if a task is
+ * cloned before inserting new rules, it doesn't get a dedicated node and its
+ * children will not inherit this new rules.
+ *
+ * @usage: reference count to manage the node lifetime.
+ * @rule: list of Landlock rules managed by this node.
+ * @prev: reference the parent node.
+ * @owner: reference the address of the node in the struct landlock_hooks. This
+ * is needed to know if we need to append a rule to the current node or
+ * create a new node.
+ */
+struct landlock_node {
+ atomic_t usage;
+ struct landlock_rule *rule;
+ struct landlock_node *prev;
+ struct landlock_node **owner;
+};
+
+struct landlock_rule {
+ atomic_t usage;
+ struct landlock_rule *prev;
+ struct bpf_prog *prog;
+};
+
+/**
+ * struct landlock_hooks - Landlock hook programs enforced on a thread
+ *
+ * This is used for low performance impact when forking a process. Instead of
+ * copying the full array and incrementing the usage field of each entries,
+ * only create a pointer to struct landlock_hooks and increment the usage
+ * field.
+ *
+ * A new struct landlock_hooks must be created thanks to a call to
+ * new_landlock_hooks().
+ *
+ * @usage: reference count to manage the object lifetime. When a thread need to
+ * add Landlock programs and if @usage is greater than 1, then the
+ * thread must duplicate struct landlock_hooks to not change the
+ * children' rules as well. FIXME
+ * @nodes: array of non-NULL struct landlock_node pointers.
+ */
+struct landlock_hooks {
+ atomic_t usage;
+ struct landlock_node *nodes[_LANDLOCK_HOOK_LAST];
+};
+
+#endif /* CONFIG_SECURITY_LANDLOCK */
+#endif /* _LINUX_LANDLOCK_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 06621c401bc0..335616ab63ff 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -111,6 +111,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_XDP,
BPF_PROG_TYPE_PERF_EVENT,
BPF_PROG_TYPE_CGROUP_SKB,
+ BPF_PROG_TYPE_LANDLOCK,
};
enum bpf_attach_type {
@@ -559,6 +560,12 @@ struct xdp_md {
__u32 data_end;
};
+/* LSM hooks */
+enum landlock_hook {
+ LANDLOCK_HOOK_UNSPEC,
+};
+#define _LANDLOCK_HOOK_LAST LANDLOCK_HOOK_UNSPEC
+
/* eBPF context and functions allowed for a rule */
#define _LANDLOCK_SUBTYPE_ACCESS_MASK ((1ULL << 0) - 1)
@@ -577,4 +584,17 @@ struct landlock_handle {
};
} __attribute__((aligned(8)));
+/**
+ * struct landlock_data
+ *
+ * @hook: LSM hook ID (e.g. BPF_PROG_TYPE_LANDLOCK_FILE_OPEN)
+ * @args: LSM hook arguments, see include/linux/lsm_hooks.h for there
+ * description and the LANDLOCK_HOOK* definitions from
+ * security/landlock/lsm.c for their types.
+ */
+struct landlock_data {
+ __u32 hook; /* enum landlock_hook */
+ __u64 args[6];
+};
+
#endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6eef1da1e8a3..0f7faa9d2262 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -739,8 +739,14 @@ static int bpf_prog_load(union bpf_attr *attr)
attr->kern_version != LINUX_VERSION_CODE)
return -EINVAL;
- if (type != BPF_PROG_TYPE_SOCKET_FILTER && !capable(CAP_SYS_ADMIN))
- return -EPERM;
+ switch (type) {
+ case BPF_PROG_TYPE_SOCKET_FILTER:
+ case BPF_PROG_TYPE_LANDLOCK:
+ break;
+ default:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ }
/* plain bpf_prog allocation */
prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
diff --git a/security/Makefile b/security/Makefile
index f2d71cdb8e19..3fdc2f19dc48 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -9,6 +9,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
subdir-$(CONFIG_SECURITY_YAMA) += yama
subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin
+subdir-$(CONFIG_SECURITY_LANDLOCK) += landlock
# always enable default capabilities
obj-y += commoncap.o
@@ -24,6 +25,7 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/
obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/
obj-$(CONFIG_SECURITY_YAMA) += yama/
obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/
+obj-$(CONFIG_SECURITY_LANDLOCK) += landlock/
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
diff --git a/security/landlock/Makefile b/security/landlock/Makefile
new file mode 100644
index 000000000000..59669d70bc7e
--- /dev/null
+++ b/security/landlock/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o
+
+landlock-y := lsm.o
diff --git a/security/landlock/common.h b/security/landlock/common.h
new file mode 100644
index 000000000000..0b5aad4a7aaa
--- /dev/null
+++ b/security/landlock/common.h
@@ -0,0 +1,27 @@
+/*
+ * Landlock LSM - private headers
+ *
+ * Copyright (C) 2016 Mickaël Salaün <mic@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _SECURITY_LANDLOCK_COMMON_H
+#define _SECURITY_LANDLOCK_COMMON_H
+
+#include <linux/bpf.h> /* enum landlock_hook */
+
+/**
+ * get_index - get an index for the rules of struct landlock_hooks
+ *
+ * @hook: a Landlock hook ID
+ */
+static inline int get_index(enum landlock_hook hook)
+{
+ /* hook ID > 0 for loaded programs */
+ return hook - 1;
+}
+
+#endif /* _SECURITY_LANDLOCK_COMMON_H */
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
new file mode 100644
index 000000000000..d7564540c493
--- /dev/null
+++ b/security/landlock/lsm.c
@@ -0,0 +1,181 @@
+/*
+ * Landlock LSM
+ *
+ * Copyright (C) 2016 Mickaël Salaün <mic@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bpf.h> /* enum bpf_reg_type, struct landlock_data */
+#include <linux/cred.h>
+#include <linux/err.h> /* MAX_ERRNO */
+#include <linux/filter.h> /* struct bpf_prog, BPF_PROG_RUN() */
+#include <linux/kernel.h> /* FIELD_SIZEOF() */
+#include <linux/landlock.h>
+#include <linux/lsm_hooks.h>
+
+#include "common.h"
+
+/**
+ * landlock_run_prog - run Landlock program for a syscall
+ *
+ * @hook_idx: hook index in the rules array
+ * @ctx: non-NULL eBPF context
+ * @hooks: Landlock hooks pointer
+ */
+static u32 landlock_run_prog(u32 hook_idx, const struct landlock_data *ctx,
+ struct landlock_hooks *hooks)
+{
+ struct landlock_node *node;
+ u32 ret = 0;
+
+ if (!hooks)
+ return 0;
+
+ for (node = hooks->nodes[hook_idx]; node; node = node->prev) {
+ struct landlock_rule *rule;
+
+ for (rule = node->rule; rule; rule = rule->prev) {
+ if (WARN_ON(!rule->prog))
+ continue;
+ rcu_read_lock();
+ ret = BPF_PROG_RUN(rule->prog, (void *)ctx);
+ rcu_read_unlock();
+ if (ret) {
+ if (ret > MAX_ERRNO)
+ ret = MAX_ERRNO;
+ goto out;
+ }
+ }
+ }
+
+out:
+ return ret;
+}
+
+static int landlock_enforce(enum landlock_hook hook, __u64 args[6])
+{
+ u32 ret = 0;
+ u32 hook_idx = get_index(hook);
+
+ struct landlock_data ctx = {
+ .hook = hook,
+ .args[0] = args[0],
+ .args[1] = args[1],
+ .args[2] = args[2],
+ .args[3] = args[3],
+ .args[4] = args[4],
+ .args[5] = args[5],
+ };
+
+ /* placeholder for seccomp and cgroup managers */
+ ret = landlock_run_prog(hook_idx, &ctx, NULL);
+
+ return -ret;
+}
+
+static const struct bpf_func_proto *bpf_landlock_func_proto(
+ enum bpf_func_id func_id, union bpf_prog_subtype *prog_subtype)
+{
+ switch (func_id) {
+ default:
+ return NULL;
+ }
+}
+
+static bool __is_valid_access(int off, int size, enum bpf_access_type type,
+ enum bpf_reg_type *reg_type,
+ enum bpf_reg_type arg_types[6],
+ union bpf_prog_subtype *prog_subtype)
+{
+ int arg_nb, expected_size;
+
+ if (type != BPF_READ)
+ return false;
+ if (off < 0 || off >= sizeof(struct landlock_data))
+ return false;
+
+ /* check size */
+ switch (off) {
+ case offsetof(struct landlock_data, hook):
+ expected_size = sizeof(__u32);
+ break;
+ case offsetof(struct landlock_data, args[0]) ...
+ offsetof(struct landlock_data, args[5]):
+ expected_size = sizeof(__u64);
+ break;
+ default:
+ return false;
+ }
+ if (expected_size != size)
+ return false;
+
+ /* check pointer access and set pointer type */
+ switch (off) {
+ case offsetof(struct landlock_data, args[0]) ...
+ offsetof(struct landlock_data, args[5]):
+ arg_nb = (off - offsetof(struct landlock_data, args[0]))
+ / FIELD_SIZEOF(struct landlock_data, args[0]);
+ *reg_type = arg_types[arg_nb];
+ if (*reg_type == NOT_INIT)
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+static inline bool bpf_landlock_is_valid_access(int off, int size,
+ enum bpf_access_type type, enum bpf_reg_type *reg_type,
+ union bpf_prog_subtype *prog_subtype)
+{
+ enum landlock_hook hook = prog_subtype->landlock_rule.hook;
+
+ switch (hook) {
+ case LANDLOCK_HOOK_UNSPEC:
+ default:
+ return false;
+ }
+}
+
+static inline bool bpf_landlock_is_valid_subtype(
+ union bpf_prog_subtype *prog_subtype)
+{
+ enum landlock_hook hook = prog_subtype->landlock_rule.hook;
+
+ switch (hook) {
+ case LANDLOCK_HOOK_UNSPEC:
+ default:
+ return false;
+ }
+ if (!prog_subtype->landlock_rule.hook ||
+ prog_subtype->landlock_rule.hook > _LANDLOCK_HOOK_LAST)
+ return false;
+ if (prog_subtype->landlock_rule.access & ~_LANDLOCK_SUBTYPE_ACCESS_MASK)
+ return false;
+ if (prog_subtype->landlock_rule.option & ~_LANDLOCK_SUBTYPE_OPTION_MASK)
+ return false;
+
+ return true;
+}
+
+static const struct bpf_verifier_ops bpf_landlock_ops = {
+ .get_func_proto = bpf_landlock_func_proto,
+ .is_valid_access = bpf_landlock_is_valid_access,
+ .is_valid_subtype = bpf_landlock_is_valid_subtype,
+};
+
+static struct bpf_prog_type_list bpf_landlock_type __read_mostly = {
+ .ops = &bpf_landlock_ops,
+ .type = BPF_PROG_TYPE_LANDLOCK,
+};
+
+static int __init register_landlock_filter_ops(void)
+{
+ bpf_register_prog_type(&bpf_landlock_type);
+ return 0;
+}
+
+late_initcall(register_landlock_filter_ops);
--
2.9.3
^ permalink raw reply related
* [RFC v4 04/18] bpf,landlock: Add eBPF program subtype and is_valid_subtype() verifier
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
The program subtype's goal is to be able to have different static
fine-grained verifications for a unique program type.
The struct bpf_verifier_ops gets a new optional function:
is_valid_subtype(). This new verifier is called at the begening of the
eBPF program verification to check if the (optional) program subtype is
valid.
For now, only Landlock eBPF programs are using a program subtype but
this could be used by other program types in the future.
Cf. the next commit to see how the subtype is used by Landlock LSM.
Changes since v3:
* remove the "origin" field
* add an "option" field
* cleanup comments
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Link: https://lkml.kernel.org/r/20160827205559.GA43880@ast-mbp.thefacebook.com
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
---
include/linux/bpf.h | 7 +++++--
include/linux/filter.h | 1 +
include/uapi/linux/bpf.h | 18 ++++++++++++++++++
kernel/bpf/syscall.c | 5 +++--
kernel/bpf/verifier.c | 9 +++++++--
kernel/trace/bpf_trace.c | 12 ++++++++----
net/core/filter.c | 26 ++++++++++++++++----------
7 files changed, 58 insertions(+), 20 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 34b9e9cd1af7..2cca9fc8b72b 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -163,18 +163,21 @@ struct bpf_prog;
struct bpf_verifier_ops {
/* return eBPF function prototype for verification */
- const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id func_id);
+ const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id func_id,
+ union bpf_prog_subtype *prog_subtype);
/* return true if 'size' wide access at offset 'off' within bpf_context
* with 'type' (read or write) is allowed
*/
bool (*is_valid_access)(int off, int size, enum bpf_access_type type,
- enum bpf_reg_type *reg_type);
+ enum bpf_reg_type *reg_type,
+ union bpf_prog_subtype *prog_subtype);
int (*gen_prologue)(struct bpf_insn *insn, bool direct_write,
const struct bpf_prog *prog);
u32 (*convert_ctx_access)(enum bpf_access_type type, int dst_reg,
int src_reg, int ctx_off,
struct bpf_insn *insn, struct bpf_prog *prog);
+ bool (*is_valid_subtype)(union bpf_prog_subtype *prog_subtype);
};
struct bpf_prog_type_list {
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 1f09c521adfe..88470cdd3ee1 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -406,6 +406,7 @@ struct bpf_prog {
kmemcheck_bitfield_end(meta);
u32 len; /* Number of filter blocks */
enum bpf_prog_type type; /* Type of BPF program */
+ union bpf_prog_subtype subtype; /* For fine-grained verifications */
struct bpf_prog_aux *aux; /* Auxiliary fields */
struct sock_fprog_kern *orig_prog; /* Original BPF program */
unsigned int (*bpf_func)(const struct sk_buff *skb,
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 339a9307ba6e..06621c401bc0 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -130,6 +130,14 @@ enum bpf_attach_type {
#define BPF_F_NO_PREALLOC (1U << 0)
+union bpf_prog_subtype {
+ struct {
+ __u32 hook; /* enum landlock_hook */
+ __aligned_u64 access; /* LANDLOCK_SUBTYPE_ACCESS_* */
+ __aligned_u64 option; /* LANDLOCK_SUBTYPE_OPTION_* */
+ } landlock_rule;
+} __attribute__((aligned(8)));
+
union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32 map_type; /* one of enum bpf_map_type */
@@ -158,6 +166,7 @@ union bpf_attr {
__u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */
+ union bpf_prog_subtype prog_subtype;
};
struct { /* anonymous struct used by BPF_OBJ_* commands */
@@ -550,6 +559,15 @@ struct xdp_md {
__u32 data_end;
};
+/* eBPF context and functions allowed for a rule */
+#define _LANDLOCK_SUBTYPE_ACCESS_MASK ((1ULL << 0) - 1)
+
+/*
+ * (future) options for a Landlock rule (e.g. run even if a previous rule
+ * returned an errno code)
+ */
+#define _LANDLOCK_SUBTYPE_OPTION_MASK ((1ULL << 0) - 1)
+
/* Map handle entry */
struct landlock_handle {
__u32 type; /* enum bpf_map_handle_type */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 13149c9cb3a4..6eef1da1e8a3 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -572,7 +572,7 @@ static void fixup_bpf_calls(struct bpf_prog *prog)
continue;
}
- fn = prog->aux->ops->get_func_proto(insn->imm);
+ fn = prog->aux->ops->get_func_proto(insn->imm, &prog->subtype);
/* all functions that have prototype and verifier allowed
* programs to call them, must be real in-kernel functions
*/
@@ -710,7 +710,7 @@ struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
EXPORT_SYMBOL_GPL(bpf_prog_get_type);
/* last field in 'union bpf_attr' used by this command */
-#define BPF_PROG_LOAD_LAST_FIELD kern_version
+#define BPF_PROG_LOAD_LAST_FIELD prog_subtype
static int bpf_prog_load(union bpf_attr *attr)
{
@@ -768,6 +768,7 @@ static int bpf_prog_load(union bpf_attr *attr)
err = find_prog_type(type, prog);
if (err < 0)
goto free_prog;
+ prog->subtype = attr->prog_subtype;
/* run eBPF verifier */
err = bpf_check(&prog, attr);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 1bc7701466b0..9b921a9afa3c 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -655,7 +655,8 @@ static int check_ctx_access(struct bpf_verifier_env *env, int off, int size,
return 0;
if (env->prog->aux->ops->is_valid_access &&
- env->prog->aux->ops->is_valid_access(off, size, t, reg_type)) {
+ env->prog->aux->ops->is_valid_access(off, size, t, reg_type,
+ &env->prog->subtype)) {
/* remember the offset of last byte accessed in ctx */
if (env->prog->aux->max_ctx_offset < off + size)
env->prog->aux->max_ctx_offset = off + size;
@@ -1181,7 +1182,7 @@ static int check_call(struct bpf_verifier_env *env, int func_id)
}
if (env->prog->aux->ops->get_func_proto)
- fn = env->prog->aux->ops->get_func_proto(func_id);
+ fn = env->prog->aux->ops->get_func_proto(func_id, &env->prog->subtype);
if (!fn) {
verbose("unknown func %d\n", func_id);
@@ -3065,6 +3066,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
if ((*prog)->len <= 0 || (*prog)->len > BPF_MAXINSNS)
return -E2BIG;
+ if ((*prog)->aux->ops->is_valid_subtype &&
+ !(*prog)->aux->ops->is_valid_subtype(&(*prog)->subtype))
+ return -EINVAL;
+
/* 'struct bpf_verifier_env' can be global, but since it's not small,
* allocate/free it every time bpf_check() is called
*/
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 5dcb99281259..51cf0f254bf2 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -435,7 +435,8 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
}
}
-static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func_id)
+static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func_id,
+ union bpf_prog_subtype *prog_subtype)
{
switch (func_id) {
case BPF_FUNC_perf_event_output:
@@ -449,7 +450,8 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func
/* bpf+kprobe programs can access fields of 'struct pt_regs' */
static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
- enum bpf_reg_type *reg_type)
+ enum bpf_reg_type *reg_type,
+ union bpf_prog_subtype *prog_subtype)
{
if (off < 0 || off >= sizeof(struct pt_regs))
return false;
@@ -517,7 +519,8 @@ static const struct bpf_func_proto bpf_get_stackid_proto_tp = {
.arg3_type = ARG_ANYTHING,
};
-static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
+static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id,
+ union bpf_prog_subtype *prog_subtype)
{
switch (func_id) {
case BPF_FUNC_perf_event_output:
@@ -530,7 +533,8 @@ static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
}
static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type,
- enum bpf_reg_type *reg_type)
+ enum bpf_reg_type *reg_type,
+ union bpf_prog_subtype *prog_subtype)
{
if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE)
return false;
diff --git a/net/core/filter.c b/net/core/filter.c
index bd6eebeed5c6..a39f5956f31a 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2483,7 +2483,8 @@ static const struct bpf_func_proto bpf_xdp_event_output_proto = {
};
static const struct bpf_func_proto *
-sk_filter_func_proto(enum bpf_func_id func_id)
+sk_filter_func_proto(enum bpf_func_id func_id,
+ union bpf_prog_subtype *prog_subtype)
{
switch (func_id) {
case BPF_FUNC_map_lookup_elem:
@@ -2509,7 +2510,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)
}
static const struct bpf_func_proto *
-tc_cls_act_func_proto(enum bpf_func_id func_id)
+tc_cls_act_func_proto(enum bpf_func_id func_id,
+ union bpf_prog_subtype *prog_subtype)
{
switch (func_id) {
case BPF_FUNC_skb_store_bytes:
@@ -2563,12 +2565,12 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
case BPF_FUNC_skb_under_cgroup:
return &bpf_skb_under_cgroup_proto;
default:
- return sk_filter_func_proto(func_id);
+ return sk_filter_func_proto(func_id, prog_subtype);
}
}
static const struct bpf_func_proto *
-xdp_func_proto(enum bpf_func_id func_id)
+xdp_func_proto(enum bpf_func_id func_id, union bpf_prog_subtype *prog_subtype)
{
switch (func_id) {
case BPF_FUNC_perf_event_output:
@@ -2576,18 +2578,19 @@ xdp_func_proto(enum bpf_func_id func_id)
case BPF_FUNC_get_smp_processor_id:
return &bpf_get_smp_processor_id_proto;
default:
- return sk_filter_func_proto(func_id);
+ return sk_filter_func_proto(func_id, prog_subtype);
}
}
static const struct bpf_func_proto *
-cg_skb_func_proto(enum bpf_func_id func_id)
+cg_skb_func_proto(enum bpf_func_id func_id,
+ union bpf_prog_subtype *prog_subtype)
{
switch (func_id) {
case BPF_FUNC_skb_load_bytes:
return &bpf_skb_load_bytes_proto;
default:
- return sk_filter_func_proto(func_id);
+ return sk_filter_func_proto(func_id, prog_subtype);
}
}
@@ -2606,7 +2609,8 @@ static bool __is_valid_access(int off, int size, enum bpf_access_type type)
static bool sk_filter_is_valid_access(int off, int size,
enum bpf_access_type type,
- enum bpf_reg_type *reg_type)
+ enum bpf_reg_type *reg_type,
+ union bpf_prog_subtype *prog_subtype)
{
switch (off) {
case offsetof(struct __sk_buff, tc_classid):
@@ -2669,7 +2673,8 @@ static int tc_cls_act_prologue(struct bpf_insn *insn_buf, bool direct_write,
static bool tc_cls_act_is_valid_access(int off, int size,
enum bpf_access_type type,
- enum bpf_reg_type *reg_type)
+ enum bpf_reg_type *reg_type,
+ union bpf_prog_subtype *prog_subtype)
{
if (type == BPF_WRITE) {
switch (off) {
@@ -2712,7 +2717,8 @@ static bool __is_valid_xdp_access(int off, int size,
static bool xdp_is_valid_access(int off, int size,
enum bpf_access_type type,
- enum bpf_reg_type *reg_type)
+ enum bpf_reg_type *reg_type,
+ union bpf_prog_subtype *prog_subtype)
{
if (type == BPF_WRITE)
return false;
--
2.9.3
^ permalink raw reply related
* [RFC v4 03/18] bpf,landlock: Add a new arraymap type to deal with (Landlock) handles
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
This new arraymap looks like a set and brings new properties:
* strong typing of entries: the eBPF functions get the array type of
elements instead of CONST_PTR_TO_MAP (e.g.
CONST_PTR_TO_LANDLOCK_HANDLE_FS);
* force sequential filling (i.e. replace or append-only update), which
allow quick browsing of all entries.
This strong typing is useful to statically check if the content of a map
can be passed to an eBPF function. For example, Landlock use it to store
and manage kernel objects (e.g. struct file) instead of dealing with
userland raw data. This improve efficiency and ensure that an eBPF
program can only call functions with the right high-level arguments.
The enum bpf_map_handle_type list low-level types (e.g.
BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD) which are identified when
updating a map entry (handle). This handle types are used to infer a
high-level arraymap type which are listed in enum bpf_map_array_type
(e.g. BPF_MAP_ARRAY_TYPE_LANDLOCK_FS).
For now, this new arraymap is only used by Landlock LSM (cf. next
commits) but it could be useful for other needs.
Changes since v3:
* make handle arraymap safe (RCU) and remove buggy synchronize_rcu()
* factor out the arraymay walk
Changes since v2:
* add a RLIMIT_NOFILE-based limit to the maximum number of arraymap
handle entries (suggested by Andy Lutomirski)
* remove useless checks
Changes since v1:
* arraymap of handles replace custom checker groups
* simpler userland API
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: Kees Cook <keescook@chromium.org>
Link: https://lkml.kernel.org/r/CALCETrWwTiz3kZTkEgOW24-DvhQq6LftwEXh77FD2G5o71yD7g@mail.gmail.com
---
include/linux/bpf.h | 24 +++++
include/uapi/linux/bpf.h | 21 ++++
kernel/bpf/arraymap.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++
kernel/bpf/verifier.c | 20 +++-
4 files changed, 334 insertions(+), 1 deletion(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index cf87db6daf27..34b9e9cd1af7 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -13,6 +13,11 @@
#include <linux/percpu.h>
#include <linux/err.h>
+#ifdef CONFIG_SECURITY_LANDLOCK
+#include <linux/fs.h> /* struct file */
+#include <linux/spinlock_types.h> /* spinlock_t */
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
struct perf_event;
struct bpf_map;
@@ -38,6 +43,7 @@ struct bpf_map_ops {
struct bpf_map {
atomic_t refcnt;
enum bpf_map_type map_type;
+ enum bpf_map_array_type map_array_type;
u32 key_size;
u32 value_size;
u32 max_entries;
@@ -80,6 +86,8 @@ enum bpf_arg_type {
ARG_PTR_TO_CTX, /* pointer to context */
ARG_ANYTHING, /* any (initialized) argument is ok */
+
+ ARG_CONST_PTR_TO_LANDLOCK_HANDLE_FS, /* pointer to Landlock FS map handle */
};
/* type of values returned from helper functions */
@@ -146,6 +154,9 @@ enum bpf_reg_type {
* map element.
*/
PTR_TO_MAP_VALUE_ADJ,
+
+ /* Landlock */
+ CONST_PTR_TO_LANDLOCK_HANDLE_FS,
};
struct bpf_prog;
@@ -196,6 +207,10 @@ struct bpf_array {
*/
enum bpf_prog_type owner_prog_type;
bool owner_jited;
+#ifdef CONFIG_SECURITY_LANDLOCK
+ atomic_t n_entries; /* number of entries in a handle array */
+ raw_spinlock_t update; /* protect n_entries consistency */
+#endif /* CONFIG_SECURITY_LANDLOCK */
union {
char value[0] __aligned(8);
void *ptrs[0] __aligned(8);
@@ -203,6 +218,15 @@ struct bpf_array {
};
};
+#ifdef CONFIG_SECURITY_LANDLOCK
+struct map_landlock_handle {
+ u32 type; /* enum bpf_map_handle_type */
+ union {
+ struct path path;
+ };
+};
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
#define MAX_TAIL_CALL_CNT 32
struct bpf_event_entry {
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index f31b655f93cf..339a9307ba6e 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -87,6 +87,18 @@ enum bpf_map_type {
BPF_MAP_TYPE_PERCPU_ARRAY,
BPF_MAP_TYPE_STACK_TRACE,
BPF_MAP_TYPE_CGROUP_ARRAY,
+ BPF_MAP_TYPE_LANDLOCK_ARRAY,
+};
+
+enum bpf_map_array_type {
+ BPF_MAP_ARRAY_TYPE_UNSPEC,
+ BPF_MAP_ARRAY_TYPE_LANDLOCK_FS,
+};
+
+enum bpf_map_handle_type {
+ BPF_MAP_HANDLE_TYPE_UNSPEC,
+ BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD,
+ /* BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_GLOB, */
};
enum bpf_prog_type {
@@ -538,4 +550,13 @@ struct xdp_md {
__u32 data_end;
};
+/* Map handle entry */
+struct landlock_handle {
+ __u32 type; /* enum bpf_map_handle_type */
+ union {
+ __u32 fd;
+ __aligned_u64 glob;
+ };
+} __attribute__((aligned(8)));
+
#endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index a2ac051c342f..3d045ee71eef 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -16,6 +16,15 @@
#include <linux/mm.h>
#include <linux/filter.h>
#include <linux/perf_event.h>
+#include <linux/file.h> /* fput() */
+#include <linux/fs.h> /* struct file */
+
+#ifdef CONFIG_SECURITY_LANDLOCK
+#include <asm/resource.h> /* RLIMIT_NOFILE */
+#include <linux/mount.h> /* struct vfsmount, MNT_INTERNAL */
+#include <linux/path.h> /* path_get(), path_put() */
+#include <linux/sched.h> /* rlimit() */
+#endif /* CONFIG_SECURITY_LANDLOCK */
static void bpf_array_free_percpu(struct bpf_array *array)
{
@@ -89,6 +98,10 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
array->map.value_size = attr->value_size;
array->map.max_entries = attr->max_entries;
array->elem_size = elem_size;
+#ifdef CONFIG_SECURITY_LANDLOCK
+ atomic_set(&array->n_entries, 0);
+ raw_spin_lock_init(&array->update);
+#endif /* CONFIG_SECURITY_LANDLOCK */
if (!percpu)
goto out;
@@ -580,3 +593,260 @@ static int __init register_cgroup_array_map(void)
}
late_initcall(register_cgroup_array_map);
#endif
+
+#ifdef CONFIG_SECURITY_LANDLOCK
+
+static struct bpf_map *landlock_array_map_alloc(union bpf_attr *attr)
+{
+ if (attr->value_size != sizeof(struct landlock_handle))
+ return ERR_PTR(-EINVAL);
+ /* XXX: FD arraymap works because elem_size = round_up(attr->value_size, 8) */
+ /* XXX: do we want memory with GFP_USER? */
+ return array_map_alloc(attr);
+}
+
+static void landlock_free_handle(struct map_landlock_handle *handle)
+{
+ enum bpf_map_handle_type handle_type;
+
+ if (WARN_ON(!handle))
+ return;
+ handle_type = handle->type;
+
+ switch (handle_type) {
+ case BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD:
+ path_put(&handle->path);
+ break;
+ case BPF_MAP_HANDLE_TYPE_UNSPEC:
+ default:
+ WARN_ON(1);
+ }
+ kfree(handle);
+}
+
+/* called when map->refcnt goes to zero, either from workqueue or from syscall */
+static void landlock_array_map_free(struct bpf_map *map)
+{
+ struct bpf_array *array = container_of(map, struct bpf_array, map);
+ struct map_landlock_handle **handle;
+ size_t i;
+
+ /* wait for all eBPF programs to complete before freeing the map */
+ synchronize_rcu();
+
+ for (i = 0, handle = (struct map_landlock_handle **) array->value;
+ i < atomic_read(&array->n_entries);
+ i++, handle = (struct map_landlock_handle **)
+ (array->value + array->elem_size * i)) {
+ landlock_free_handle(*handle);
+ }
+ kvfree(array);
+}
+
+static enum bpf_map_array_type landlock_get_array_type(
+ enum bpf_map_handle_type handle_type)
+{
+ switch (handle_type) {
+ case BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD:
+ return BPF_MAP_ARRAY_TYPE_LANDLOCK_FS;
+ case BPF_MAP_HANDLE_TYPE_UNSPEC:
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * landlock_new_handle - store an user handle in an arraymap entry
+ *
+ * @handle: non-NULL user-side Landlock handle source
+ *
+ * Return a new Landlock handle
+ */
+static inline struct map_landlock_handle *landlock_new_handle(
+ struct landlock_handle *handle)
+{
+ enum bpf_map_handle_type handle_type = handle->type;
+ struct file *handle_file;
+ struct map_landlock_handle *ret;
+
+ /* access control already done for the FD */
+
+ switch (handle_type) {
+ case BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD:
+ handle_file = fget(handle->fd);
+ if (IS_ERR(handle_file))
+ return ERR_CAST(handle_file);
+ /* check if the FD is tied to a user mount point */
+ if (unlikely(handle_file->f_path.mnt->mnt_flags & MNT_INTERNAL)) {
+ fput(handle_file);
+ return ERR_PTR(-EINVAL);
+ }
+ path_get(&handle_file->f_path);
+ ret = kmalloc(sizeof(*ret), GFP_KERNEL);
+ ret->path = handle_file->f_path;
+ fput(handle_file);
+ break;
+ case BPF_MAP_HANDLE_TYPE_UNSPEC:
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ ret->type = handle_type;
+ return ret;
+}
+
+static void *nop_map_lookup_elem(struct bpf_map *map, void *key)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+/* called from syscall or from eBPF program */
+static int landlock_array_map_update_elem(struct bpf_map *map, void *key,
+ void *value, u64 map_flags)
+{
+ struct bpf_array *array = container_of(map, struct bpf_array, map);
+ u32 index = *(u32 *)key;
+ enum bpf_map_array_type array_type;
+ int ret, n_entries;
+ struct landlock_handle *khandle = (struct landlock_handle *)value;
+ struct map_landlock_handle **handle_ref, *handle_old, *handle_new;
+ unsigned long flags;
+
+ if (unlikely(map_flags > BPF_EXIST))
+ /* unknown flags */
+ return -EINVAL;
+
+ /*
+ * Limit number of entries in an arraymap of handles to the maximum
+ * number of open files for the current process. The maximum number of
+ * handle entries (including all arraymaps) for a process is then
+ * (RLIMIT_NOFILE - 1) * RLIMIT_NOFILE. If the process' RLIMIT_NOFILE
+ * is 0, then any entry update is forbidden.
+ *
+ * An eBPF program can inherit all the arraymap FD. The worse case is
+ * to fill a bunch of arraymaps, create an eBPF program, close the
+ * arraymap FDs, and start again. The maximum number of arraymap
+ * entries can then be close to RLIMIT_NOFILE^3.
+ *
+ * FIXME: This should be improved... any idea?
+ */
+ if (unlikely(index >= rlimit(RLIMIT_NOFILE)))
+ return -EMFILE;
+
+ if (unlikely(index >= array->map.max_entries))
+ /* all elements were pre-allocated, cannot insert a new one */
+ return -E2BIG;
+
+ /* TODO: handle all flags, not only BPF_ANY */
+ if (unlikely(map_flags == BPF_NOEXIST))
+ /* all elements already exist */
+ return -EEXIST;
+
+ if (unlikely(!khandle))
+ return -EINVAL;
+
+ array_type = landlock_get_array_type(khandle->type);
+ if (array_type < 0)
+ return array_type;
+
+ if (!map->map_array_type) {
+ /* set the initial set type */
+ map->map_array_type = array_type;
+ } else if (map->map_array_type != array_type) {
+ return -EINVAL;
+ }
+
+ WARN_ON_ONCE(!rcu_read_lock_held());
+
+ /* bpf_map_update_elem() can be called in_irq() */
+ raw_spin_lock_irqsave(&array->update, flags);
+ n_entries = atomic_read(&array->n_entries);
+
+ if (unlikely(index > n_entries)) {
+ /* only replace an existing entry or append a new one */
+ ret = -EINVAL;
+ goto err;
+ }
+
+ handle_new = landlock_new_handle(khandle);
+ if (IS_ERR(handle_new)) {
+ ret = PTR_ERR(handle_new);
+ goto err;
+ }
+
+ handle_ref = (struct map_landlock_handle **)
+ (array->value + array->elem_size * index);
+ handle_old = xchg(handle_ref, handle_new);
+ if (index == n_entries)
+ atomic_inc(&array->n_entries);
+ raw_spin_unlock_irqrestore(&array->update, flags);
+
+ if (index != n_entries) {
+ synchronize_rcu();
+ landlock_free_handle(handle_old);
+ }
+ return 0;
+
+err:
+ raw_spin_unlock_irqrestore(&array->update, flags);
+ return ret;
+}
+
+/* called from syscall or from eBPF program */
+static int landlock_array_map_delete_elem(struct bpf_map *map, void *key)
+{
+ struct bpf_array *array = container_of(map, struct bpf_array, map);
+ u32 index = *(u32 *)key;
+ struct map_landlock_handle *handle_old, **handle_ref;
+ unsigned long flags;
+ int n_entries;
+
+ if (unlikely(index >= array->map.max_entries))
+ return -E2BIG;
+
+ WARN_ON_ONCE(!rcu_read_lock_held());
+
+ /* bpf_map_delete_elem() can be called in_irq() */
+ raw_spin_lock_irqsave(&array->update, flags);
+ n_entries = atomic_read(&array->n_entries);
+
+ /* only delete the last element: forbid holes in the array */
+ if (!n_entries || index != (n_entries - 1))
+ goto err;
+
+ atomic_dec(&array->n_entries);
+ handle_ref = (struct map_landlock_handle **)
+ (array->value + array->elem_size * index);
+ handle_old = xchg(handle_ref, NULL);
+ raw_spin_unlock_irqrestore(&array->update, flags);
+
+ synchronize_rcu();
+ landlock_free_handle(handle_old);
+ return 0;
+
+err:
+ raw_spin_unlock_irqrestore(&array->update, flags);
+ return -EINVAL;
+}
+
+static const struct bpf_map_ops landlock_array_ops = {
+ .map_alloc = landlock_array_map_alloc,
+ .map_free = landlock_array_map_free,
+ .map_get_next_key = array_map_get_next_key,
+ .map_lookup_elem = nop_map_lookup_elem,
+ .map_update_elem = landlock_array_map_update_elem,
+ .map_delete_elem = landlock_array_map_delete_elem,
+};
+
+static struct bpf_map_type_list landlock_array_type __read_mostly = {
+ .ops = &landlock_array_ops,
+ .type = BPF_MAP_TYPE_LANDLOCK_ARRAY,
+};
+
+static int __init register_landlock_array_map(void)
+{
+ bpf_register_map_type(&landlock_array_type);
+ return 0;
+}
+
+late_initcall(register_landlock_array_map);
+#endif /* CONFIG_SECURITY_LANDLOCK */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 99a7e5b388f2..1bc7701466b0 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -188,6 +188,7 @@ static const char * const reg_type_str[] = {
[CONST_IMM] = "imm",
[PTR_TO_PACKET] = "pkt",
[PTR_TO_PACKET_END] = "pkt_end",
+ [CONST_PTR_TO_LANDLOCK_HANDLE_FS] = "landlock_handle_fs",
};
static void print_verifier_state(struct bpf_verifier_state *state)
@@ -513,6 +514,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
case PTR_TO_PACKET_END:
case FRAME_PTR:
case CONST_PTR_TO_MAP:
+ case CONST_PTR_TO_LANDLOCK_HANDLE_FS:
return true;
default:
return false;
@@ -973,6 +975,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
expected_type = PTR_TO_CTX;
if (type != expected_type)
goto err_type;
+ } else if (arg_type == ARG_CONST_PTR_TO_LANDLOCK_HANDLE_FS) {
+ expected_type = CONST_PTR_TO_LANDLOCK_HANDLE_FS;
+ if (type != expected_type)
+ goto err_type;
} else if (arg_type == ARG_PTR_TO_STACK ||
arg_type == ARG_PTR_TO_RAW_STACK) {
expected_type = PTR_TO_STACK;
@@ -2031,6 +2037,17 @@ static struct bpf_map *ld_imm64_to_map_ptr(struct bpf_insn *insn)
return (struct bpf_map *) (unsigned long) imm64;
}
+static inline enum bpf_reg_type bpf_reg_type_from_map(struct bpf_map *map)
+{
+ switch (map->map_array_type) {
+ case BPF_MAP_ARRAY_TYPE_LANDLOCK_FS:
+ return CONST_PTR_TO_LANDLOCK_HANDLE_FS;
+ case BPF_MAP_ARRAY_TYPE_UNSPEC:
+ default:
+ return CONST_PTR_TO_MAP;
+ }
+}
+
/* verify BPF_LD_IMM64 instruction */
static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
{
@@ -2067,8 +2084,9 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
/* replace_map_fd_with_map_ptr() should have caught bad ld_imm64 */
BUG_ON(insn->src_reg != BPF_PSEUDO_MAP_FD);
- regs[insn->dst_reg].type = CONST_PTR_TO_MAP;
regs[insn->dst_reg].map_ptr = ld_imm64_to_map_ptr(insn);
+ regs[insn->dst_reg].type =
+ bpf_reg_type_from_map(regs[insn->dst_reg].map_ptr);
return 0;
}
--
2.9.3
^ permalink raw reply related
* [RFC v4 02/18] bpf: Move u64_to_ptr() to BPF headers and inline it
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
This helper will be useful for arraymap (next commit).
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: Daniel Borkmann <daniel@iogearbox.net>
---
include/linux/bpf.h | 6 ++++++
kernel/bpf/syscall.c | 6 ------
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index c201017b5730..cf87db6daf27 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -283,6 +283,12 @@ static inline void bpf_long_memcpy(void *dst, const void *src, u32 size)
/* verify correctness of eBPF program */
int bpf_check(struct bpf_prog **fp, union bpf_attr *attr);
+
+/* helper to convert user pointers passed inside __aligned_u64 fields */
+static inline void __user *u64_to_ptr(__u64 val)
+{
+ return (void __user *) (unsigned long) val;
+}
#else
static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl)
{
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 1814c010ace6..13149c9cb3a4 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -252,12 +252,6 @@ struct bpf_map *bpf_map_get_with_uref(u32 ufd)
return map;
}
-/* helper to convert user pointers passed inside __aligned_u64 fields */
-static void __user *u64_to_ptr(__u64 val)
-{
- return (void __user *) (unsigned long) val;
-}
-
int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
{
return -ENOTSUPP;
--
2.9.3
^ permalink raw reply related
* [RFC v4 01/18] landlock: Add Kconfig
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>
Initial Landlock Kconfig needed to split the Landlock eBPF and seccomp
parts to ease the review.
Changes from v2:
* add seccomp filter or cgroups (with eBPF programs attached support)
dependencies
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Serge E. Hallyn <serge@hallyn.com>
---
security/Kconfig | 1 +
security/landlock/Kconfig | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+)
create mode 100644 security/landlock/Kconfig
diff --git a/security/Kconfig b/security/Kconfig
index 118f4549404e..c63194c561c5 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -164,6 +164,7 @@ source security/tomoyo/Kconfig
source security/apparmor/Kconfig
source security/loadpin/Kconfig
source security/yama/Kconfig
+source security/landlock/Kconfig
source security/integrity/Kconfig
diff --git a/security/landlock/Kconfig b/security/landlock/Kconfig
new file mode 100644
index 000000000000..dec64270b06d
--- /dev/null
+++ b/security/landlock/Kconfig
@@ -0,0 +1,23 @@
+config SECURITY_LANDLOCK
+ bool "Landlock sandbox support"
+ depends on SECURITY
+ depends on BPF_SYSCALL
+ depends on SECCOMP_FILTER || CGROUP_BPF
+ default y
+ help
+ Landlock is a stacked LSM which allows any user to load a security
+ policy to restrict their processes (i.e. create a sandbox). The
+ policy is a list of stacked eBPF programs for some LSM hooks. Each
+ program can do some access comparison to check if an access request
+ is legitimate.
+
+ You need to enable seccomp filter and/or cgroups (with eBPF programs
+ attached support) to apply a security policy to either a process
+ hierarchy (e.g. application with built-in sandboxing) or a group of
+ processes (e.g. container sandboxing). It is recommended to enable
+ both seccomp filter and cgroups.
+
+ Further information about eBPF can be found in
+ Documentation/networking/filter.txt
+
+ If you are unsure how to answer this question, answer Y.
--
2.9.3
^ permalink raw reply related
* [RFC v4 00/18] Landlock LSM: Unprivileged sandboxing
From: Mickaël Salaün @ 2016-10-26 6:56 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
Thomas Graf, Will Drewry, kernel-hardening, linux-api,
linux-security-module, netdev, cgroups
Hi,
This fourth RFC brings some improvements over the previous one [1]. An important
new point is the abstraction from the raw types of LSM hook arguments. It is
now possible to call a Landlock function the same way for LSM hooks with
different internal argument types. Some parts of the code are revamped with RCU
to properly deal with concurrency. From a userland point of view, the only
remaining link with seccomp-bpf is the ability to use the seccomp(2) syscall to
load and enforce a Landlock rule. Seccomp filters cannot trigger Landlock rules
anymore. For now, it is no more possible for an unprivileged user to enforce a
Landlock rule on a cgroup through delegation.
As suggested, I plan to write documentation for userland and kernel developers
with some kind of guiding principles. A remaining question is how to enforce
limitations for the rule creation?
# Landlock LSM
The goal of this new stackable Linux Security Module (LSM) called Landlock is
to allow any process, including unprivileged ones, to create powerful security
sandboxes comparable to the Seatbelt/XNU Sandbox or the OpenBSD Pledge. This
kind of sandbox is expected to help mitigate the security impact of bugs or
unexpected/malicious behaviors in userland applications.
eBPF programs are used to create a security rule. They are very limited (i.e.
can only call a whitelist of functions) and cannot do a denial of service (i.e.
no loop). A new dedicated eBPF map allows to collect and compare Landlock
handles with system resources (e.g. files or network connections).
The approach taken is to add the minimum amount of code while still allowing
the userland to create quite complex access rules. A dedicated security policy
language as the one used by SELinux, AppArmor and other major LSMs involves a
lot of code and is usually dedicated to a trusted user (i.e. root).
# eBPF
To get an expressive language while still being safe and small, Landlock is
based on eBPF. Landlock should be usable by untrusted processes and must then
expose a minimal attack surface. The eBPF bytecode is minimal while powerful,
widely used and designed to be used by not so trusted application. Reusing this
code allows to not reproduce the same mistakes and minimize new code while
still taking a generic approach. Only a few additional features are added like
a new kind of arraymap and some dedicated eBPF functions.
An eBPF program has access to an eBPF context which contains the LSM hook
arguments (as does seccomp-bpf with syscall arguments). They can be used
directly or passed to helper functions according to their types. It is then
possible to do complex access checks without race conditions nor inconsistent
evaluation (i.e. incorrect mirroring of the OS code and state [2]).
There is one eBPF program subtype per LSM hook. This allows to statically check
which context access is performed by an eBPF program. This is needed to deny
kernel address leak and ensure the right use of LSM hook arguments with eBPF
functions. Moreover, this safe pointer handling removes the need for runtime
check or abstract data, which improves performances. Any user can add multiple
Landlock eBPF programs per LSM hook. They are stacked and evaluated one after
the other (cf. seccomp-bpf).
# LSM hooks
Unlike syscalls, LSM hooks are security checkpoints and are not architecture
dependent. They are designed to match a security need associated with a
security policy (e.g. access to a file). Exposing parts of some LSM hooks
instead of using the syscall API for sandboxing should help to avoid bugs and
hacks as encountered by the first RFC. Instead of redoing the work of the LSM
hooks through syscalls, we should use and expose them as does policies of
access control LSM.
Only a subset of the hooks are meaningful for an unprivileged sandbox mechanism
(e.g. file system or network access control). Landlock uses an abstraction of
raw LSM hooks, which allow to deal with possible future API changes of the LSM
hook API. Moreover, thanks to the ePBF program typing (per LSM hook) used by
Landlock, it should not be hard to make such evolutions backward compatible.
# Use case scenario
First, a process needs to create a new dedicated eBPF map containing handles.
This handles are references to system resources (e.g. file or directory) and
grouped in one or multiple maps to be efficiently managed and checked in
batches. This kind of map can be passed to Landlock eBPF functions to compare,
for example, with a file access request. The handles are only accessible from
the eBPF programs created by the same thread.
The loaded Landlock eBPF programs can be triggered by a seccomp filter
returning RET_LANDLOCK. In addition, a cookie (16-bit value) can be passed from
a seccomp filter to eBPF programs. This allow flexible security policies
between seccomp and Landlock.
Another way to enforce a Landlock security policy is to attach Landlock
programs to a dedicated cgroup. All the processes in this cgroup will then be
subject to this policy. For unprivileged processes, this can be done thanks to
cgroup delegation.
A triggered Landlock eBPF program can allow or deny an access, according to
its subtype (i.e. LSM hook), thanks to errno return values.
# Sandbox example with process hierarchy sandboxing (seccomp)
$ ls /home
user1
$ LANDLOCK_ALLOWED='/bin:/lib:/usr:/tmp:/proc/self/fd/0' \
./samples/landlock/sandbox /bin/sh -i
Launching a new sandboxed process.
$ ls /home
ls: cannot access '/home': No such file or directory
# Sandbox example with conditional access control depending on a cgroup
$ mkdir /sys/fs/cgroup/sandboxed
$ ls /home
user1
$ LANDLOCK_CGROUPS='/sys/fs/cgroup/sandboxed' \
LANDLOCK_ALLOWED='/bin:/lib:/usr:/tmp:/proc/self/fd/0' \
./samples/landlock/sandbox
Ready to sandbox with cgroups.
$ ls /home
user1
$ echo $$ > /sys/fs/cgroup/sandboxed/cgroup.procs
$ ls /home
ls: cannot access '/home': No such file or directory
# Current limitations and possible improvements
For now, eBPF programs can only return an errno code. It may be interesting to
be able to do other actions like seccomp-bpf does (e.g. kill process). Such
features can easily be implemented but the main advantage of the current
approach is to be able to only execute eBPF programs until one returns an errno
code instead of executing all programs like seccomp-bpf does.
It is quite easy to add new eBPF functions to extend Landlock. The main concern
should be about the possibility to leak information from current process to
another one (e.g. through maps) to not reproduce the same security sensitive
behavior as ptrace.
This design does not seem too intrusive but is flexible enough to allow a
powerful sandbox mechanism accessible by any process on Linux. The use of
seccomp and Landlock is more suitable with the help of a userland library (e.g.
libseccomp) that could help to specify a high-level language to express a
security policy instead of raw eBPF programs. Moreover, thanks to LLVM, it is
possible to express an eBPF program with a subset of C.
# FAQ
## Why does seccomp-bpf is not enough?
A seccomp filter can access to raw syscall arguments which means that it is not
possible to filter according to pointed such as a file path. As the first
version of this patch series demonstrated, filtering at the syscall level is
complicated (e.g. need to take care of race conditions). This is mainly because
the access control checkpoints of the kernel are not at this high-level but
more underneath, at LSM hooks level. The LSM hooks are designed to handle this
kind of checks. This series use this approach to leverage the ability of
unprivileged users to limit themselves.
Cf. "What it isn't?" in Documentation/prctl/seccomp_filter.txt
## Why using the seccomp(2) syscall?
Landlock use the same semantic as seccomp to apply access rule restrictions. It
add a new layer of security for the current process which is inherited by its
childs. It makes sense to use an unique access-restricting syscall (that should
be allowed by seccomp-bpf rules) which can only drop privileges. Moreover, a
Landlock eBPF program could come from outside a process (e.g. passed through a
UNIX socket). It is then useful to differentiate the creation/load of Landlock
eBPF programs via bpf(2), from rule enforcing via seccomp(2).
## Why using cgroups?
cgroups are designed to handle groups of processes. One use case is to manage
containers. Sandboxing based on process hierarchy (seccomp) is design to handle
immutable security policies, which is a good security property but does not
match all use cases. A user can attach Landlock rules to a cgroup. Doing so,
all the processes in that cgroup will be subject to the security policy.
However, if the user is allowed to manage this cgroup, it could dynamically
move this group of processes to a cgroup with another security policy (or
none). Landlock rules can be applied either on a process hierarchy (e.g.
application with built-in sandboxing) or a group of processes (e.g. container
sandboxing). Both approaches can be combined for the same process.
## Does Landlock can limit network access or other resources?
Limiting network access is obviously in the scope of Landlock but it is not yet
implemented. The main goal now is to get feedback about the whole concept, the
API and the file access control part. More access control types could be
implemented in the future.
Sargun Dhillon sent a RFC (Checmate) [4] to deal with network manipulation.
This could be implemented on top of the Landlock framework.
## Why a new LSM? Are SELinux, AppArmor, Smack or Tomoyo not good enough?
The current access control LSMs are fine for their purpose which is to give the
*root* the ability to enforce a security policy for the *system*. What is
missing is a way to enforce a security policy for any applications by its
developer and *unprivileged user* as seccomp can do for raw syscall filtering.
Moreover, Landlock handles stacked hook programs from different users. It must
then ensure there is no possible malicious interactions between these programs.
Differences with other (access control) LSMs:
* not only dedicated to administrators (i.e. no_new_priv);
* limited kernel attack surface (e.g. policy parsing);
* helpers to compare complex objects (path/FD), no access to internal kernel
data (do not leak addresses);
* constrained policy rules/programs (no DoS: deterministic execution time);
* do not leak more information than the loader process can legitimately have
access to (minimize metadata inference): must compare from an already allowed
file (through a handle).
## Why not use a policy language like used by SElinux or AppArmor?
This kind of LSMs are dedicated to administrators. They already manage the
system and are not a threat to the system security. However, seccomp, and
Landlock too, should be available to anyone, which potentially include
untrusted users and processes. To reduce the attack surface, Landlock should
expose the minimum amount of code, hence minimal complexity. Moreover, another
threat is to make accessible to a malicious code a new way to gain more
information. For example, Landlock features should not allow a program to get
the file owner if the directory containing this file is not readable. This data
could then be exfiltrated thanks to the access result. Thus, we should limit
the expressiveness of the available checks. The current approach is to do the
checks in such a way that only a comparison with an already accessed resource
(e.g. file descriptor) is possible. This allow to have a reference to compare
with, without exposing much information.
## As a developer, why do I need this feature?
Landlock's goal is to help userland to limit its attack surface.
Security-conscious developers would like to protect users from a security bug
in their applications and the third-party dependencies they are using. Such a
bug can compromise all the user data and help an attacker to perform a
privilege escalation. Using an *unprivileged sandbox* feature such as Landlock
empowers the developer with the ability to properly compartmentalize its
software and limit the impact of vulnerabilities.
## As a user, why do I need a this feature?
Any user can already use seccomp-bpf to whitelist a set of syscalls to
reduce the kernel attack surface for a predefined set of processes. However an
unprivileged user can't create a security policy like the root user can thanks to
SELinux and other access control LSMs. Landlock allows any unprivileged user to
protect their data from being accessed by any process they run but only an
identified subset. User tools can be created to help create such a high-level
access control policy. This policy may not be powerful enough to express the
same policies as the current access control LSMs, because of the threat an
unprivileged user can be to the system, but it should be enough for most
use-cases (e.g. blacklist or whitelist a set of file hierarchies).
# Changes since RFC v3
* use abstract LSM hook arguments with custom types (e.g. *_LANDLOCK_ARG_FS for
struct file, struct inode and struct path)
* add more LSM hooks to support full file system access control
* improve the sandbox example
* fix races and RCU issues:
* eBPF program execution and eBPF helpers
* revamp the arraymap of handles to cleanly deal with update/delete
* eBPF program subtype for Landlock:
* remove the "origin" field
* add an "option" field
* rebase onto Daniel Mack's patches v7 [3]
* remove merged commit 1955351da41c ("bpf: Set register type according to
is_valid_access()")
* fix spelling mistakes
* cleanup some type and variable names
* split patches
* for now, remove cgroup delegation handling for unprivileged user
* remove extra access check for cgroup_get_from_fd()
* remove unused example code dealing with skb
* remove seccomp-bpf link:
* no more seccomp cookie
* for now, it is no more possible to check the current syscall properties
# Changes since RFC v2
* revamp cgroup handling:
* use Daniel Mack's patches "Add eBPF hooks for cgroups" v5
* remove bpf_landlock_cmp_cgroup_beneath()
* make BPF_PROG_ATTACH usable with delegated cgroups
* add a new CGRP_NO_NEW_PRIVS flag for safe cgroups
* handle Landlock sandboxing for cgroups hierarchy
* allow unprivileged processes to attach Landlock eBPF program to cgroups
* add subtype to eBPF programs:
* replace Landlock hook identification by custom eBPF program types with a
dedicated subtype field
* manage fine-grained privileged Landlock programs
* register Landlock programs for dedicated trigger origins (e.g. syscall,
return from seccomp filter and/or interruption)
* performance and memory optimizations: use an array to access Landlock hooks
directly but do not duplicated it for each thread (seccomp-based)
* allow running Landlock programs without seccomp filter
* fix seccomp-related issues
* remove extra errno bounding check for Landlock programs
* add some examples for optional eBPF functions or context access (network
related) according to security checks to allow more features for privileged
programs (e.g. Checmate)
# Changes since RFC v1
* focus on the LSM hooks, not the syscalls:
* much more simple implementation
* does not need audit cache tricks to avoid race conditions
* more simple to use and more generic because using the LSM hook abstraction
directly
* more efficient because only checking in LSM hooks
* architecture agnostic
* switch from cBPF to eBPF:
* new eBPF program types dedicated to Landlock
* custom functions used by the eBPF program
* gain some new features (e.g. 10 registers, can load values of different
size, LLVM translator) but only a few functions allowed and a dedicated map
type
* new context: LSM hook ID, cookie and LSM hook arguments
* need to set the sysctl kernel.unprivileged_bpf_disable to 0 (default value)
to be able to load hook filters as unprivileged users
* smaller and simpler:
* no more checker groups but dedicated arraymap of handles
* simpler userland structs thanks to eBPF functions
* distinctive name: Landlock
This series can be applied on top of Daniel Mack's patches for BPF_PROG_ATTACH
v7 [3] on Linux v4.9-rc2. This can be tested with CONFIG_SECURITY_LANDLOCK,
CONFIG_SECCOMP_FILTER and CONFIG_CGROUP_BPF. I would really appreciate
constructive comments on the usability, architecture, code and userland API of
Landlock LSM.
[1] https://lkml.kernel.org/r/20160914072415.26021-1-mic@digikod.net
[2] https://crypto.stanford.edu/cs155/papers/traps.pdf
[3] https://lkml.kernel.org/r/1477390454-12553-1-git-send-email-daniel@zonque.org
[4] https://lkml.kernel.org/r/20160829114542.GA20836@ircssh.c.rugged-nimbus-611.internal
Regards,
Mickaël Salaün (18):
landlock: Add Kconfig
bpf: Move u64_to_ptr() to BPF headers and inline it
bpf,landlock: Add a new arraymap type to deal with (Landlock) handles
bpf,landlock: Add eBPF program subtype and is_valid_subtype() verifier
bpf,landlock: Define an eBPF program type for Landlock
fs: Constify path_is_under()'s arguments
landlock: Add LSM hooks
landlock: Handle file comparisons
landlock: Add manager functions
seccomp: Split put_seccomp_filter() with put_seccomp()
seccomp,landlock: Handle Landlock hooks per process hierarchy
bpf: Cosmetic change for bpf_prog_attach()
bpf/cgroup: Replace struct bpf_prog with struct bpf_object
bpf/cgroup: Make cgroup_bpf_update() return an error code
bpf/cgroup: Move capability check
bpf/cgroup,landlock: Handle Landlock hooks per cgroup
landlock: Add update and debug access flags
samples/landlock: Add sandbox example
fs/namespace.c | 2 +-
include/linux/bpf-cgroup.h | 19 +-
include/linux/bpf.h | 44 +++-
include/linux/cgroup-defs.h | 2 +
include/linux/filter.h | 1 +
include/linux/fs.h | 2 +-
include/linux/landlock.h | 95 +++++++++
include/linux/lsm_hooks.h | 5 +
include/linux/seccomp.h | 12 +-
include/uapi/linux/bpf.h | 105 ++++++++++
include/uapi/linux/seccomp.h | 1 +
kernel/bpf/arraymap.c | 270 +++++++++++++++++++++++++
kernel/bpf/cgroup.c | 139 ++++++++++---
kernel/bpf/syscall.c | 71 ++++---
kernel/bpf/verifier.c | 35 +++-
kernel/cgroup.c | 6 +-
kernel/fork.c | 15 +-
kernel/seccomp.c | 26 ++-
kernel/trace/bpf_trace.c | 12 +-
net/core/filter.c | 26 ++-
samples/Makefile | 2 +-
samples/bpf/bpf_helpers.h | 5 +
samples/landlock/.gitignore | 1 +
samples/landlock/Makefile | 16 ++
samples/landlock/sandbox.c | 405 +++++++++++++++++++++++++++++++++++++
security/Kconfig | 1 +
security/Makefile | 2 +
security/landlock/Kconfig | 23 +++
security/landlock/Makefile | 3 +
security/landlock/checker_fs.c | 152 ++++++++++++++
security/landlock/checker_fs.h | 20 ++
security/landlock/common.h | 58 ++++++
security/landlock/lsm.c | 449 +++++++++++++++++++++++++++++++++++++++++
security/landlock/manager.c | 379 ++++++++++++++++++++++++++++++++++
security/security.c | 1 +
35 files changed, 2309 insertions(+), 96 deletions(-)
create mode 100644 include/linux/landlock.h
create mode 100644 samples/landlock/.gitignore
create mode 100644 samples/landlock/Makefile
create mode 100644 samples/landlock/sandbox.c
create mode 100644 security/landlock/Kconfig
create mode 100644 security/landlock/Makefile
create mode 100644 security/landlock/checker_fs.c
create mode 100644 security/landlock/checker_fs.h
create mode 100644 security/landlock/common.h
create mode 100644 security/landlock/lsm.c
create mode 100644 security/landlock/manager.c
--
2.9.3
^ permalink raw reply
* [PATCH (net.git) 3/3] stmmac: fix PTP type ethtool stats
From: Giuseppe Cavallaro @ 2016-10-26 6:56 UTC (permalink / raw)
To: netdev
Cc: alexandre.torgue, rayagond, richardcochran, linux-kernel,
seraphin.bonnaffe, Giuseppe Cavallaro
In-Reply-To: <1477464964-5960-1-git-send-email-peppe.cavallaro@st.com>
This patch fixes the ethtool stats for PTP frames; previous
version does not take care about some message types: i.e.
announce, management and signaling. It also provided a
broken statistic in case of "No PTP message received".
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre TORGUE <alexandre.torgue@st.com>
Cc: Rayagond Kokatanur <rayagond@vayavyalabs.com>
---
drivers/net/ethernet/stmicro/stmmac/common.h | 19 ++++++++-------
drivers/net/ethernet/stmicro/stmmac/descs.h | 20 +++++++++-------
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 27 +++++++++++++--------
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 28 ++++++++++++++--------
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 19 ++++++++-------
5 files changed, 69 insertions(+), 44 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 6fc214c..6d2de4e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -120,14 +120,17 @@ struct stmmac_extra_stats {
unsigned long ip_csum_bypassed;
unsigned long ipv4_pkt_rcvd;
unsigned long ipv6_pkt_rcvd;
- unsigned long rx_msg_type_ext_no_ptp;
- unsigned long rx_msg_type_sync;
- unsigned long rx_msg_type_follow_up;
- unsigned long rx_msg_type_delay_req;
- unsigned long rx_msg_type_delay_resp;
- unsigned long rx_msg_type_pdelay_req;
- unsigned long rx_msg_type_pdelay_resp;
- unsigned long rx_msg_type_pdelay_follow_up;
+ unsigned long no_ptp_rx_msg_type_ext;
+ unsigned long ptp_rx_msg_type_sync;
+ unsigned long ptp_rx_msg_type_follow_up;
+ unsigned long ptp_rx_msg_type_delay_req;
+ unsigned long ptp_rx_msg_type_delay_resp;
+ unsigned long ptp_rx_msg_type_pdelay_req;
+ unsigned long ptp_rx_msg_type_pdelay_resp;
+ unsigned long ptp_rx_msg_type_pdelay_follow_up;
+ unsigned long ptp_rx_msg_type_announce;
+ unsigned long ptp_rx_msg_type_management;
+ unsigned long ptp_rx_msg_pkt_reserved_type;
unsigned long ptp_frame_type;
unsigned long ptp_ver;
unsigned long timestamp_dropped;
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
index 2e4c171..e3c86d4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
@@ -155,14 +155,18 @@
#define ERDES4_L3_L4_FILT_NO_MATCH_MASK GENMASK(27, 26)
/* Extended RDES4 message type definitions */
-#define RDES_EXT_NO_PTP 0
-#define RDES_EXT_SYNC 1
-#define RDES_EXT_FOLLOW_UP 2
-#define RDES_EXT_DELAY_REQ 3
-#define RDES_EXT_DELAY_RESP 4
-#define RDES_EXT_PDELAY_REQ 5
-#define RDES_EXT_PDELAY_RESP 6
-#define RDES_EXT_PDELAY_FOLLOW_UP 7
+#define RDES_EXT_NO_PTP 0x0
+#define RDES_EXT_SYNC 0x1
+#define RDES_EXT_FOLLOW_UP 0x2
+#define RDES_EXT_DELAY_REQ 0x3
+#define RDES_EXT_DELAY_RESP 0x4
+#define RDES_EXT_PDELAY_REQ 0x5
+#define RDES_EXT_PDELAY_RESP 0x6
+#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
+#define RDES_PTP_ANNOUNCE 0x8
+#define RDES_PTP_MANAGEMENT 0x9
+#define RDES_PTP_SIGNALING 0xa
+#define RDES_PTP_PKT_RESERVED_TYPE 0xf
/* Basic descriptor structure for normal and alternate descriptors */
struct dma_desc {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index 2ef2f0c..a601f8d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -123,22 +123,29 @@ static int dwmac4_wrback_get_rx_status(void *data, struct stmmac_extra_stats *x,
x->ipv4_pkt_rcvd++;
if (rdes1 & RDES1_IPV6_HEADER)
x->ipv6_pkt_rcvd++;
- if (message_type == RDES_EXT_SYNC)
- x->rx_msg_type_sync++;
+
+ if (message_type == RDES_EXT_NO_PTP)
+ x->no_ptp_rx_msg_type_ext++;
+ else if (message_type == RDES_EXT_SYNC)
+ x->ptp_rx_msg_type_sync++;
else if (message_type == RDES_EXT_FOLLOW_UP)
- x->rx_msg_type_follow_up++;
+ x->ptp_rx_msg_type_follow_up++;
else if (message_type == RDES_EXT_DELAY_REQ)
- x->rx_msg_type_delay_req++;
+ x->ptp_rx_msg_type_delay_req++;
else if (message_type == RDES_EXT_DELAY_RESP)
- x->rx_msg_type_delay_resp++;
+ x->ptp_rx_msg_type_delay_resp++;
else if (message_type == RDES_EXT_PDELAY_REQ)
- x->rx_msg_type_pdelay_req++;
+ x->ptp_rx_msg_type_pdelay_req++;
else if (message_type == RDES_EXT_PDELAY_RESP)
- x->rx_msg_type_pdelay_resp++;
+ x->ptp_rx_msg_type_pdelay_resp++;
else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
- x->rx_msg_type_pdelay_follow_up++;
- else
- x->rx_msg_type_ext_no_ptp++;
+ x->ptp_rx_msg_type_pdelay_follow_up++;
+ else if (message_type == RDES_PTP_ANNOUNCE)
+ x->ptp_rx_msg_type_announce++;
+ else if (message_type == RDES_PTP_MANAGEMENT)
+ x->ptp_rx_msg_type_management++;
+ else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
+ x->ptp_rx_msg_pkt_reserved_type++;
if (rdes1 & RDES1_PTP_PACKET_TYPE)
x->ptp_frame_type++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 38f19c9..e755493 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -150,22 +150,30 @@ static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
x->ipv4_pkt_rcvd++;
if (rdes4 & ERDES4_IPV6_PKT_RCVD)
x->ipv6_pkt_rcvd++;
- if (message_type == RDES_EXT_SYNC)
- x->rx_msg_type_sync++;
+
+ if (message_type == RDES_EXT_NO_PTP)
+ x->no_ptp_rx_msg_type_ext++;
+ else if (message_type == RDES_EXT_SYNC)
+ x->ptp_rx_msg_type_sync++;
else if (message_type == RDES_EXT_FOLLOW_UP)
- x->rx_msg_type_follow_up++;
+ x->ptp_rx_msg_type_follow_up++;
else if (message_type == RDES_EXT_DELAY_REQ)
- x->rx_msg_type_delay_req++;
+ x->ptp_rx_msg_type_delay_req++;
else if (message_type == RDES_EXT_DELAY_RESP)
- x->rx_msg_type_delay_resp++;
+ x->ptp_rx_msg_type_delay_resp++;
else if (message_type == RDES_EXT_PDELAY_REQ)
- x->rx_msg_type_pdelay_req++;
+ x->ptp_rx_msg_type_pdelay_req++;
else if (message_type == RDES_EXT_PDELAY_RESP)
- x->rx_msg_type_pdelay_resp++;
+ x->ptp_rx_msg_type_pdelay_resp++;
else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
- x->rx_msg_type_pdelay_follow_up++;
- else
- x->rx_msg_type_ext_no_ptp++;
+ x->ptp_rx_msg_type_pdelay_follow_up++;
+ else if (message_type == RDES_PTP_ANNOUNCE)
+ x->ptp_rx_msg_type_announce++;
+ else if (message_type == RDES_PTP_MANAGEMENT)
+ x->ptp_rx_msg_type_management++;
+ else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
+ x->ptp_rx_msg_pkt_reserved_type++;
+
if (rdes4 & ERDES4_PTP_FRAME_TYPE)
x->ptp_frame_type++;
if (rdes4 & ERDES4_PTP_VER)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 1e06173..c5d0142 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -115,14 +115,17 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(ip_csum_bypassed),
STMMAC_STAT(ipv4_pkt_rcvd),
STMMAC_STAT(ipv6_pkt_rcvd),
- STMMAC_STAT(rx_msg_type_ext_no_ptp),
- STMMAC_STAT(rx_msg_type_sync),
- STMMAC_STAT(rx_msg_type_follow_up),
- STMMAC_STAT(rx_msg_type_delay_req),
- STMMAC_STAT(rx_msg_type_delay_resp),
- STMMAC_STAT(rx_msg_type_pdelay_req),
- STMMAC_STAT(rx_msg_type_pdelay_resp),
- STMMAC_STAT(rx_msg_type_pdelay_follow_up),
+ STMMAC_STAT(no_ptp_rx_msg_type_ext),
+ STMMAC_STAT(ptp_rx_msg_type_sync),
+ STMMAC_STAT(ptp_rx_msg_type_follow_up),
+ STMMAC_STAT(ptp_rx_msg_type_delay_req),
+ STMMAC_STAT(ptp_rx_msg_type_delay_resp),
+ STMMAC_STAT(ptp_rx_msg_type_pdelay_req),
+ STMMAC_STAT(ptp_rx_msg_type_pdelay_resp),
+ STMMAC_STAT(ptp_rx_msg_type_pdelay_follow_up),
+ STMMAC_STAT(ptp_rx_msg_type_announce),
+ STMMAC_STAT(ptp_rx_msg_type_management),
+ STMMAC_STAT(ptp_rx_msg_pkt_reserved_type),
STMMAC_STAT(ptp_frame_type),
STMMAC_STAT(ptp_ver),
STMMAC_STAT(timestamp_dropped),
--
2.7.4
^ permalink raw reply related
* [PATCH (net.git) 1/3] stmmac: update the PTP header file
From: Giuseppe Cavallaro @ 2016-10-26 6:56 UTC (permalink / raw)
To: netdev
Cc: alexandre.torgue, rayagond, richardcochran, linux-kernel,
seraphin.bonnaffe, Giuseppe Cavallaro
In-Reply-To: <1477464964-5960-1-git-send-email-peppe.cavallaro@st.com>
This patch is to update this file by using BIT macros, removing
not used defines and fixes some typos.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre TORGUE <alexandre.torgue@st.com>
Cc: Rayagond Kokatanur <rayagond@vayavyalabs.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 72 ++++++++++++------------
1 file changed, 37 insertions(+), 35 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
index 4535df3..c06938c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -22,51 +22,53 @@
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
******************************************************************************/
-#ifndef __STMMAC_PTP_H__
-#define __STMMAC_PTP_H__
+#ifndef __STMMAC_PTP_H__
+#define __STMMAC_PTP_H__
-/* IEEE 1588 PTP register offsets */
-#define PTP_TCR 0x0700 /* Timestamp Control Reg */
-#define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */
-#define PTP_STSR 0x0708 /* System Time – Seconds Regr */
-#define PTP_STNSR 0x070C /* System Time – Nanoseconds Reg */
-#define PTP_STSUR 0x0710 /* System Time – Seconds Update Reg */
-#define PTP_STNSUR 0x0714 /* System Time – Nanoseconds Update Reg */
-#define PTP_TAR 0x0718 /* Timestamp Addend Reg */
-#define PTP_TTSR 0x071C /* Target Time Seconds Reg */
-#define PTP_TTNSR 0x0720 /* Target Time Nanoseconds Reg */
-#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
-#define PTP_TSR 0x0728 /* Timestamp Status */
+#define PTP_GMAC4_OFFSET 0xb00
+#define PTP_GMAC3_X_OFFSET 0x700
-#define PTP_STNSUR_ADDSUB_SHIFT 31
+/* IEEE 1588 PTP register offsets */
+#define PTP_TCR 0x00 /* Timestamp Control Reg */
+#define PTP_SSIR 0x04 /* Sub-Second Increment Reg */
+#define PTP_STSR 0x08 /* System Time – Seconds Regr */
+#define PTP_STNSR 0x0c /* System Time – Nanoseconds Reg */
+#define PTP_STSUR 0x10 /* System Time – Seconds Update Reg */
+#define PTP_STNSUR 0x14 /* System Time – Nanoseconds Update Reg */
+#define PTP_TAR 0x18 /* Timestamp Addend Reg */
-/* PTP TCR defines */
-#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
-#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
-#define PTP_TCR_TSINIT 0x00000004 /* Timestamp Initialize */
-#define PTP_TCR_TSUPDT 0x00000008 /* Timestamp Update */
-/* Timestamp Interrupt Trigger Enable */
-#define PTP_TCR_TSTRIG 0x00000010
-#define PTP_TCR_TSADDREG 0x00000020 /* Addend Reg Update */
-#define PTP_TCR_TSENALL 0x00000100 /* Enable Timestamp for All Frames */
-/* Timestamp Digital or Binary Rollover Control */
-#define PTP_TCR_TSCTRLSSR 0x00000200
+#define PTP_STNSUR_ADDSUB_SHIFT 31
+#define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */
+#define PTP_BINARY_ROLLOVER_MODE 0x80000000 /* ~0.466 ns */
+/* PTP Timestamp control register defines */
+#define PTP_TCR_TSENA BIT(0) /* Timestamp Enable */
+#define PTP_TCR_TSCFUPDT BIT(1) /* Timestamp Fine/Coarse Update */
+#define PTP_TCR_TSINIT BIT(2) /* Timestamp Initialize */
+#define PTP_TCR_TSUPDT BIT(3) /* Timestamp Update */
+#define PTP_TCR_TSTRIG BIT(4) /* Timestamp Interrupt Trigger Enable */
+#define PTP_TCR_TSADDREG BIT(5) /* Addend Reg Update */
+#define PTP_TCR_TSENALL BIT(8) /* Enable Timestamp for All Frames */
+#define PTP_TCR_TSCTRLSSR BIT(9) /* Digital or Binary Rollover Control */
/* Enable PTP packet Processing for Version 2 Format */
-#define PTP_TCR_TSVER2ENA 0x00000400
+#define PTP_TCR_TSVER2ENA BIT(10)
/* Enable Processing of PTP over Ethernet Frames */
-#define PTP_TCR_TSIPENA 0x00000800
+#define PTP_TCR_TSIPENA BIT(11)
/* Enable Processing of PTP Frames Sent over IPv6-UDP */
-#define PTP_TCR_TSIPV6ENA 0x00001000
+#define PTP_TCR_TSIPV6ENA BIT(12)
/* Enable Processing of PTP Frames Sent over IPv4-UDP */
-#define PTP_TCR_TSIPV4ENA 0x00002000
+#define PTP_TCR_TSIPV4ENA BIT(13)
/* Enable Timestamp Snapshot for Event Messages */
-#define PTP_TCR_TSEVNTENA 0x00004000
+#define PTP_TCR_TSEVNTENA BIT(14)
/* Enable Snapshot for Messages Relevant to Master */
-#define PTP_TCR_TSMSTRENA 0x00008000
+#define PTP_TCR_TSMSTRENA BIT(15)
/* Select PTP packets for Taking Snapshots */
-#define PTP_TCR_SNAPTYPSEL_1 0x00010000
+#define PTP_TCR_SNAPTYPSEL_1 GENMASK(17, 16)
/* Enable MAC address for PTP Frame Filtering */
-#define PTP_TCR_TSENMACADDR 0x00040000
+#define PTP_TCR_TSENMACADDR BIT(18)
+
+/* SSIR defines */
+#define PTP_SSIR_SSINC_MASK 0xff
+#define GMAC4_PTP_SSIR_SSINC_SHIFT 16
-#endif /* __STMMAC_PTP_H__ */
+#endif /* __STMMAC_PTP_H__ */
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] IB/mlx4: avoid a -Wmaybe-uninitialize warning
From: Yishai Hadas @ 2016-10-26 6:51 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Yishai Hadas, David S. Miller, Jack Morgenstein, Or Gerlitz,
Eran Ben Elisha, Moshe Shemesh, Christophe Jaillet, Moni Shoua,
netdev, linux-rdma, linux-kernel
In-Reply-To: <20161025161632.411899-1-arnd@arndb.de>
On 10/25/2016 7:16 PM, Arnd Bergmann wrote:
> There is an old warning about mlx4_SW2HW_EQ_wrapper on x86:
>
> ethernet/mellanox/mlx4/resource_tracker.c: In function ‘mlx4_SW2HW_EQ_wrapper’:
> ethernet/mellanox/mlx4/resource_tracker.c:3071:10: error: ‘eq’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
>
> The problem here is that gcc won't track the state of the variable
> across a spin_unlock. Moving the assignment out of the lock is
> safe here and avoids the warning.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Yishai Hadas <yishaih@mellanox.com>
> ---
> drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
> index 84d7857ccc27..c548beaaf910 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
> @@ -1605,13 +1605,14 @@ static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
> r->com.from_state = r->com.state;
> r->com.to_state = state;
> r->com.state = RES_EQ_BUSY;
> - if (eq)
> - *eq = r;
> }
> }
>
> spin_unlock_irq(mlx4_tlock(dev));
>
> + if (!err && eq)
> + *eq = r;
> +
> return err;
> }
>
>
^ permalink raw reply
* Re: [PATCH 19/28] brcmfmac: avoid maybe-uninitialized warning in brcmf_cfg80211_start_ap
From: Kalle Valo @ 2016-10-26 6:49 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Arend van Spriel, Linus Torvalds, linux-kernel, Hante Meuleman,
Franky Lin, Pieter-Paul Giesberts, Franky (Zhenhui) Lin,
Rafał Miłecki, linux-wireless, brcm80211-dev-list.pdl,
netdev
In-Reply-To: <20161017221355.1861551-7-arnd@arndb.de>
Arnd Bergmann <arnd@arndb.de> writes:
> A bugfix added a sanity check around the assignment and use of the
> 'is_11d' variable, which looks correct to me, but as the function is
> rather complex already, this confuses the compiler to the point where
> it can no longer figure out if the variable is always initialized
> correctly:
>
> brcm80211/brcmfmac/cfg80211.c: In function ‘brcmf_cfg80211_start_ap’:
> brcm80211/brcmfmac/cfg80211.c:4586:10: error: ‘is_11d’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
>
> This adds an initialization for the newly introduced case in which
> the variable should not really be used, in order to make the warning
> go away.
>
> Fixes: b3589dfe0212 ("brcmfmac: ignore 11d configuration errors")
> Cc: Hante Meuleman <hante.meuleman@broadcom.com>
> Cc: Arend van Spriel <arend.vanspriel@broadcom.com>
> Cc: Kalle Valo <kvalo@codeaurora.org>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Via which tree are you planning to submit this? Should I take it?
--
Kalle Valo
^ permalink raw reply
* [PATCH net-next] net: core: Traverse the adjacency list from first entry
From: idosch @ 2016-10-26 6:39 UTC (permalink / raw)
To: davem; +Cc: netdev, mlxsw, dsa, Ido Schimmel
From: Ido Schimmel <idosch@mellanox.com>
netdev_next_lower_dev() returns NULL when we finished traversing the
adjacency list ('iter' points to the list's head). Therefore, we must
start traversing the list from the first entry and not its head.
Fixes: 1a3f060c1a47 ("net: Introduce new api for walking upper and lower devices")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
net/core/dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index f55fb45..d9c937f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5419,7 +5419,7 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
struct list_head *iter;
int ret;
- for (iter = &dev->adj_list.lower,
+ for (iter = dev->adj_list.lower.next,
ldev = netdev_next_lower_dev(dev, &iter);
ldev;
ldev = netdev_next_lower_dev(dev, &iter)) {
--
2.7.4
^ permalink raw reply related
* Re: [PATCH (net.git)] net: phy: at803x: disable by default the hibernation feature
From: Giuseppe CAVALLARO @ 2016-10-26 6:08 UTC (permalink / raw)
To: Andrew Lunn; +Cc: netdev, Matus Ujhelyi
In-Reply-To: <20161025090007.GB21818@lunn.ch>
Hello Andrew.
On 10/25/2016 11:00 AM, Andrew Lunn wrote:
>> For example, while booting a Kernel the SYNP MAC (stmmac) fails
>> to initialize own DMA engine if the phy entered in hibernation
>> before.
>
> Have you tried fixing stmmac instead?
Let me describe better what happens, to be honest, this is a
marginal user-case, but, maybe it makes sense to share this patch in
case of somebody meets the same issue.
When performing "ifconfig eth0 up", if this phy is not in hibernation,
the iface comes up w/o any issues.
If the PHY is in hibernation, because the cable is unplugged (and
this is a default for these transceivers), the phy clock does down and
the MAC cannot init own DMA. The stmmac is designed to fail the open in
this case.
If I plug the cable the next ifconfig up is ok.
The meaning of the patch, I proposed, is to remove by default this
hibernation feature at PHY level that, for me, should be an option
not a default. For example, I have used other HW where some
power state features could be enabled but, by default, were turned
off. Also these transceivers support EEE so, I guess, there is all the
technology to manage the power consumption on new setup.
Concerning the stmmac, how the driver could fix this situation?
The PHY does not provide the clock required for GMAC and the stmmac
cannot reset own DMA. I had thought to delay this as soon as the link
is UP but I don't like this approach where the open should return
a sane state but this is not true and we should wait the ACK from the
PHY to reset the MAC DMAC.
Anyway, as said, the patch covers a marginal user-case so feel free to
consider it or not. For sure, I am open to change something at MAC
level if you have better idea.
Regards
Peppe
>
> Andrew
>
^ permalink raw reply
* Re: [PATCH net] sctp: validate chunk len before actually using it
From: Xin Long @ 2016-10-26 5:54 UTC (permalink / raw)
To: Marcelo Ricardo Leitner
Cc: network dev, linux-sctp, Neil Horman, Vlad Yasevich, syzkaller,
kcc, glider, Eric Dumazet, Dmitry Vyukov, andreyknvl
In-Reply-To: <06d1d4f21f959784823d7c7e31c3ea7e7360cb99.1477410525.git.marcelo.leitner@gmail.com>
On Wed, Oct 26, 2016 at 12:27 AM, Marcelo Ricardo Leitner
<marcelo.leitner@gmail.com> wrote:
> Andrey Konovalov reported that KASAN detected that SCTP was using a slab
> beyond the boundaries. It was caused because when handling out of the
> blue packets in function sctp_sf_ootb() it was checking the chunk len
> only after already processing the first chunk, validating only for the
> 2nd and subsequent ones.
>
> The fix is to just move the check upwards so it's also validated for the
> 1st chunk.
>
> Reported-by: Andrey Konovalov <andreyknvl@google.com>
> Tested-by: Andrey Konovalov <andreyknvl@google.com>
> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Reviewed-by: Xin Long <lucien.xin@gmail.com>
^ permalink raw reply
* Re: [PATCH net] packet: on direct_xmit, limit tso and csum to supported devices
From: Willem de Bruijn @ 2016-10-26 4:29 UTC (permalink / raw)
To: Eric Dumazet
Cc: Network Development, David Miller, Daniel Borkmann,
Willem de Bruijn
In-Reply-To: <1477443451.7065.163.camel@edumazet-glaptop3.roam.corp.google.com>
On Tue, Oct 25, 2016 at 8:57 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Tue, 2016-10-25 at 20:28 -0400, Willem de Bruijn wrote:
>> From: Willem de Bruijn <willemb@google.com>
>>
>> When transmitting on a packet socket with PACKET_VNET_HDR and
>> PACKET_QDISC_BYPASS, validate device support for features requested
>> in vnet_hdr.
>
>
> You probably need to add an EXPORT_SYMBOL(validate_xmit_skb_list)
> because af_packet might be modular.
Thanks, Eric. I'll send a v2.
^ permalink raw reply
* Re: [PATCH net-next 2/3] bpf: Add new cgroups prog type to enable sock modifications
From: David Ahern @ 2016-10-26 3:09 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, daniel, ast, daniel
In-Reply-To: <1477450103.7065.175.camel@edumazet-glaptop3.roam.corp.google.com>
On 10/25/16 8:48 PM, Eric Dumazet wrote:
> Maybe I do not understand how you plan to use this.
>
> Let say you want a filter to force a BIND_TO_DEVICE xxx because a task
> runs in a cgroup yyy
>
> Then a program doing a socket() + connect (127.0.0.1) will fail ?
maybe. VRF devices can have 127.0.0.1 address in which case the connect would succeed. ntpq uses 127.0.0.1 to talk to ntpd for example. If ntpd is bound to a Management VRF, then you need this context for ntpq to talk to it.
>
> I do not see how a BPF filter at socket() time can be selective.
Here's my use case - and this is what we are doing today with the l3mdev cgroup (a patch which has not been accepted upstream):
1. create VRF device
2. create cgroup and configure it
in this case it means load the bpf program that sets the sk_bound_dev_if to the vrf device that was just created
3. Add shell to cgroup
For Management VRF this can be done automatically at login so a user does not need to take any action.
At this point any command run in the shell runs in the VRF context (PS1 for bash can show the VRF to keep you from going crazy on why a connect fails :-)) so any ipv4/ipv6 sockets have that VRF scope.
For example, if the VRF is a management VRF, sockets opened by apt-get are automatically bound to the VRF at create time, so requests go out the eth0 (management) interface.
In a similar fashion, using a cgroup and assigning tasks to it allows automated launch of systemd services with instances running in a VRF context - one dhcrelay in vrf red, one in vrf blue with both using a parameterized instance file.
^ permalink raw reply
* Re: [PATCH net-next 2/3] bpf: Add new cgroups prog type to enable sock modifications
From: Eric Dumazet @ 2016-10-26 2:48 UTC (permalink / raw)
To: David Ahern; +Cc: netdev, daniel, ast, daniel
In-Reply-To: <fdeb1f5b-d122-36d8-4866-42cb5f29f0e2@cumulusnetworks.com>
On Tue, 2016-10-25 at 20:21 -0600, David Ahern wrote:
> On 10/25/16 5:39 PM, Eric Dumazet wrote:
> > On Tue, 2016-10-25 at 15:30 -0700, David Ahern wrote:
> >> Add new cgroup based program type, BPF_PROG_TYPE_CGROUP_SOCK. Similar to
> >> BPF_PROG_TYPE_CGROUP_SKB programs can be attached to a cgroup and run
> >> any time a process in the cgroup opens an AF_INET or AF_INET6 socket.
> >> Currently only sk_bound_dev_if is exported to userspace for modification
> >> by a bpf program.
> >>
> >> This allows a cgroup to be configured such that AF_INET{6} sockets opened
> >> by processes are automatically bound to a specific device. In turn, this
> >> enables the running of programs that do not support SO_BINDTODEVICE in a
> >> specific VRF context / L3 domain.
> >
> > Does this mean that these programs no longer can use loopback ?
>
> I am probably misunderstanding your question, so I'll ramble a bit and
> see if I cover it.
>
> This patch set generically allows sk_bound_dev_if to be set to any
> value. It does not check that an index corresponds to a device at that
> moment (either bpf prog install or execution of the filter), and even
> if it did the device can be deleted at any moment. That seems to be
> standard operating procedure with bpf filters (user mistakes mean
> packets go no where and in this case a socket is bound to a
> non-existent device).
>
> The index can be any interface (e.g., eth0) or an L3 device (e.g., a
> VRF). Loopback and index=1 is allowed.
>
> The VRF device is the loopback device for the domain, so binding to it
> covers addresses on the VRF device as well as interfaces enslaved to
> it.
>
> Did you mean something else?
Maybe I do not understand how you plan to use this.
Let say you want a filter to force a BIND_TO_DEVICE xxx because a task
runs in a cgroup yyy
Then a program doing a socket() + connect (127.0.0.1) will fail ?
I do not see how a BPF filter at socket() time can be selective.
^ permalink raw reply
* [PATCH v2 3/5] kconfig: regenerate *.c_shipped files after previous changes
From: Nicolas Pitre @ 2016-10-26 2:28 UTC (permalink / raw)
To: John Stultz, Richard Cochran, Yann E. MORIN, Michal Marek
Cc: Thomas Gleixner, Josh Triplett, Edward Cree, netdev, linux-kbuild,
linux-kernel
In-Reply-To: <1477448931-29051-1-git-send-email-nicolas.pitre@linaro.org>
Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
scripts/kconfig/zconf.hash.c_shipped | 228 ++---
scripts/kconfig/zconf.tab.c_shipped | 1631 ++++++++++++++++------------------
2 files changed, 888 insertions(+), 971 deletions(-)
diff --git a/scripts/kconfig/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped
index 360a62df2b..bf7f1378b3 100644
--- a/scripts/kconfig/zconf.hash.c_shipped
+++ b/scripts/kconfig/zconf.hash.c_shipped
@@ -32,7 +32,7 @@
struct kconf_id;
static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
-/* maximum key range = 71, duplicates = 0 */
+/* maximum key range = 72, duplicates = 0 */
#ifdef __GNUC__
__inline
@@ -46,32 +46,32 @@ kconf_id_hash (register const char *str, register unsigned int len)
{
static const unsigned char asso_values[] =
{
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 0, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 5, 25, 25,
- 0, 0, 0, 5, 0, 0, 73, 73, 5, 0,
- 10, 5, 45, 73, 20, 20, 0, 15, 15, 73,
- 20, 5, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 0, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 0, 20, 10,
+ 0, 0, 0, 30, 0, 0, 74, 74, 5, 15,
+ 0, 25, 40, 74, 15, 0, 0, 10, 35, 74,
+ 10, 0, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74
};
register int hval = len;
@@ -97,33 +97,35 @@ struct kconf_id_strings_t
char kconf_id_strings_str8[sizeof("tristate")];
char kconf_id_strings_str9[sizeof("endchoice")];
char kconf_id_strings_str10[sizeof("---help---")];
+ char kconf_id_strings_str11[sizeof("select")];
char kconf_id_strings_str12[sizeof("def_tristate")];
char kconf_id_strings_str13[sizeof("def_bool")];
char kconf_id_strings_str14[sizeof("defconfig_list")];
- char kconf_id_strings_str17[sizeof("on")];
- char kconf_id_strings_str18[sizeof("optional")];
- char kconf_id_strings_str21[sizeof("option")];
- char kconf_id_strings_str22[sizeof("endmenu")];
- char kconf_id_strings_str23[sizeof("mainmenu")];
- char kconf_id_strings_str25[sizeof("menuconfig")];
- char kconf_id_strings_str27[sizeof("modules")];
- char kconf_id_strings_str28[sizeof("allnoconfig_y")];
+ char kconf_id_strings_str16[sizeof("source")];
+ char kconf_id_strings_str17[sizeof("endmenu")];
+ char kconf_id_strings_str18[sizeof("allnoconfig_y")];
+ char kconf_id_strings_str20[sizeof("range")];
+ char kconf_id_strings_str22[sizeof("modules")];
+ char kconf_id_strings_str23[sizeof("hex")];
+ char kconf_id_strings_str27[sizeof("on")];
char kconf_id_strings_str29[sizeof("menu")];
- char kconf_id_strings_str31[sizeof("select")];
+ char kconf_id_strings_str31[sizeof("option")];
char kconf_id_strings_str32[sizeof("comment")];
- char kconf_id_strings_str33[sizeof("env")];
- char kconf_id_strings_str35[sizeof("range")];
- char kconf_id_strings_str36[sizeof("choice")];
- char kconf_id_strings_str39[sizeof("bool")];
- char kconf_id_strings_str41[sizeof("source")];
+ char kconf_id_strings_str33[sizeof("mainmenu")];
+ char kconf_id_strings_str37[sizeof("suggest")];
+ char kconf_id_strings_str38[sizeof("optional")];
+ char kconf_id_strings_str41[sizeof("choice")];
char kconf_id_strings_str42[sizeof("visible")];
- char kconf_id_strings_str43[sizeof("hex")];
+ char kconf_id_strings_str45[sizeof("imply")];
char kconf_id_strings_str46[sizeof("config")];
- char kconf_id_strings_str47[sizeof("boolean")];
+ char kconf_id_strings_str47[sizeof("depends")];
+ char kconf_id_strings_str49[sizeof("help")];
char kconf_id_strings_str51[sizeof("string")];
- char kconf_id_strings_str54[sizeof("help")];
- char kconf_id_strings_str56[sizeof("prompt")];
- char kconf_id_strings_str72[sizeof("depends")];
+ char kconf_id_strings_str52[sizeof("boolean")];
+ char kconf_id_strings_str54[sizeof("bool")];
+ char kconf_id_strings_str55[sizeof("menuconfig")];
+ char kconf_id_strings_str71[sizeof("prompt")];
+ char kconf_id_strings_str73[sizeof("env")];
};
static const struct kconf_id_strings_t kconf_id_strings_contents =
{
@@ -134,33 +136,35 @@ static const struct kconf_id_strings_t kconf_id_strings_contents =
"tristate",
"endchoice",
"---help---",
+ "select",
"def_tristate",
"def_bool",
"defconfig_list",
- "on",
- "optional",
- "option",
+ "source",
"endmenu",
- "mainmenu",
- "menuconfig",
- "modules",
"allnoconfig_y",
+ "range",
+ "modules",
+ "hex",
+ "on",
"menu",
- "select",
+ "option",
"comment",
- "env",
- "range",
+ "mainmenu",
+ "suggest",
+ "optional",
"choice",
- "bool",
- "source",
"visible",
- "hex",
+ "imply",
"config",
- "boolean",
- "string",
+ "depends",
"help",
+ "string",
+ "boolean",
+ "bool",
+ "menuconfig",
"prompt",
- "depends"
+ "env"
};
#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
#ifdef __GNUC__
@@ -174,11 +178,11 @@ kconf_id_lookup (register const char *str, register unsigned int len)
{
enum
{
- TOTAL_KEYWORDS = 34,
+ TOTAL_KEYWORDS = 36,
MIN_WORD_LENGTH = 2,
MAX_WORD_LENGTH = 14,
MIN_HASH_VALUE = 2,
- MAX_HASH_VALUE = 72
+ MAX_HASH_VALUE = 73
};
static const struct kconf_id wordlist[] =
@@ -200,75 +204,79 @@ kconf_id_lookup (register const char *str, register unsigned int len)
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND},
#line 25 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_HELP, TF_COMMAND},
- {-1},
+#line 40 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_SELECT, TF_COMMAND},
#line 33 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE},
#line 36 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
-#line 46 "scripts/kconfig/zconf.gperf"
+#line 48 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION},
- {-1}, {-1},
-#line 44 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ON, TF_PARAM},
-#line 29 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND},
- {-1}, {-1},
-#line 43 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_OPTION, TF_COMMAND},
+ {-1},
+#line 18 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_SOURCE, TF_COMMAND},
#line 17 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND},
-#line 15 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_MAINMENU, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ENDMENU, TF_COMMAND},
+#line 50 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPT_ALLNOCONFIG_Y,TF_OPTION},
{-1},
-#line 23 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25, T_MENUCONFIG, TF_COMMAND},
+#line 43 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_RANGE, TF_COMMAND},
+ {-1},
+#line 47 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_OPT_MODULES, TF_OPTION},
+#line 38 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_HEX},
+ {-1}, {-1}, {-1},
+#line 46 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_ON, TF_PARAM},
{-1},
-#line 45 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION},
-#line 48 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPT_ALLNOCONFIG_Y,TF_OPTION},
#line 16 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND},
{-1},
-#line 40 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND},
+#line 45 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_OPTION, TF_COMMAND},
#line 21 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
-#line 47 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_OPT_ENV, TF_OPTION},
- {-1},
-#line 41 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_RANGE, TF_COMMAND},
-#line 19 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_CHOICE, TF_COMMAND},
- {-1}, {-1},
-#line 34 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39, T_TYPE, TF_COMMAND, S_BOOLEAN},
- {-1},
-#line 18 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND},
+#line 15 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_MAINMENU, TF_COMMAND},
+ {-1}, {-1}, {-1},
#line 42 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_SUGGEST, TF_COMMAND},
+#line 29 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str38, T_OPTIONAL, TF_COMMAND},
+ {-1}, {-1},
+#line 19 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_CHOICE, TF_COMMAND},
+#line 44 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_VISIBLE, TF_COMMAND},
-#line 38 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_TYPE, TF_COMMAND, S_HEX},
{-1}, {-1},
+#line 41 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str45, T_IMPLY, TF_COMMAND},
#line 22 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_CONFIG, TF_COMMAND},
-#line 35 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN},
- {-1}, {-1}, {-1},
+#line 28 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_DEPENDS, TF_COMMAND},
+ {-1},
+#line 24 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str49, T_HELP, TF_COMMAND},
+ {-1},
#line 39 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_TYPE, TF_COMMAND, S_STRING},
- {-1}, {-1},
-#line 24 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54, T_HELP, TF_COMMAND},
+#line 35 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str52, T_TYPE, TF_COMMAND, S_BOOLEAN},
{-1},
-#line 31 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str56, T_PROMPT, TF_COMMAND},
+#line 34 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54, T_TYPE, TF_COMMAND, S_BOOLEAN},
+#line 23 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str55, T_MENUCONFIG, TF_COMMAND},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 28 "scripts/kconfig/zconf.gperf"
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str72, T_DEPENDS, TF_COMMAND}
+#line 31 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str71, T_PROMPT, TF_COMMAND},
+ {-1},
+#line 49 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str73, T_OPT_ENV, TF_OPTION}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -289,5 +297,5 @@ kconf_id_lookup (register const char *str, register unsigned int len)
}
return 0;
}
-#line 49 "scripts/kconfig/zconf.gperf"
+#line 51 "scripts/kconfig/zconf.gperf"
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index 7a4d658c20..ecc3cdb382 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -1,19 +1,19 @@
-/* A Bison parser, made by GNU Bison 2.5.1. */
+/* A Bison parser, made by GNU Bison 3.0.4. */
/* Bison implementation for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
-
+
+ Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@@ -26,7 +26,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -44,7 +44,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.5.1"
+#define YYBISON_VERSION "3.0.4"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -58,18 +58,16 @@
/* Pull parsers. */
#define YYPULL 1
-/* Using locations. */
-#define YYLSP_NEEDED 0
/* Substitute the variable and function names. */
#define yyparse zconfparse
#define yylex zconflex
#define yyerror zconferror
-#define yylval zconflval
-#define yychar zconfchar
#define yydebug zconfdebug
#define yynerrs zconfnerrs
+#define yylval zconflval
+#define yychar zconfchar
/* Copy the first part of user declarations. */
@@ -108,19 +106,14 @@ static struct menu *current_menu, *current_entry;
-# ifndef YY_NULL
+# ifndef YY_NULLPTR
# if defined __cplusplus && 201103L <= __cplusplus
-# define YY_NULL nullptr
+# define YY_NULLPTR nullptr
# else
-# define YY_NULL 0
+# define YY_NULLPTR 0
# endif
# endif
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-
/* Enabling verbose error messages. */
#ifdef YYERROR_VERBOSE
# undef YYERROR_VERBOSE
@@ -129,62 +122,66 @@ static struct menu *current_menu, *current_entry;
# define YYERROR_VERBOSE 0
#endif
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int zconfdebug;
+#endif
-/* Tokens. */
+/* Token type. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- T_MAINMENU = 258,
- T_MENU = 259,
- T_ENDMENU = 260,
- T_SOURCE = 261,
- T_CHOICE = 262,
- T_ENDCHOICE = 263,
- T_COMMENT = 264,
- T_CONFIG = 265,
- T_MENUCONFIG = 266,
- T_HELP = 267,
- T_HELPTEXT = 268,
- T_IF = 269,
- T_ENDIF = 270,
- T_DEPENDS = 271,
- T_OPTIONAL = 272,
- T_PROMPT = 273,
- T_TYPE = 274,
- T_DEFAULT = 275,
- T_SELECT = 276,
- T_RANGE = 277,
- T_VISIBLE = 278,
- T_OPTION = 279,
- T_ON = 280,
- T_WORD = 281,
- T_WORD_QUOTE = 282,
- T_UNEQUAL = 283,
- T_LESS = 284,
- T_LESS_EQUAL = 285,
- T_GREATER = 286,
- T_GREATER_EQUAL = 287,
- T_CLOSE_PAREN = 288,
- T_OPEN_PAREN = 289,
- T_EOL = 290,
- T_OR = 291,
- T_AND = 292,
- T_EQUAL = 293,
- T_NOT = 294
- };
+ enum yytokentype
+ {
+ T_MAINMENU = 258,
+ T_MENU = 259,
+ T_ENDMENU = 260,
+ T_SOURCE = 261,
+ T_CHOICE = 262,
+ T_ENDCHOICE = 263,
+ T_COMMENT = 264,
+ T_CONFIG = 265,
+ T_MENUCONFIG = 266,
+ T_HELP = 267,
+ T_HELPTEXT = 268,
+ T_IF = 269,
+ T_ENDIF = 270,
+ T_DEPENDS = 271,
+ T_OPTIONAL = 272,
+ T_PROMPT = 273,
+ T_TYPE = 274,
+ T_DEFAULT = 275,
+ T_SELECT = 276,
+ T_IMPLY = 277,
+ T_SUGGEST = 278,
+ T_RANGE = 279,
+ T_VISIBLE = 280,
+ T_OPTION = 281,
+ T_ON = 282,
+ T_WORD = 283,
+ T_WORD_QUOTE = 284,
+ T_UNEQUAL = 285,
+ T_LESS = 286,
+ T_LESS_EQUAL = 287,
+ T_GREATER = 288,
+ T_GREATER_EQUAL = 289,
+ T_CLOSE_PAREN = 290,
+ T_OPEN_PAREN = 291,
+ T_EOL = 292,
+ T_OR = 293,
+ T_AND = 294,
+ T_EQUAL = 295,
+ T_NOT = 296
+ };
#endif
-
-
+/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
+
+union YYSTYPE
{
@@ -196,14 +193,20 @@ typedef union YYSTYPE
const struct kconf_id *id;
+};
-} YYSTYPE;
+typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
+extern YYSTYPE zconflval;
+
+int zconfparse (void);
+
+
+
/* Copy the second part of user declarations. */
@@ -224,11 +227,8 @@ typedef unsigned char yytype_uint8;
#ifdef YYTYPE_INT8
typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
#else
-typedef short int yytype_int8;
+typedef signed char yytype_int8;
#endif
#ifdef YYTYPE_UINT16
@@ -248,8 +248,7 @@ typedef short int yytype_int16;
# define YYSIZE_T __SIZE_TYPE__
# elif defined size_t
# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
+# elif ! defined YYSIZE_T
# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
# define YYSIZE_T size_t
# else
@@ -263,39 +262,68 @@ typedef short int yytype_int16;
# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
# endif
# endif
# ifndef YY_
-# define YY_(msgid) msgid
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__ \
+ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
+ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+# define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+# define _Noreturn __declspec (noreturn)
+# else
+# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
#else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
#endif
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
-#else
-static int
-YYID (yyi)
- int yyi;
+# define YY_INITIAL_VALUE(Value) Value
#endif
-{
- return yyi;
-}
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
#endif
+
#if ! defined yyoverflow || YYERROR_VERBOSE
/* The parser invokes alloca or malloc; define the necessary symbols. */
@@ -313,8 +341,7 @@ YYID (yyi)
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
/* Use EXIT_SUCCESS as a witness for stdlib.h. */
# ifndef EXIT_SUCCESS
@@ -326,8 +353,8 @@ YYID (yyi)
# endif
# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
# ifndef YYSTACK_ALLOC_MAXIMUM
/* The OS might guarantee only one guard page at the bottom of the stack,
and a page size can be as small as 4096 bytes. So we cannot safely
@@ -343,7 +370,7 @@ YYID (yyi)
# endif
# if (defined __cplusplus && ! defined EXIT_SUCCESS \
&& ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
+ && (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
# ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
@@ -351,15 +378,13 @@ YYID (yyi)
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
+# if ! defined malloc && ! defined EXIT_SUCCESS
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
-# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
+# if ! defined free && ! defined EXIT_SUCCESS
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
@@ -369,7 +394,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
#if (! defined yyoverflow \
&& (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
/* A type that is properly aligned for any stack member. */
union yyalloc
@@ -394,16 +419,16 @@ union yyalloc
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
#endif
@@ -422,7 +447,7 @@ union yyalloc
for (yyi = 0; yyi < (Count); yyi++) \
(Dst)[yyi] = (Src)[yyi]; \
} \
- while (YYID (0))
+ while (0)
# endif
# endif
#endif /* !YYCOPY_NEEDED */
@@ -430,25 +455,27 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 11
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 298
+#define YYLAST 310
/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 40
+#define YYNTOKENS 42
/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 50
/* YYNRULES -- Number of rules. */
-#define YYNRULES 122
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 199
+#define YYNRULES 126
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 209
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
#define YYUNDEFTOK 2
-#define YYMAXUTOK 294
+#define YYMAXUTOK 296
-#define YYTRANSLATE(YYX) \
+#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, without out-of-bounds checking. */
static const yytype_uint8 yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -480,90 +507,30 @@ static const yytype_uint8 yytranslate[] =
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
+ 35, 36, 37, 38, 39, 40, 41
};
#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 6, 8, 11, 13, 14, 17, 20,
- 23, 26, 31, 36, 40, 42, 44, 46, 48, 50,
- 52, 54, 56, 58, 60, 62, 64, 66, 68, 72,
- 75, 79, 82, 86, 89, 90, 93, 96, 99, 102,
- 105, 108, 112, 117, 122, 127, 133, 137, 138, 142,
- 143, 146, 150, 153, 155, 159, 160, 163, 166, 169,
- 172, 175, 180, 184, 187, 192, 193, 196, 200, 202,
- 206, 207, 210, 213, 216, 220, 224, 228, 230, 234,
- 235, 238, 241, 244, 248, 252, 255, 258, 261, 262,
- 265, 268, 271, 276, 277, 280, 283, 286, 287, 290,
- 292, 294, 297, 300, 303, 305, 308, 309, 312, 314,
- 318, 322, 326, 330, 334, 338, 342, 345, 349, 353,
- 355, 357, 358
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int8 yyrhs[] =
-{
- 41, 0, -1, 85, 42, -1, 42, -1, 67, 43,
- -1, 43, -1, -1, 43, 45, -1, 43, 59, -1,
- 43, 71, -1, 43, 84, -1, 43, 26, 1, 35,
- -1, 43, 44, 1, 35, -1, 43, 1, 35, -1,
- 16, -1, 18, -1, 19, -1, 21, -1, 17, -1,
- 22, -1, 20, -1, 23, -1, 35, -1, 65, -1,
- 75, -1, 48, -1, 50, -1, 73, -1, 26, 1,
- 35, -1, 1, 35, -1, 10, 26, 35, -1, 47,
- 51, -1, 11, 26, 35, -1, 49, 51, -1, -1,
- 51, 52, -1, 51, 53, -1, 51, 79, -1, 51,
- 77, -1, 51, 46, -1, 51, 35, -1, 19, 82,
- 35, -1, 18, 83, 86, 35, -1, 20, 87, 86,
- 35, -1, 21, 26, 86, 35, -1, 22, 88, 88,
- 86, 35, -1, 24, 54, 35, -1, -1, 54, 26,
- 55, -1, -1, 38, 83, -1, 7, 89, 35, -1,
- 56, 60, -1, 84, -1, 57, 62, 58, -1, -1,
- 60, 61, -1, 60, 79, -1, 60, 77, -1, 60,
- 35, -1, 60, 46, -1, 18, 83, 86, 35, -1,
- 19, 82, 35, -1, 17, 35, -1, 20, 26, 86,
- 35, -1, -1, 62, 45, -1, 14, 87, 85, -1,
- 84, -1, 63, 66, 64, -1, -1, 66, 45, -1,
- 66, 71, -1, 66, 59, -1, 3, 83, 85, -1,
- 4, 83, 35, -1, 68, 80, 78, -1, 84, -1,
- 69, 72, 70, -1, -1, 72, 45, -1, 72, 71,
- -1, 72, 59, -1, 6, 83, 35, -1, 9, 83,
- 35, -1, 74, 78, -1, 12, 35, -1, 76, 13,
- -1, -1, 78, 79, -1, 78, 35, -1, 78, 46,
- -1, 16, 25, 87, 35, -1, -1, 80, 81, -1,
- 80, 35, -1, 23, 86, -1, -1, 83, 86, -1,
- 26, -1, 27, -1, 5, 35, -1, 8, 35, -1,
- 15, 35, -1, 35, -1, 85, 35, -1, -1, 14,
- 87, -1, 88, -1, 88, 29, 88, -1, 88, 30,
- 88, -1, 88, 31, 88, -1, 88, 32, 88, -1,
- 88, 38, 88, -1, 88, 28, 88, -1, 34, 87,
- 33, -1, 39, 87, -1, 87, 36, 87, -1, 87,
- 37, 87, -1, 26, -1, 27, -1, -1, 26, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 108, 108, 108, 110, 110, 112, 114, 115, 116,
- 117, 118, 119, 123, 127, 127, 127, 127, 127, 127,
- 127, 127, 131, 132, 133, 134, 135, 136, 140, 141,
- 147, 155, 161, 169, 179, 181, 182, 183, 184, 185,
- 186, 189, 197, 203, 213, 219, 225, 228, 230, 241,
- 242, 247, 256, 261, 269, 272, 274, 275, 276, 277,
- 278, 281, 287, 298, 304, 314, 316, 321, 329, 337,
- 340, 342, 343, 344, 349, 356, 363, 368, 376, 379,
- 381, 382, 383, 386, 394, 401, 408, 414, 421, 423,
- 424, 425, 428, 436, 438, 439, 442, 449, 451, 456,
- 457, 460, 461, 462, 466, 467, 470, 471, 474, 475,
- 476, 477, 478, 479, 480, 481, 482, 483, 484, 487,
- 488, 491, 492
+ 0, 110, 110, 110, 112, 112, 114, 116, 117, 118,
+ 119, 120, 121, 125, 129, 129, 129, 129, 129, 129,
+ 129, 129, 129, 129, 133, 134, 135, 136, 137, 138,
+ 142, 143, 149, 157, 163, 171, 181, 183, 184, 185,
+ 186, 187, 188, 191, 199, 205, 215, 221, 227, 233,
+ 239, 242, 244, 255, 256, 261, 270, 275, 283, 286,
+ 288, 289, 290, 291, 292, 295, 301, 312, 318, 328,
+ 330, 335, 343, 351, 354, 356, 357, 358, 363, 370,
+ 377, 382, 390, 393, 395, 396, 397, 400, 408, 415,
+ 422, 428, 435, 437, 438, 439, 442, 450, 452, 453,
+ 456, 463, 465, 470, 471, 474, 475, 476, 480, 481,
+ 484, 485, 488, 489, 490, 491, 492, 493, 494, 495,
+ 496, 497, 498, 501, 502, 505, 506
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 0
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
@@ -571,274 +538,271 @@ static const char *const yytname[] =
"$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
"T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
"T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
- "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
- "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
- "T_LESS", "T_LESS_EQUAL", "T_GREATER", "T_GREATER_EQUAL",
- "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
- "T_NOT", "$accept", "input", "start", "stmt_list", "option_name",
- "common_stmt", "option_error", "config_entry_start", "config_stmt",
- "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
- "config_option", "symbol_option", "symbol_option_list",
- "symbol_option_arg", "choice", "choice_entry", "choice_end",
- "choice_stmt", "choice_option_list", "choice_option", "choice_block",
- "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu",
- "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt",
- "comment", "comment_stmt", "help_start", "help", "depends_list",
- "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt",
- "end", "nl", "if_expr", "expr", "symbol", "word_opt", YY_NULL
+ "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_IMPLY",
+ "T_SUGGEST", "T_RANGE", "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD",
+ "T_WORD_QUOTE", "T_UNEQUAL", "T_LESS", "T_LESS_EQUAL", "T_GREATER",
+ "T_GREATER_EQUAL", "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR",
+ "T_AND", "T_EQUAL", "T_NOT", "$accept", "input", "start", "stmt_list",
+ "option_name", "common_stmt", "option_error", "config_entry_start",
+ "config_stmt", "menuconfig_entry_start", "menuconfig_stmt",
+ "config_option_list", "config_option", "symbol_option",
+ "symbol_option_list", "symbol_option_arg", "choice", "choice_entry",
+ "choice_end", "choice_stmt", "choice_option_list", "choice_option",
+ "choice_block", "if_entry", "if_end", "if_stmt", "if_block",
+ "mainmenu_stmt", "menu", "menu_entry", "menu_end", "menu_stmt",
+ "menu_block", "source_stmt", "comment", "comment_stmt", "help_start",
+ "help", "depends_list", "depends", "visibility_list", "visible",
+ "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol",
+ "word_opt", YY_NULLPTR
};
#endif
# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
static const yytype_uint16 yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 291, 292, 293, 294
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296
};
# endif
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
+#define YYPACT_NINF -101
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-101)))
+
+#define YYTABLE_NINF -90
+
+#define yytable_value_is_error(Yytable_value) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
{
- 0, 40, 41, 41, 42, 42, 43, 43, 43, 43,
- 43, 43, 43, 43, 44, 44, 44, 44, 44, 44,
- 44, 44, 45, 45, 45, 45, 45, 45, 46, 46,
- 47, 48, 49, 50, 51, 51, 51, 51, 51, 51,
- 51, 52, 52, 52, 52, 52, 53, 54, 54, 55,
- 55, 56, 57, 58, 59, 60, 60, 60, 60, 60,
- 60, 61, 61, 61, 61, 62, 62, 63, 64, 65,
- 66, 66, 66, 66, 67, 68, 69, 70, 71, 72,
- 72, 72, 72, 73, 74, 75, 76, 77, 78, 78,
- 78, 78, 79, 80, 80, 80, 81, 82, 82, 83,
- 83, 84, 84, 84, 85, 85, 86, 86, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 88,
- 88, 89, 89
+ 19, 79, -101, 15, -101, 153, -101, 20, -101, -101,
+ -18, -101, 17, 79, 25, 79, 51, 65, 79, 53,
+ 85, 44, 84, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, 131, -101, 145, -101, -101, -101, -101,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, 199, -101, -101, 118, -101, 149, -101,
+ 150, -101, 160, -101, 175, 188, 189, -101, -101, 44,
+ 44, 78, 161, -101, 191, 192, 27, 119, 81, 174,
+ 273, -16, 273, 233, -101, -101, -101, -101, -101, -101,
+ -9, -101, 44, 44, 118, 123, 123, 123, 123, 123,
+ 123, -101, -101, 193, 194, 205, 79, 79, 44, 207,
+ 217, 218, 123, -101, 259, -101, -101, -101, -101, 262,
+ -101, -101, 234, 79, 79, 248, -101, -101, -101, -101,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, 271,
+ -101, 258, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, 250, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, 44, 271, 253, 271, 45, 271, 271, 271,
+ 123, 33, 254, -101, -101, 271, 255, 271, 44, -101,
+ 111, 256, -101, -101, 257, 260, 261, 263, 271, 264,
+ -101, -101, 265, -101, 266, 127, -101, -101, -101, -101,
+ -101, -101, 268, 79, -101, -101, -101, -101, -101
};
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
{
- 0, 2, 2, 1, 2, 1, 0, 2, 2, 2,
- 2, 4, 4, 3, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 3, 2,
- 3, 2, 3, 2, 0, 2, 2, 2, 2, 2,
- 2, 3, 4, 4, 4, 5, 3, 0, 3, 0,
- 2, 3, 2, 1, 3, 0, 2, 2, 2, 2,
- 2, 4, 3, 2, 4, 0, 2, 3, 1, 3,
- 0, 2, 2, 2, 3, 3, 3, 1, 3, 0,
- 2, 2, 2, 3, 3, 2, 2, 2, 0, 2,
- 2, 2, 4, 0, 2, 2, 2, 0, 2, 1,
- 1, 2, 2, 2, 1, 2, 0, 2, 1, 3,
- 3, 3, 3, 3, 3, 3, 2, 3, 3, 1,
- 1, 0, 1
+ 6, 0, 108, 0, 3, 0, 6, 6, 103, 104,
+ 0, 1, 0, 0, 0, 0, 125, 0, 0, 0,
+ 0, 0, 0, 14, 20, 15, 16, 22, 17, 18,
+ 19, 21, 23, 0, 24, 0, 7, 36, 27, 36,
+ 28, 59, 69, 8, 74, 25, 97, 83, 9, 29,
+ 92, 26, 10, 0, 109, 2, 78, 13, 0, 105,
+ 0, 126, 0, 106, 0, 0, 0, 123, 124, 0,
+ 0, 0, 112, 107, 0, 0, 0, 0, 0, 0,
+ 0, 92, 0, 0, 79, 87, 55, 88, 32, 34,
+ 0, 120, 0, 0, 71, 0, 0, 0, 0, 0,
+ 0, 11, 12, 0, 0, 0, 0, 101, 0, 0,
+ 0, 0, 0, 51, 0, 42, 41, 37, 38, 0,
+ 40, 39, 0, 0, 101, 0, 63, 64, 60, 62,
+ 61, 70, 58, 57, 75, 77, 73, 76, 72, 110,
+ 99, 0, 98, 84, 86, 82, 85, 81, 94, 95,
+ 93, 119, 121, 122, 118, 113, 114, 115, 116, 117,
+ 31, 90, 0, 110, 0, 110, 110, 110, 110, 110,
+ 0, 0, 0, 91, 67, 110, 0, 110, 0, 100,
+ 0, 0, 43, 102, 0, 0, 0, 0, 110, 53,
+ 50, 30, 0, 66, 0, 111, 96, 44, 45, 46,
+ 47, 48, 0, 0, 52, 65, 68, 49, 54
};
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
- Performed when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
{
- 6, 0, 104, 0, 3, 0, 6, 6, 99, 100,
- 0, 1, 0, 0, 0, 0, 121, 0, 0, 0,
- 0, 0, 0, 14, 18, 15, 16, 20, 17, 19,
- 21, 0, 22, 0, 7, 34, 25, 34, 26, 55,
- 65, 8, 70, 23, 93, 79, 9, 27, 88, 24,
- 10, 0, 105, 2, 74, 13, 0, 101, 0, 122,
- 0, 102, 0, 0, 0, 119, 120, 0, 0, 0,
- 108, 103, 0, 0, 0, 0, 0, 0, 0, 88,
- 0, 0, 75, 83, 51, 84, 30, 32, 0, 116,
- 0, 0, 67, 0, 0, 0, 0, 0, 0, 11,
- 12, 0, 0, 0, 0, 97, 0, 0, 0, 47,
- 0, 40, 39, 35, 36, 0, 38, 37, 0, 0,
- 97, 0, 59, 60, 56, 58, 57, 66, 54, 53,
- 71, 73, 69, 72, 68, 106, 95, 0, 94, 80,
- 82, 78, 81, 77, 90, 91, 89, 115, 117, 118,
- 114, 109, 110, 111, 112, 113, 29, 86, 0, 106,
- 0, 106, 106, 106, 0, 0, 0, 87, 63, 106,
- 0, 106, 0, 96, 0, 0, 41, 98, 0, 0,
- 106, 49, 46, 28, 0, 62, 0, 107, 92, 42,
- 43, 44, 0, 0, 48, 61, 64, 45, 50
+ -101, -101, 289, 293, -101, 24, -67, -101, -101, -101,
+ -101, 267, -101, -101, -101, -101, -101, -101, -101, -22,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, 116, -101, -101, -101, -101, -101, 223, 226, -65,
+ -101, -101, 184, -1, 32, 0, -100, -68, -92, -101
};
-/* YYDEFGOTO[NTERM-NUM]. */
+ /* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 3, 4, 5, 33, 34, 112, 35, 36, 37,
- 38, 74, 113, 114, 165, 194, 39, 40, 128, 41,
- 76, 124, 77, 42, 132, 43, 78, 6, 44, 45,
- 141, 46, 80, 47, 48, 49, 115, 116, 81, 117,
- 79, 138, 160, 161, 50, 7, 173, 69, 70, 60
+ -1, 3, 4, 5, 35, 36, 116, 37, 38, 39,
+ 40, 76, 117, 118, 171, 204, 41, 42, 132, 43,
+ 78, 128, 79, 44, 136, 45, 80, 6, 46, 47,
+ 145, 48, 82, 49, 50, 51, 119, 120, 83, 121,
+ 81, 142, 164, 165, 52, 7, 179, 71, 72, 62
};
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -91
-static const yytype_int16 yypact[] =
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int16 yytable[] =
{
- 19, 37, -91, 13, -91, 79, -91, 20, -91, -91,
- -16, -91, 21, 37, 25, 37, 41, 36, 37, 78,
- 83, 31, 56, -91, -91, -91, -91, -91, -91, -91,
- -91, 116, -91, 127, -91, -91, -91, -91, -91, -91,
- -91, -91, -91, -91, -91, -91, -91, -91, -91, -91,
- -91, 147, -91, -91, 105, -91, 109, -91, 111, -91,
- 114, -91, 136, 137, 142, -91, -91, 31, 31, 76,
- 254, -91, 143, 146, 27, 115, 207, 258, 243, -14,
- 243, 179, -91, -91, -91, -91, -91, -91, -7, -91,
- 31, 31, 105, 51, 51, 51, 51, 51, 51, -91,
- -91, 156, 168, 181, 37, 37, 31, 178, 51, -91,
- 206, -91, -91, -91, -91, 196, -91, -91, 175, 37,
- 37, 185, -91, -91, -91, -91, -91, -91, -91, -91,
- -91, -91, -91, -91, -91, 214, -91, 230, -91, -91,
- -91, -91, -91, -91, -91, -91, -91, -91, 183, -91,
- -91, -91, -91, -91, -91, -91, -91, -91, 31, 214,
- 194, 214, 45, 214, 51, 26, 195, -91, -91, 214,
- 197, 214, 31, -91, 139, 208, -91, -91, 220, 224,
- 214, 222, -91, -91, 226, -91, 227, 123, -91, -91,
- -91, -91, 235, 37, -91, -91, -91, -91, -91
+ 10, 90, 91, 154, 155, 156, 157, 158, 159, 139,
+ 56, 127, 58, 130, 60, 11, 149, 64, 150, 2,
+ 170, 140, 1, 1, 152, 153, 151, -33, 103, 92,
+ 93, -33, -33, -33, -33, -33, -33, -33, -33, 104,
+ 166, -33, -33, 105, -33, 106, 107, 108, 109, 110,
+ 111, 112, -33, 113, 57, 114, 2, 54, 135, 178,
+ 144, 189, 59, 181, 115, 183, 184, 185, 186, 187,
+ 190, 94, 67, 68, 149, 192, 150, 194, 188, 61,
+ 69, 65, 103, 92, 93, 70, -56, -56, 202, -56,
+ -56, -56, -56, 104, 180, -56, -56, 105, 122, 123,
+ 124, 125, 63, 131, 134, 163, 143, 8, 9, 114,
+ 195, 133, 138, 66, 147, 2, 92, 93, 126, -35,
+ 103, 73, 175, -35, -35, -35, -35, -35, -35, -35,
+ -35, 104, 74, -35, -35, 105, -35, 106, 107, 108,
+ 109, 110, 111, 112, -35, 113, 75, 114, 196, 92,
+ 93, 67, 68, -5, 12, 54, 115, 13, 14, 15,
+ 16, 17, 18, 19, 20, 92, 93, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 14,
+ 15, 33, 17, 18, 19, 20, 84, 85, 21, 22,
+ 34, 95, 96, 97, 98, 99, 137, 86, 146, -4,
+ 12, 100, 208, 13, 14, 15, 16, 17, 18, 19,
+ 20, 34, 87, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 88, 89, 33, 101, 102,
+ 160, 161, 162, -89, 103, 167, 34, -89, -89, -89,
+ -89, -89, -89, -89, -89, 168, 169, -89, -89, 105,
+ -89, -89, -89, -89, -89, -89, -89, -89, -89, 103,
+ 172, 114, -80, -80, -80, -80, -80, -80, -80, -80,
+ 148, 174, -80, -80, 105, 173, 177, 13, 14, 15,
+ 16, 17, 18, 19, 20, 178, 114, 21, 22, 93,
+ 182, 191, 193, 197, 198, 148, 55, 199, 200, 53,
+ 201, 129, 205, 206, 203, 207, 77, 141, 176, 0,
+ 34
};
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
+static const yytype_int16 yycheck[] =
{
- -91, -91, 264, 268, -91, 30, -65, -91, -91, -91,
- -91, 238, -91, -91, -91, -91, -91, -91, -91, -12,
- -91, -91, -91, -91, -91, -91, -91, -91, -91, -91,
- -91, -5, -91, -91, -91, -91, -91, 200, 209, -61,
- -91, -91, 170, -1, 65, 0, 118, -66, -90, -91
+ 1, 69, 70, 95, 96, 97, 98, 99, 100, 25,
+ 10, 78, 13, 78, 15, 0, 83, 18, 83, 37,
+ 112, 37, 3, 3, 92, 93, 35, 0, 1, 38,
+ 39, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 108, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 37, 28, 37, 37, 80, 14,
+ 82, 28, 37, 163, 37, 165, 166, 167, 168, 169,
+ 37, 71, 28, 29, 141, 175, 141, 177, 170, 28,
+ 36, 28, 1, 38, 39, 41, 5, 6, 188, 8,
+ 9, 10, 11, 12, 162, 14, 15, 16, 17, 18,
+ 19, 20, 37, 79, 80, 106, 82, 28, 29, 28,
+ 178, 79, 80, 28, 82, 37, 38, 39, 37, 0,
+ 1, 37, 123, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 1, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 1, 28, 37, 38,
+ 39, 28, 29, 0, 1, 37, 37, 4, 5, 6,
+ 7, 8, 9, 10, 11, 38, 39, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 5,
+ 6, 28, 8, 9, 10, 11, 37, 37, 14, 15,
+ 37, 30, 31, 32, 33, 34, 80, 37, 82, 0,
+ 1, 40, 203, 4, 5, 6, 7, 8, 9, 10,
+ 11, 37, 37, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 37, 37, 28, 37, 37,
+ 37, 37, 27, 0, 1, 28, 37, 4, 5, 6,
+ 7, 8, 9, 10, 11, 28, 28, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 1,
+ 1, 28, 4, 5, 6, 7, 8, 9, 10, 11,
+ 37, 37, 14, 15, 16, 13, 28, 4, 5, 6,
+ 7, 8, 9, 10, 11, 14, 28, 14, 15, 39,
+ 37, 37, 37, 37, 37, 37, 7, 37, 37, 6,
+ 37, 78, 37, 37, 40, 37, 39, 81, 124, -1,
+ 37
};
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -86
-static const yytype_int16 yytable[] =
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
{
- 10, 88, 89, 150, 151, 152, 153, 154, 155, 135,
- 54, 123, 56, 11, 58, 126, 145, 62, 164, 2,
- 146, 136, 1, 1, 148, 149, 147, -31, 101, 90,
- 91, -31, -31, -31, -31, -31, -31, -31, -31, 102,
- 162, -31, -31, 103, -31, 104, 105, 106, 107, 108,
- -31, 109, 181, 110, 2, 52, 55, 65, 66, 172,
- 57, 182, 111, 8, 9, 67, 131, 59, 140, 92,
- 68, 61, 145, 133, 180, 142, 146, 65, 66, -5,
- 12, 90, 91, 13, 14, 15, 16, 17, 18, 19,
- 20, 71, 174, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 159, 63, 31, 187, 127, 130, 64,
- 139, 2, 90, 91, 32, -33, 101, 72, 169, -33,
- -33, -33, -33, -33, -33, -33, -33, 102, 73, -33,
- -33, 103, -33, 104, 105, 106, 107, 108, -33, 109,
- 52, 110, 129, 134, 82, 143, 83, -4, 12, 84,
- 111, 13, 14, 15, 16, 17, 18, 19, 20, 90,
- 91, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 85, 86, 31, 188, 90, 91, 87, 99, -85,
- 101, 100, 32, -85, -85, -85, -85, -85, -85, -85,
- -85, 156, 198, -85, -85, 103, -85, -85, -85, -85,
- -85, -85, -85, 157, 163, 110, 158, 166, 101, 167,
- 168, 171, -52, -52, 144, -52, -52, -52, -52, 102,
- 91, -52, -52, 103, 118, 119, 120, 121, 172, 176,
- 183, 101, 185, 110, -76, -76, -76, -76, -76, -76,
- -76, -76, 122, 189, -76, -76, 103, 13, 14, 15,
- 16, 17, 18, 19, 20, 190, 110, 21, 22, 191,
- 193, 195, 196, 14, 15, 144, 17, 18, 19, 20,
- 197, 53, 21, 22, 51, 75, 125, 175, 32, 177,
- 178, 179, 93, 94, 95, 96, 97, 184, 137, 186,
- 170, 0, 98, 32, 0, 0, 0, 0, 192
+ 0, 3, 37, 43, 44, 45, 69, 87, 28, 29,
+ 85, 0, 1, 4, 5, 6, 7, 8, 9, 10,
+ 11, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 28, 37, 46, 47, 49, 50, 51,
+ 52, 58, 59, 61, 65, 67, 70, 71, 73, 75,
+ 76, 77, 86, 45, 37, 44, 87, 37, 85, 37,
+ 85, 28, 91, 37, 85, 28, 28, 28, 29, 36,
+ 41, 89, 90, 37, 1, 1, 53, 53, 62, 64,
+ 68, 82, 74, 80, 37, 37, 37, 37, 37, 37,
+ 89, 89, 38, 39, 87, 30, 31, 32, 33, 34,
+ 40, 37, 37, 1, 12, 16, 18, 19, 20, 21,
+ 22, 23, 24, 26, 28, 37, 48, 54, 55, 78,
+ 79, 81, 17, 18, 19, 20, 37, 48, 63, 79,
+ 81, 47, 60, 86, 47, 61, 66, 73, 86, 25,
+ 37, 80, 83, 47, 61, 72, 73, 86, 37, 48,
+ 81, 35, 89, 89, 90, 90, 90, 90, 90, 90,
+ 37, 37, 27, 85, 84, 85, 89, 28, 28, 28,
+ 90, 56, 1, 13, 37, 85, 84, 28, 14, 88,
+ 89, 88, 37, 88, 88, 88, 88, 88, 90, 28,
+ 37, 37, 88, 37, 88, 89, 37, 37, 37, 37,
+ 37, 37, 88, 40, 57, 37, 37, 37, 85
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-91))
-
-#define yytable_value_is_error(yytable_value) \
- YYID (0)
-
-static const yytype_int16 yycheck[] =
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
{
- 1, 67, 68, 93, 94, 95, 96, 97, 98, 23,
- 10, 76, 13, 0, 15, 76, 81, 18, 108, 35,
- 81, 35, 3, 3, 90, 91, 33, 0, 1, 36,
- 37, 4, 5, 6, 7, 8, 9, 10, 11, 12,
- 106, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 24, 26, 26, 35, 35, 35, 26, 27, 14,
- 35, 35, 35, 26, 27, 34, 78, 26, 80, 69,
- 39, 35, 137, 78, 164, 80, 137, 26, 27, 0,
- 1, 36, 37, 4, 5, 6, 7, 8, 9, 10,
- 11, 35, 158, 14, 15, 16, 17, 18, 19, 20,
- 21, 22, 23, 104, 26, 26, 172, 77, 78, 26,
- 80, 35, 36, 37, 35, 0, 1, 1, 119, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 1, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 35, 26, 77, 78, 35, 80, 35, 0, 1, 35,
- 35, 4, 5, 6, 7, 8, 9, 10, 11, 36,
- 37, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 35, 35, 26, 35, 36, 37, 35, 35, 0,
- 1, 35, 35, 4, 5, 6, 7, 8, 9, 10,
- 11, 35, 193, 14, 15, 16, 17, 18, 19, 20,
- 21, 22, 23, 35, 26, 26, 25, 1, 1, 13,
- 35, 26, 5, 6, 35, 8, 9, 10, 11, 12,
- 37, 14, 15, 16, 17, 18, 19, 20, 14, 35,
- 35, 1, 35, 26, 4, 5, 6, 7, 8, 9,
- 10, 11, 35, 35, 14, 15, 16, 4, 5, 6,
- 7, 8, 9, 10, 11, 35, 26, 14, 15, 35,
- 38, 35, 35, 5, 6, 35, 8, 9, 10, 11,
- 35, 7, 14, 15, 6, 37, 76, 159, 35, 161,
- 162, 163, 28, 29, 30, 31, 32, 169, 79, 171,
- 120, -1, 38, 35, -1, -1, -1, -1, 180
+ 0, 42, 43, 43, 44, 44, 45, 45, 45, 45,
+ 45, 45, 45, 45, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46, 47, 47, 47, 47, 47, 47,
+ 48, 48, 49, 50, 51, 52, 53, 53, 53, 53,
+ 53, 53, 53, 54, 54, 54, 54, 54, 54, 54,
+ 55, 56, 56, 57, 57, 58, 59, 60, 61, 62,
+ 62, 62, 62, 62, 62, 63, 63, 63, 63, 64,
+ 64, 65, 66, 67, 68, 68, 68, 68, 69, 70,
+ 71, 72, 73, 74, 74, 74, 74, 75, 76, 77,
+ 78, 79, 80, 80, 80, 80, 81, 82, 82, 82,
+ 83, 84, 84, 85, 85, 86, 86, 86, 87, 87,
+ 88, 88, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 90, 90, 91, 91
};
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
{
- 0, 3, 35, 41, 42, 43, 67, 85, 26, 27,
- 83, 0, 1, 4, 5, 6, 7, 8, 9, 10,
- 11, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 26, 35, 44, 45, 47, 48, 49, 50, 56,
- 57, 59, 63, 65, 68, 69, 71, 73, 74, 75,
- 84, 43, 35, 42, 85, 35, 83, 35, 83, 26,
- 89, 35, 83, 26, 26, 26, 27, 34, 39, 87,
- 88, 35, 1, 1, 51, 51, 60, 62, 66, 80,
- 72, 78, 35, 35, 35, 35, 35, 35, 87, 87,
- 36, 37, 85, 28, 29, 30, 31, 32, 38, 35,
- 35, 1, 12, 16, 18, 19, 20, 21, 22, 24,
- 26, 35, 46, 52, 53, 76, 77, 79, 17, 18,
- 19, 20, 35, 46, 61, 77, 79, 45, 58, 84,
- 45, 59, 64, 71, 84, 23, 35, 78, 81, 45,
- 59, 70, 71, 84, 35, 46, 79, 33, 87, 87,
- 88, 88, 88, 88, 88, 88, 35, 35, 25, 83,
- 82, 83, 87, 26, 88, 54, 1, 13, 35, 83,
- 82, 26, 14, 86, 87, 86, 35, 86, 86, 86,
- 88, 26, 35, 35, 86, 35, 86, 87, 35, 35,
- 35, 35, 86, 38, 55, 35, 35, 35, 83
+ 0, 2, 2, 1, 2, 1, 0, 2, 2, 2,
+ 2, 4, 4, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 2, 3, 2, 3, 2, 0, 2, 2, 2,
+ 2, 2, 2, 3, 4, 4, 4, 4, 4, 5,
+ 3, 0, 3, 0, 2, 3, 2, 1, 3, 0,
+ 2, 2, 2, 2, 2, 4, 3, 2, 4, 0,
+ 2, 3, 1, 3, 0, 2, 2, 2, 3, 3,
+ 3, 1, 3, 0, 2, 2, 2, 3, 3, 2,
+ 2, 2, 0, 2, 2, 2, 4, 0, 2, 2,
+ 2, 0, 2, 1, 1, 2, 2, 2, 1, 2,
+ 0, 2, 1, 3, 3, 3, 3, 3, 3, 3,
+ 2, 3, 3, 1, 1, 0, 1
};
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. However,
- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
- discussed. */
-
-#define YYFAIL goto yyerrlab
-#if defined YYFAIL
- /* This is here to suppress warnings from the GCC cpp's
- -Wunused-macros. Normally we don't worry about that warning, but
- some users do, and we want to make it easy for users to remove
- YYFAIL uses, which will produce warnings from Bison 2.5. */
-#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
#define YYRECOVERING() (!!yyerrstatus)
@@ -855,55 +819,15 @@ do \
else \
{ \
yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* This macro is provided for backward compatibility. */
-
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
+ YYERROR; \
+ } \
+while (0)
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
-/* YYLEX -- calling `yylex' with the right arguments. */
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
/* Enable debugging if requested. */
#if YYDEBUG
@@ -913,40 +837,36 @@ while (YYID (0))
# define YYFPRINTF fprintf
# endif
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT. |
+`----------------------------------------*/
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
static void
yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
{
FILE *yyo = yyoutput;
YYUSE (yyo);
@@ -955,14 +875,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
# ifdef YYPRINT
if (yytype < YYNTOKENS)
YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
# endif
- switch (yytype)
- {
- default:
- break;
- }
+ YYUSE (yytype);
}
@@ -970,22 +884,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
| Print this symbol on YYOUTPUT. |
`--------------------------------*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
static void
yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+ YYFPRINTF (yyoutput, "%s %s (",
+ yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
yy_symbol_value_print (yyoutput, yytype, yyvaluep);
YYFPRINTF (yyoutput, ")");
@@ -996,16 +899,8 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
| TOP (included). |
`------------------------------------------------------------------*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
static void
yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
-#endif
{
YYFPRINTF (stderr, "Stack now");
for (; yybottom <= yytop; yybottom++)
@@ -1016,49 +911,42 @@ yy_stack_print (yybottom, yytop)
YYFPRINTF (stderr, "\n");
}
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
{
+ unsigned long int yylno = yyrline[yyrule];
int yynrhs = yyr2[yyrule];
int yyi;
- unsigned long int yylno = yyrline[yyrule];
YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
+ yyrule - 1, yylno);
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
YYFPRINTF (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
+ yy_symbol_print (stderr,
+ yystos[yyssp[yyi + 1 - yynrhs]],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
YYFPRINTF (stderr, "\n");
}
}
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule); \
+} while (0)
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
@@ -1072,7 +960,7 @@ int yydebug;
/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
+#ifndef YYINITDEPTH
# define YYINITDEPTH 200
#endif
@@ -1095,15 +983,8 @@ int yydebug;
# define yystrlen strlen
# else
/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
static YYSIZE_T
yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
{
YYSIZE_T yylen;
for (yylen = 0; yystr[yylen]; yylen++)
@@ -1119,16 +1000,8 @@ yystrlen (yystr)
# else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
static char *
yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
{
char *yyd = yydest;
const char *yys = yysrc;
@@ -1158,27 +1031,27 @@ yytnamerr (char *yyres, const char *yystr)
char const *yyp = yystr;
for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
do_not_strip_quotes: ;
}
@@ -1201,12 +1074,11 @@ static int
yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
yytype_int16 *yyssp, int yytoken)
{
- YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
/* Internationalized format string. */
- const char *yyformat = YY_NULL;
+ const char *yyformat = YY_NULLPTR;
/* Arguments of yyformat. */
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
/* Number of reported tokens (one for the "unexpected", one per
@@ -1214,10 +1086,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
int yycount = 0;
/* There are many possibilities here to consider:
- - Assume YYFAIL is not used. It's too flawed to consider. See
- <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
- for details. YYERROR is fine as it does not invoke this
- function.
- If this state is a consistent state with a default action, then
the only way this function was invoked is if the default action
is an error action. In that case, don't check for expected
@@ -1266,11 +1134,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
break;
}
yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
}
}
}
@@ -1290,10 +1160,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
# undef YYCASE_
}
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
if (*yymsg_alloc < yysize)
{
@@ -1330,78 +1202,58 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
static void
yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
{
YYUSE (yyvaluep);
-
if (!yymsg)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
switch (yytype)
{
- case 57: /* "choice_entry" */
+ case 59: /* choice_entry */
- {
+ {
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
- (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
- if (current_menu == (yyvaluep->menu))
+ ((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
+ if (current_menu == ((*yyvaluep).menu))
menu_end_menu();
-};
+}
+
+ break;
- break;
- case 63: /* "if_entry" */
+ case 65: /* if_entry */
- {
+ {
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
- (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
- if (current_menu == (yyvaluep->menu))
+ ((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
+ if (current_menu == ((*yyvaluep).menu))
menu_end_menu();
-};
+}
- break;
- case 69: /* "menu_entry" */
+ break;
- {
+ case 71: /* menu_entry */
+
+ {
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
- (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
- if (current_menu == (yyvaluep->menu))
+ ((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
+ if (current_menu == ((*yyvaluep).menu))
menu_end_menu();
-};
+}
+
+ break;
- break;
default:
- break;
+ break;
}
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
}
-/* Prevent warnings from -Wmissing-prototypes. */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
/* The lookahead symbol. */
@@ -1409,7 +1261,6 @@ int yychar;
/* The semantic value of the lookahead symbol. */
YYSTYPE yylval;
-
/* Number of syntax errors so far. */
int yynerrs;
@@ -1418,35 +1269,16 @@ int yynerrs;
| yyparse. |
`----------*/
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
int
yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
{
int yystate;
/* Number of tokens to shift before error messages enabled. */
int yyerrstatus;
/* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
+ 'yyss': related to states.
+ 'yyvs': related to semantic values.
Refer to the stacks through separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
@@ -1466,7 +1298,7 @@ yyparse ()
int yyn;
int yyresult;
/* Lookahead token as an internal (translated) token number. */
- int yytoken;
+ int yytoken = 0;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
@@ -1484,9 +1316,8 @@ yyparse ()
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1495,14 +1326,6 @@ yyparse ()
yyerrstatus = 0;
yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
-
goto yysetstate;
/*------------------------------------------------------------.
@@ -1523,23 +1346,23 @@ yyparse ()
#ifdef yyoverflow
{
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
}
#else /* no yyoverflow */
# ifndef YYSTACK_RELOCATE
@@ -1547,22 +1370,22 @@ yyparse ()
# else
/* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
+ goto yyexhaustedlab;
yystacksize *= 2;
if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
+ yystacksize = YYMAXDEPTH;
{
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
}
# endif
#endif /* no yyoverflow */
@@ -1571,10 +1394,10 @@ yyparse ()
yyvsp = yyvs + yysize - 1;
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
+ (unsigned long int) yystacksize));
if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
+ YYABORT;
}
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
@@ -1603,7 +1426,7 @@ yybackup:
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
+ yychar = yylex ();
}
if (yychar <= YYEOF)
@@ -1643,7 +1466,9 @@ yybackup:
yychar = YYEMPTY;
yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
goto yynewstate;
@@ -1666,7 +1491,7 @@ yyreduce:
yylen = yyr2[yyn];
/* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
+ '$$ = $1'.
Otherwise, the following line sets YYVAL to garbage.
This behavior is undocumented and Bison
@@ -1682,64 +1507,73 @@ yyreduce:
case 10:
{ zconf_error("unexpected end statement"); }
+
break;
case 11:
- { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); }
+ { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); }
+
break;
case 12:
{
- zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name);
+ zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[-2].id)->name);
}
+
break;
case 13:
{ zconf_error("invalid statement"); }
+
break;
- case 28:
+ case 30:
+
+ { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); }
- { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); }
break;
- case 29:
+ case 31:
{ zconf_error("invalid option"); }
+
break;
- case 30:
+ case 32:
{
- struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+ struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
sym->flags |= SYMBOL_OPTIONAL;
menu_add_entry(sym);
- printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
}
+
break;
- case 31:
+ case 33:
{
menu_end_entry();
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 32:
+ case 34:
{
- struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+ struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
sym->flags |= SYMBOL_OPTIONAL;
menu_add_entry(sym);
- printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
}
+
break;
- case 33:
+ case 35:
{
if (current_entry->prompt)
@@ -1749,352 +1583,419 @@ yyreduce:
menu_end_entry();
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 41:
+ case 43:
{
- menu_set_type((yyvsp[(1) - (3)].id)->stype);
+ menu_set_type((yyvsp[-2].id)->stype);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
zconf_curname(), zconf_lineno(),
- (yyvsp[(1) - (3)].id)->stype);
+ (yyvsp[-2].id)->stype);
}
+
break;
- case 42:
+ case 44:
{
- menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+ menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 43:
+ case 45:
{
- menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
- if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN)
- menu_set_type((yyvsp[(1) - (4)].id)->stype);
+ menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr));
+ if ((yyvsp[-3].id)->stype != S_UNKNOWN)
+ menu_set_type((yyvsp[-3].id)->stype);
printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
zconf_curname(), zconf_lineno(),
- (yyvsp[(1) - (4)].id)->stype);
+ (yyvsp[-3].id)->stype);
}
+
break;
- case 44:
+ case 46:
{
- menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+ menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 45:
+ case 47:
{
- menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
- printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+ menu_add_symbol(P_IMPLY, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+ printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
}
+
break;
case 48:
{
- const struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string)));
+ menu_add_symbol(P_SUGGEST, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+ printd(DEBUG_PARSE, "%s:%d:suggest\n", zconf_curname(), zconf_lineno());
+}
+
+ break;
+
+ case 49:
+
+ {
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr));
+ printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+}
+
+ break;
+
+ case 52:
+
+ {
+ const struct kconf_id *id = kconf_id_lookup((yyvsp[-1].string), strlen((yyvsp[-1].string)));
if (id && id->flags & TF_OPTION)
- menu_add_option(id->token, (yyvsp[(3) - (3)].string));
+ menu_add_option(id->token, (yyvsp[0].string));
else
- zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string));
- free((yyvsp[(2) - (3)].string));
+ zconfprint("warning: ignoring unknown option %s", (yyvsp[-1].string));
+ free((yyvsp[-1].string));
}
+
break;
- case 49:
+ case 53:
{ (yyval.string) = NULL; }
+
break;
- case 50:
+ case 54:
+
+ { (yyval.string) = (yyvsp[0].string); }
- { (yyval.string) = (yyvsp[(2) - (2)].string); }
break;
- case 51:
+ case 55:
{
- struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE);
+ struct symbol *sym = sym_lookup((yyvsp[-1].string), SYMBOL_CHOICE);
sym->flags |= SYMBOL_AUTO;
menu_add_entry(sym);
menu_add_expr(P_CHOICE, NULL, NULL);
printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 52:
+ case 56:
{
(yyval.menu) = menu_add_menu();
}
+
break;
- case 53:
+ case 57:
{
- if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) {
+ if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
}
}
+
break;
- case 61:
+ case 65:
{
- menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+ menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 62:
+ case 66:
{
- if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) {
- menu_set_type((yyvsp[(1) - (3)].id)->stype);
+ if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) {
+ menu_set_type((yyvsp[-2].id)->stype);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
zconf_curname(), zconf_lineno(),
- (yyvsp[(1) - (3)].id)->stype);
+ (yyvsp[-2].id)->stype);
} else
YYERROR;
}
+
break;
- case 63:
+ case 67:
{
current_entry->sym->flags |= SYMBOL_OPTIONAL;
printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 64:
+ case 68:
{
- if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) {
- menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+ if ((yyvsp[-3].id)->stype == S_UNKNOWN) {
+ menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
printd(DEBUG_PARSE, "%s:%d:default\n",
zconf_curname(), zconf_lineno());
} else
YYERROR;
}
+
break;
- case 67:
+ case 71:
{
printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
menu_add_entry(NULL);
- menu_add_dep((yyvsp[(2) - (3)].expr));
+ menu_add_dep((yyvsp[-1].expr));
(yyval.menu) = menu_add_menu();
}
+
break;
- case 68:
+ case 72:
{
- if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) {
+ if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
}
}
+
break;
- case 74:
+ case 78:
{
- menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+ menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
}
+
break;
- case 75:
+ case 79:
{
menu_add_entry(NULL);
- menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+ menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 76:
+ case 80:
{
(yyval.menu) = menu_add_menu();
}
+
break;
- case 77:
+ case 81:
{
- if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) {
+ if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
}
}
+
break;
- case 83:
+ case 87:
{
- printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
- zconf_nextfile((yyvsp[(2) - (3)].string));
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+ zconf_nextfile((yyvsp[-1].string));
}
+
break;
- case 84:
+ case 88:
{
menu_add_entry(NULL);
- menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
+ menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL);
printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 85:
+ case 89:
{
menu_end_entry();
}
+
break;
- case 86:
+ case 90:
{
printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
zconf_starthelp();
}
+
break;
- case 87:
+ case 91:
{
- current_entry->help = (yyvsp[(2) - (2)].string);
+ current_entry->help = (yyvsp[0].string);
}
+
break;
- case 92:
+ case 96:
{
- menu_add_dep((yyvsp[(3) - (4)].expr));
+ menu_add_dep((yyvsp[-1].expr));
printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
}
+
break;
- case 96:
+ case 100:
{
- menu_add_visibility((yyvsp[(2) - (2)].expr));
+ menu_add_visibility((yyvsp[0].expr));
}
+
break;
- case 98:
+ case 102:
{
- menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
+ menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr));
}
- break;
-
- case 101:
- { (yyval.id) = (yyvsp[(1) - (2)].id); }
break;
- case 102:
-
- { (yyval.id) = (yyvsp[(1) - (2)].id); }
- break;
+ case 105:
- case 103:
+ { (yyval.id) = (yyvsp[-1].id); }
- { (yyval.id) = (yyvsp[(1) - (2)].id); }
break;
case 106:
- { (yyval.expr) = NULL; }
- break;
-
- case 107:
+ { (yyval.id) = (yyvsp[-1].id); }
- { (yyval.expr) = (yyvsp[(2) - (2)].expr); }
break;
- case 108:
-
- { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); }
- break;
+ case 107:
- case 109:
+ { (yyval.id) = (yyvsp[-1].id); }
- { (yyval.expr) = expr_alloc_comp(E_LTH, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
break;
case 110:
- { (yyval.expr) = expr_alloc_comp(E_LEQ, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
+ { (yyval.expr) = NULL; }
+
break;
case 111:
- { (yyval.expr) = expr_alloc_comp(E_GTH, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
+ { (yyval.expr) = (yyvsp[0].expr); }
+
break;
case 112:
- { (yyval.expr) = expr_alloc_comp(E_GEQ, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
+ { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); }
+
break;
case 113:
- { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
+ { (yyval.expr) = expr_alloc_comp(E_LTH, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
break;
case 114:
- { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
+ { (yyval.expr) = expr_alloc_comp(E_LEQ, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
break;
case 115:
- { (yyval.expr) = (yyvsp[(2) - (3)].expr); }
+ { (yyval.expr) = expr_alloc_comp(E_GTH, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
break;
case 116:
- { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); }
+ { (yyval.expr) = expr_alloc_comp(E_GEQ, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
break;
case 117:
- { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); }
+ { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
break;
case 118:
- { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); }
+ { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
break;
case 119:
- { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); }
+ { (yyval.expr) = (yyvsp[-1].expr); }
+
break;
case 120:
- { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); }
+ { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); }
+
break;
case 121:
+ { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); }
+
+ break;
+
+ case 122:
+
+ { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); }
+
+ break;
+
+ case 123:
+
+ { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); }
+
+ break;
+
+ case 124:
+
+ { (yyval.symbol) = sym_lookup((yyvsp[0].string), SYMBOL_CONST); free((yyvsp[0].string)); }
+
+ break;
+
+ case 125:
+
{ (yyval.string) = NULL; }
+
break;
@@ -2120,7 +2021,7 @@ yyreduce:
*++yyvsp = yyval;
- /* Now `shift' the result of the reduction. Determine what state
+ /* Now 'shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -2135,9 +2036,9 @@ yyreduce:
goto yynewstate;
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
yyerrlab:
/* Make sure we have latest lookahead translation. See comments at
user semantic actions for why this is necessary. */
@@ -2188,20 +2089,20 @@ yyerrlab:
if (yyerrstatus == 3)
{
/* If just tried and failed to reuse lookahead token after an
- error, discard it. */
+ error, discard it. */
if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
}
/* Else will try to reuse lookahead token after shifting the error
@@ -2220,7 +2121,7 @@ yyerrorlab:
if (/*CONSTCOND*/ 0)
goto yyerrorlab;
- /* Do not reclaim the symbols of the rule which action triggered
+ /* Do not reclaim the symbols of the rule whose action triggered
this YYERROR. */
YYPOPSTACK (yylen);
yylen = 0;
@@ -2233,35 +2134,37 @@ yyerrorlab:
| yyerrlab1 -- common code for both syntax error and YYERROR. |
`-------------------------------------------------------------*/
yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
for (;;)
{
yyn = yypact[yystate];
if (!yypact_value_is_default (yyn))
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
/* Pop the current state because it cannot handle the error token. */
if (yyssp == yyss)
- YYABORT;
+ YYABORT;
yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
+ yystos[yystate], yyvsp);
YYPOPSTACK (1);
yystate = *yyssp;
YY_STACK_PRINT (yyss, yyssp);
}
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
@@ -2304,14 +2207,14 @@ yyreturn:
yydestruct ("Cleanup: discarding lookahead",
yytoken, &yylval);
}
- /* Do not reclaim the symbols of the rule which action triggered
+ /* Do not reclaim the symbols of the rule whose action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
YY_STACK_PRINT (yyss, yyssp);
while (yyssp != yyss)
{
yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
+ yystos[*yyssp], yyvsp);
YYPOPSTACK (1);
}
#ifndef yyoverflow
@@ -2322,14 +2225,11 @@ yyreturn:
if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
+ return yyresult;
}
-
-
void conf_parse(const char *name)
{
struct symbol *sym;
@@ -2501,6 +2401,16 @@ static void print_symbol(FILE *out, struct menu *menu)
expr_fprint(prop->expr, out);
fputc('\n', out);
break;
+ case P_IMPLY:
+ fputs( " imply ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_SUGGEST:
+ fputs( " suggest ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
case P_RANGE:
fputs( " range ", out);
expr_fprint(prop->expr, out);
@@ -2577,4 +2487,3 @@ void zconfdump(FILE *out)
#include "expr.c"
#include "symbol.c"
#include "menu.c"
-
--
2.7.4
^ permalink raw reply related
* [PATCH v2 5/5] posix-timers: make it configurable
From: Nicolas Pitre @ 2016-10-26 2:28 UTC (permalink / raw)
To: John Stultz, Richard Cochran, Yann E. MORIN, Michal Marek
Cc: Thomas Gleixner, Josh Triplett, Edward Cree, netdev, linux-kbuild,
linux-kernel
In-Reply-To: <1477448931-29051-1-git-send-email-nicolas.pitre@linaro.org>
Some embedded systems have no use for them. This removes about
22KB from the kernel binary size when configured out.
Corresponding syscalls are routed to a stub logging the attempt to
use those syscalls which should be enough of a clue if they were
disabled without proper consideration. They are: timer_create,
timer_gettime: timer_getoverrun, timer_settime, timer_delete,
clock_adjtime.
The clock_settime, clock_gettime, clock_getres and clock_nanosleep
syscalls are replaced by simple wrappers compatible with CLOCK_REALTIME,
CLOCK_MONOTONIC and CLOCK_BOOTTIME only which should cover the vast
majority of use cases with very little code.
Signed-off-by: Nicolas Pitre <nico@linaro.org>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
---
drivers/ptp/Kconfig | 2 +-
include/linux/posix-timers.h | 28 +++++++++-
include/linux/sched.h | 10 ++++
init/Kconfig | 17 +++++++
kernel/signal.c | 4 ++
kernel/time/Makefile | 10 +++-
kernel/time/posix-stubs.c | 118 +++++++++++++++++++++++++++++++++++++++++++
7 files changed, 184 insertions(+), 5 deletions(-)
create mode 100644 kernel/time/posix-stubs.c
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 0f7492f8ea..bdce332911 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -6,7 +6,7 @@ menu "PTP clock support"
config PTP_1588_CLOCK
tristate "PTP clock support"
- depends on NET
+ depends on NET && POSIX_TIMERS
select PPS
select NET_PTP_CLASSIFY
help
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index 62d44c1760..2288c5c557 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -118,6 +118,8 @@ struct k_clock {
extern struct k_clock clock_posix_cpu;
extern struct k_clock clock_posix_dynamic;
+#ifdef CONFIG_POSIX_TIMERS
+
void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock);
/* function to call to trigger timer event */
@@ -131,8 +133,30 @@ void posix_cpu_timers_exit_group(struct task_struct *task);
void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
cputime_t *newval, cputime_t *oldval);
-long clock_nanosleep_restart(struct restart_block *restart_block);
-
void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
+#else
+
+#include <linux/random.h>
+
+static inline void posix_timers_register_clock(const clockid_t clock_id,
+ struct k_clock *new_clock) {}
+static inline int posix_timer_event(struct k_itimer *timr, int si_private)
+{ return 0; }
+static inline void run_posix_cpu_timers(struct task_struct *task) {}
+static inline void posix_cpu_timers_exit(struct task_struct *task)
+{
+ add_device_randomness((const void*) &task->se.sum_exec_runtime,
+ sizeof(unsigned long long));
+}
+static inline void posix_cpu_timers_exit_group(struct task_struct *task) {}
+static inline void set_process_cpu_timer(struct task_struct *task,
+ unsigned int clock_idx, cputime_t *newval, cputime_t *oldval) {}
+static inline void update_rlimit_cpu(struct task_struct *task,
+ unsigned long rlim_new) {}
+
+#endif
+
+long clock_nanosleep_restart(struct restart_block *restart_block);
+
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 348f51b0ec..ad716d5559 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2946,8 +2946,13 @@ static inline void exit_thread(struct task_struct *tsk)
extern void exit_files(struct task_struct *);
extern void __cleanup_sighand(struct sighand_struct *);
+#ifdef CONFIG_POSIX_TIMERS
extern void exit_itimers(struct signal_struct *);
extern void flush_itimer_signals(void);
+#else
+static inline void exit_itimers(struct signal_struct *s) {}
+static inline void flush_itimer_signals(void) {}
+#endif
extern void do_group_exit(int);
@@ -3450,7 +3455,12 @@ static __always_inline bool need_resched(void)
* Thread group CPU time accounting.
*/
void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times);
+#ifdef CONFIG_POSIX_TIMERS
void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times);
+#else
+static inline void thread_group_cputimer(struct task_struct *tsk,
+ struct task_cputime *times) {}
+#endif
/*
* Reevaluate whether the task has signals pending delivery.
diff --git a/init/Kconfig b/init/Kconfig
index 34407f15e6..351d422252 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1445,6 +1445,23 @@ config SYSCTL_SYSCALL
If unsure say N here.
+config POSIX_TIMERS
+ bool "Posix Clocks & timers" if EXPERT
+ default y
+ help
+ This includes native support for POSIX timers to the kernel.
+ Most embedded systems may have no use for them and therefore they
+ can be configured out to reduce the size of the kernel image.
+
+ When this option is disabled, the following syscalls won't be
+ available: timer_create, timer_gettime: timer_getoverrun,
+ timer_settime, timer_delete, clock_adjtime. Furthermore, the
+ clock_settime, clock_gettime, clock_getres and clock_nanosleep
+ syscalls will be limited to CLOCK_REALTIME and CLOCK_MONOTONIC
+ only.
+
+ If unsure say y.
+
config KALLSYMS
bool "Load all symbols for debugging/ksymoops" if EXPERT
default y
diff --git a/kernel/signal.c b/kernel/signal.c
index 75761acc77..0a38c9d646 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -427,6 +427,7 @@ void flush_signals(struct task_struct *t)
spin_unlock_irqrestore(&t->sighand->siglock, flags);
}
+#ifdef CONFIG_POSIX_TIMERS
static void __flush_itimer_signals(struct sigpending *pending)
{
sigset_t signal, retain;
@@ -460,6 +461,7 @@ void flush_itimer_signals(void)
__flush_itimer_signals(&tsk->signal->shared_pending);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
}
+#endif
void ignore_signals(struct task_struct *t)
{
@@ -611,6 +613,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
*/
current->jobctl |= JOBCTL_STOP_DEQUEUED;
}
+#ifdef CONFIG_POSIX_TIMERS
if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) {
/*
* Release the siglock to ensure proper locking order
@@ -622,6 +625,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
do_schedule_next_timer(info);
spin_lock(&tsk->sighand->siglock);
}
+#endif
return signr;
}
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index 49eca0beed..fc26c308f5 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -1,6 +1,12 @@
-obj-y += time.o timer.o hrtimer.o itimer.o posix-timers.o posix-cpu-timers.o
+obj-y += time.o timer.o hrtimer.o itimer.o
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
-obj-y += timeconv.o timecounter.o posix-clock.o alarmtimer.o
+obj-y += timeconv.o timecounter.o alarmtimer.o
+
+ifeq ($(CONFIG_POSIX_TIMERS),y)
+ obj-y += posix-timers.o posix-cpu-timers.o posix-clock.o
+else
+ obj-y += posix-stubs.o
+endif
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o tick-common.o
ifeq ($(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST),y)
diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c
new file mode 100644
index 0000000000..fe857bd4a0
--- /dev/null
+++ b/kernel/time/posix-stubs.c
@@ -0,0 +1,118 @@
+/*
+ * Dummy stubs used when CONFIG_POSIX_TIMERS=n
+ *
+ * Created by: Nicolas Pitre, July 2016
+ * Copyright: (C) 2016 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/syscalls.h>
+#include <linux/ktime.h>
+#include <linux/timekeeping.h>
+#include <linux/posix-timers.h>
+
+asmlinkage long sys_ni_posix_timers(void)
+{
+ pr_err_once("process %d (%s) attempted a POSIX timer syscall "
+ "while CONFIG_POSIX_TIMERS is not set\n",
+ current->pid, current->comm);
+ return -ENOSYS;
+}
+
+#define SYS_NI(name) SYSCALL_ALIAS(sys_##name, sys_ni_posix_timers)
+
+SYS_NI(timer_create);
+SYS_NI(timer_gettime);
+SYS_NI(timer_getoverrun);
+SYS_NI(timer_settime);
+SYS_NI(timer_delete);
+SYS_NI(clock_adjtime);
+
+/*
+ * We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC
+ * as it is easy to remain compatible with little code. CLOCK_BOOTTIME
+ * is also included for convenience as at least systemd uses it.
+ */
+
+SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
+ const struct timespec __user *, tp)
+{
+ struct timespec new_tp;
+
+ if (which_clock != CLOCK_REALTIME)
+ return -EINVAL;
+ if (copy_from_user(&new_tp, tp, sizeof (*tp)))
+ return -EFAULT;
+ return do_sys_settimeofday(&new_tp, NULL);
+}
+
+SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
+ struct timespec __user *,tp)
+{
+ struct timespec kernel_tp;
+
+ switch (which_clock) {
+ case CLOCK_REALTIME: ktime_get_real_ts(&kernel_tp); break;
+ case CLOCK_MONOTONIC: ktime_get_ts(&kernel_tp); break;
+ case CLOCK_BOOTTIME: get_monotonic_boottime(&kernel_tp); break;
+ default: return -EINVAL;
+ }
+ if (copy_to_user(tp, &kernel_tp, sizeof (kernel_tp)))
+ return -EFAULT;
+ return 0;
+}
+
+SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __user *, tp)
+{
+ struct timespec rtn_tp = {
+ .tv_sec = 0,
+ .tv_nsec = hrtimer_resolution,
+ };
+
+ switch (which_clock) {
+ case CLOCK_REALTIME:
+ case CLOCK_MONOTONIC:
+ case CLOCK_BOOTTIME:
+ if (copy_to_user(tp, &rtn_tp, sizeof(rtn_tp)))
+ return -EFAULT;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
+ const struct timespec __user *, rqtp,
+ struct timespec __user *, rmtp)
+{
+ struct timespec t;
+
+ switch (which_clock) {
+ case CLOCK_REALTIME:
+ case CLOCK_MONOTONIC:
+ case CLOCK_BOOTTIME:
+ if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
+ return -EFAULT;
+ if (!timespec_valid(&t))
+ return -EINVAL;
+ return hrtimer_nanosleep(&t, rmtp, flags & TIMER_ABSTIME ?
+ HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
+ which_clock);
+ default:
+ return -EINVAL;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+long clock_nanosleep_restart(struct restart_block *restart_block)
+{
+ return hrtimer_nanosleep_restart(restart_block);
+}
+#endif
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox