* [PATCH v9] mm: support madvise(MADV_FREE)
From: Minchan Kim @ 2014-07-01 0:36 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-mm, Minchan Kim, Michael Kerrisk, Linux API,
Hugh Dickins, Johannes Weiner, Rik van Riel, KOSAKI Motohiro,
Mel Gorman, Jason Evans, Zhang Yanfei
Linux doesn't have an ability to free pages lazy while other OS
already have been supported that named by madvise(MADV_FREE).
The gain is clear that kernel can discard freed pages rather than
swapping out or OOM if memory pressure happens.
Without memory pressure, freed pages would be reused by userspace
without another additional overhead(ex, page fault + allocation
+ zeroing).
How to work is following as.
When madvise syscall is called, VM clears dirty bit of ptes of
the range. If memory pressure happens, VM checks dirty bit of
page table and if it found still "clean", it means it's a
"lazyfree pages" so VM could discard the page instead of swapping out.
Once there was store operation for the page before VM peek a page
to reclaim, dirty bit is set so VM can swap out the page instead of
discarding.
Firstly, heavy users would be general allocators(ex, jemalloc,
tcmalloc and hope glibc supports it) and jemalloc/tcmalloc already
have supported the feature for other OS(ex, FreeBSD)
barrios@blaptop:~/benchmark/ebizzy$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 42
Stepping: 7
CPU MHz: 2801.000
BogoMIPS: 5581.64
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 4096K
NUMA node0 CPU(s): 0-3
ebizzy benchmark(./ebizzy -S 10 -n 512)
vanilla-jemalloc MADV_free-jemalloc
1 thread
records: 10 records: 10
avg: 7682.10 avg: 15306.10
std: 62.35(0.81%) std: 347.99(2.27%)
max: 7770.00 max: 15622.00
min: 7598.00 min: 14772.00
2 thread
records: 10 records: 10
avg: 12747.50 avg: 24171.00
std: 792.06(6.21%) std: 895.18(3.70%)
max: 13337.00 max: 26023.00
min: 10535.00 min: 23152.00
4 thread
records: 10 records: 10
avg: 16474.60 avg: 33717.90
std: 1496.45(9.08%) std: 2008.97(5.96%)
max: 17877.00 max: 35958.00
min: 12224.00 min: 29565.00
8 thread
records: 10 records: 10
avg: 16778.50 avg: 33308.10
std: 825.53(4.92%) std: 1668.30(5.01%)
max: 17543.00 max: 36010.00
min: 14576.00 min: 29577.00
16 thread
records: 10 records: 10
avg: 20614.40 avg: 35516.30
std: 602.95(2.92%) std: 1283.65(3.61%)
max: 21753.00 max: 37178.00
min: 19605.00 min: 33217.00
32 thread
records: 10 records: 10
avg: 22771.70 avg: 36018.50
std: 598.94(2.63%) std: 1046.76(2.91%)
max: 24035.00 max: 37266.00
min: 22108.00 min: 34149.00
In summary, MADV_FREE is about 2 time faster than MADV_DONTNEED.
* From v8
* Rebased-on v3.16-rc2-mmotm-2014-06-25-16-44
* From v7
* Rebased-on next-20140613
* From v6
* Remove page from swapcache in syscal time
* Move utility functions from memory.c to madvise.c - Johannes
* Rename untilify functtions - Johannes
* Remove unnecessary checks from vmscan.c - Johannes
* Rebased-on v3.15-rc5-mmotm-2014-05-16-16-56
* Drop Reviewe-by because there was some changes since then.
* From v5
* Fix PPC problem which don't flush TLB - Rik
* Remove unnecessary lazyfree_range stub function - Rik
* Rebased on v3.15-rc5
* From v4
* Add Reviewed-by: Zhang Yanfei
* Rebase on v3.15-rc1-mmotm-2014-04-15-16-14
* From v3
* Add "how to work part" in description - Zhang
* Add page_discardable utility function - Zhang
* Clean up
* From v2
* Remove forceful dirty marking of swap-readed page - Johannes
* Remove deactivation logic of lazyfreed page
* Rebased on 3.14
* Remove RFC tag
* From v1
* Use custom page table walker for madvise_free - Johannes
* Remove PG_lazypage flag - Johannes
* Do madvise_dontneed instead of madvise_freein swapless system
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: Linux API <linux-api@vger.kernel.org>
Cc: Hugh Dickins <hughd@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Jason Evans <je@fb.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
include/linux/rmap.h | 8 +-
include/linux/vm_event_item.h | 1 +
include/uapi/asm-generic/mman-common.h | 1 +
mm/madvise.c | 174 +++++++++++++++++++++++++++++++++
mm/rmap.c | 34 ++++++-
mm/vmscan.c | 37 +++++--
mm/vmstat.c | 1 +
7 files changed, 245 insertions(+), 11 deletions(-)
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index be574506e6a9..dea05914f167 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -181,7 +181,8 @@ static inline void page_dup_rmap(struct page *page)
* Called from mm/vmscan.c to handle paging out
*/
int page_referenced(struct page *, int is_locked,
- struct mem_cgroup *memcg, unsigned long *vm_flags);
+ struct mem_cgroup *memcg, unsigned long *vm_flags,
+ int *is_dirty);
#define TTU_ACTION(x) ((x) & TTU_ACTION_MASK)
@@ -260,9 +261,12 @@ int rmap_walk(struct page *page, struct rmap_walk_control *rwc);
static inline int page_referenced(struct page *page, int is_locked,
struct mem_cgroup *memcg,
- unsigned long *vm_flags)
+ unsigned long *vm_flags,
+ int *is_pte_dirty)
{
*vm_flags = 0;
+ if (is_pte_dirty)
+ *is_pte_dirty = 0;
return 0;
}
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
index ced92345c963..e2d3fb1e9814 100644
--- a/include/linux/vm_event_item.h
+++ b/include/linux/vm_event_item.h
@@ -25,6 +25,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
FOR_ALL_ZONES(PGALLOC),
PGFREE, PGACTIVATE, PGDEACTIVATE,
PGFAULT, PGMAJFAULT,
+ PGLAZYFREED,
FOR_ALL_ZONES(PGREFILL),
FOR_ALL_ZONES(PGSTEAL_KSWAPD),
FOR_ALL_ZONES(PGSTEAL_DIRECT),
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index ddc3b36f1046..7a94102b7a02 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -34,6 +34,7 @@
#define MADV_SEQUENTIAL 2 /* expect sequential page references */
#define MADV_WILLNEED 3 /* will need these pages */
#define MADV_DONTNEED 4 /* don't need these pages */
+#define MADV_FREE 5 /* free pages only if memory pressure */
/* common parameters: try to keep these consistent across architectures */
#define MADV_REMOVE 9 /* remove these pages & resources */
diff --git a/mm/madvise.c b/mm/madvise.c
index 0938b30da4ab..372a25a8ea82 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -19,6 +19,9 @@
#include <linux/blkdev.h>
#include <linux/swap.h>
#include <linux/swapops.h>
+#include <linux/mmu_notifier.h>
+
+#include <asm/tlb.h>
/*
* Any behaviour which results in changes to the vma->vm_flags needs to
@@ -31,6 +34,7 @@ static int madvise_need_mmap_write(int behavior)
case MADV_REMOVE:
case MADV_WILLNEED:
case MADV_DONTNEED:
+ case MADV_FREE:
return 0;
default:
/* be safe, default to 1. list exceptions explicitly */
@@ -251,6 +255,168 @@ static long madvise_willneed(struct vm_area_struct *vma,
return 0;
}
+static unsigned long madvise_free_pte_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma, pmd_t *pmd,
+ unsigned long addr, unsigned long end)
+{
+ struct mm_struct *mm = tlb->mm;
+ spinlock_t *ptl;
+ pte_t *start_pte;
+ pte_t *pte;
+ struct page *page;
+
+ start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ pte = start_pte;
+ arch_enter_lazy_mmu_mode();
+ do {
+ pte_t ptent = *pte;
+
+ if (pte_none(ptent))
+ continue;
+
+ if (!pte_present(ptent))
+ continue;
+
+ page = vm_normal_page(vma, addr, ptent);
+ if (page && PageSwapCache(page)) {
+ if (trylock_page(page)) {
+ if (try_to_free_swap(page))
+ ClearPageDirty(page);
+ unlock_page(page);
+ } else
+ continue;
+ }
+
+ /*
+ * Some of architecture(ex, PPC) don't update TLB
+ * with set_pte_at and tlb_remove_tlb_entry so for
+ * the portability, remap the pte with old|clean
+ * after pte clearing.
+ */
+ ptent = ptep_get_and_clear_full(mm, addr, pte,
+ tlb->fullmm);
+ ptent = pte_mkold(ptent);
+ ptent = pte_mkclean(ptent);
+ set_pte_at(mm, addr, pte, ptent);
+ tlb_remove_tlb_entry(tlb, pte, addr);
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+ arch_leave_lazy_mmu_mode();
+ pte_unmap_unlock(start_pte, ptl);
+
+ return addr;
+}
+
+static inline unsigned long madvise_free_pmd_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma, pud_t *pud,
+ unsigned long addr, unsigned long end)
+{
+ pmd_t *pmd;
+ unsigned long next;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ /*
+ * XXX: We can optimize with supporting Hugepage free
+ * if the range covers.
+ */
+ next = pmd_addr_end(addr, end);
+ if (pmd_trans_huge(*pmd))
+ split_huge_page_pmd(vma, addr, pmd);
+ /*
+ * Here there can be other concurrent MADV_DONTNEED or
+ * trans huge page faults running, and if the pmd is
+ * none or trans huge it can change under us. This is
+ * because MADV_LAZYFREE holds the mmap_sem in read
+ * mode.
+ */
+ if (pmd_none_or_trans_huge_or_clear_bad(pmd))
+ goto next;
+ next = madvise_free_pte_range(tlb, vma, pmd, addr, next);
+next:
+ cond_resched();
+ } while (pmd++, addr = next, addr != end);
+
+ return addr;
+}
+
+static inline unsigned long madvise_free_pud_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma, pgd_t *pgd,
+ unsigned long addr, unsigned long end)
+{
+ pud_t *pud;
+ unsigned long next;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if (pud_none_or_clear_bad(pud))
+ continue;
+ next = madvise_free_pmd_range(tlb, vma, pud, addr, next);
+ } while (pud++, addr = next, addr != end);
+
+ return addr;
+}
+
+static void madvise_free_page_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma,
+ unsigned long addr, unsigned long end)
+{
+ pgd_t *pgd;
+ unsigned long next;
+
+ BUG_ON(addr >= end);
+ tlb_start_vma(tlb, vma);
+ pgd = pgd_offset(vma->vm_mm, addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+ next = madvise_free_pud_range(tlb, vma, pgd, addr, next);
+ } while (pgd++, addr = next, addr != end);
+ tlb_end_vma(tlb, vma);
+}
+
+static int madvise_free_single_vma(struct vm_area_struct *vma,
+ unsigned long start_addr, unsigned long end_addr)
+{
+ unsigned long start, end;
+ struct mm_struct *mm = vma->vm_mm;
+ struct mmu_gather tlb;
+
+ if (vma->vm_flags & (VM_LOCKED|VM_HUGETLB|VM_PFNMAP))
+ return -EINVAL;
+
+ /* MADV_FREE works for only anon vma at the moment */
+ if (vma->vm_file)
+ return -EINVAL;
+
+ start = max(vma->vm_start, start_addr);
+ if (start >= vma->vm_end)
+ return -EINVAL;
+ end = min(vma->vm_end, end_addr);
+ if (end <= vma->vm_start)
+ return -EINVAL;
+
+ lru_add_drain();
+ tlb_gather_mmu(&tlb, mm, start, end);
+ update_hiwater_rss(mm);
+
+ mmu_notifier_invalidate_range_start(mm, start, end);
+ madvise_free_page_range(&tlb, vma, start, end);
+ mmu_notifier_invalidate_range_end(mm, start, end);
+ tlb_finish_mmu(&tlb, start, end);
+
+ return 0;
+}
+
+static long madvise_free(struct vm_area_struct *vma,
+ struct vm_area_struct **prev,
+ unsigned long start, unsigned long end)
+{
+ *prev = vma;
+ return madvise_free_single_vma(vma, start, end);
+}
+
/*
* Application no longer needs these pages. If the pages are dirty,
* it's OK to just throw them away. The app will be more careful about
@@ -381,6 +547,13 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
return madvise_remove(vma, prev, start, end);
case MADV_WILLNEED:
return madvise_willneed(vma, prev, start, end);
+ case MADV_FREE:
+ /*
+ * XXX: In this implementation, MADV_FREE works like
+ * MADV_DONTNEED on swapless system or full swap.
+ */
+ if (get_nr_swap_pages() > 0)
+ return madvise_free(vma, prev, start, end);
case MADV_DONTNEED:
return madvise_dontneed(vma, prev, start, end);
default:
@@ -400,6 +573,7 @@ madvise_behavior_valid(int behavior)
case MADV_REMOVE:
case MADV_WILLNEED:
case MADV_DONTNEED:
+ case MADV_FREE:
#ifdef CONFIG_KSM
case MADV_MERGEABLE:
case MADV_UNMERGEABLE:
diff --git a/mm/rmap.c b/mm/rmap.c
index 7928ddd91b6e..ee495d84c8b3 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -663,6 +663,7 @@ int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma)
}
struct page_referenced_arg {
+ int dirtied;
int mapcount;
int referenced;
unsigned long vm_flags;
@@ -677,6 +678,7 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
struct mm_struct *mm = vma->vm_mm;
spinlock_t *ptl;
int referenced = 0;
+ int dirty = 0;
struct page_referenced_arg *pra = arg;
if (unlikely(PageTransHuge(page))) {
@@ -729,6 +731,10 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
if (likely(!(vma->vm_flags & VM_SEQ_READ)))
referenced++;
}
+
+ if (pte_dirty(*pte))
+ dirty++;
+
pte_unmap_unlock(pte, ptl);
}
@@ -737,6 +743,9 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
pra->vm_flags |= vma->vm_flags;
}
+ if (dirty)
+ pra->dirtied++;
+
pra->mapcount--;
if (!pra->mapcount)
return SWAP_SUCCESS; /* To break the loop */
@@ -761,6 +770,7 @@ static bool invalid_page_referenced_vma(struct vm_area_struct *vma, void *arg)
* @is_locked: caller holds lock on the page
* @memcg: target memory cgroup
* @vm_flags: collect encountered vma->vm_flags who actually referenced the page
+ * @is_pte_dirty: ptes which have marked dirty bit - used for lazyfree page
*
* Quick test_and_clear_referenced for all mappings to a page,
* returns the number of ptes which referenced the page.
@@ -768,7 +778,8 @@ static bool invalid_page_referenced_vma(struct vm_area_struct *vma, void *arg)
int page_referenced(struct page *page,
int is_locked,
struct mem_cgroup *memcg,
- unsigned long *vm_flags)
+ unsigned long *vm_flags,
+ int *is_pte_dirty)
{
int ret;
int we_locked = 0;
@@ -783,6 +794,9 @@ int page_referenced(struct page *page,
};
*vm_flags = 0;
+ if (is_pte_dirty)
+ *is_pte_dirty = 0;
+
if (!page_mapped(page))
return 0;
@@ -810,6 +824,9 @@ int page_referenced(struct page *page,
if (we_locked)
unlock_page(page);
+ if (is_pte_dirty)
+ *is_pte_dirty = pra.dirtied;
+
return pra.referenced;
}
@@ -1128,6 +1145,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
spinlock_t *ptl;
int ret = SWAP_AGAIN;
enum ttu_flags flags = (enum ttu_flags)arg;
+ int dirty = 0;
pte = page_check_address(page, mm, address, &ptl, 0);
if (!pte)
@@ -1157,7 +1175,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
pteval = ptep_clear_flush(vma, address, pte);
/* Move the dirty bit to the physical page now the pte is gone. */
- if (pte_dirty(pteval))
+ dirty = pte_dirty(pteval);
+ if (dirty)
set_page_dirty(page);
/* Update high watermark before we lower rss */
@@ -1204,6 +1223,16 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
}
dec_mm_counter(mm, MM_ANONPAGES);
inc_mm_counter(mm, MM_SWAPENTS);
+ } else if (flags & TTU_UNMAP) {
+ if (dirty || PageDirty(page)) {
+ set_pte_at(mm, address, pte, pteval);
+ ret = SWAP_FAIL;
+ goto out_unmap;
+ } else {
+ /* It's a freeable page by madvise_free */
+ dec_mm_counter(mm, MM_ANONPAGES);
+ goto discard;
+ }
} else if (IS_ENABLED(CONFIG_MIGRATION)) {
/*
* Store the pfn of the page in a special migration
@@ -1227,6 +1256,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
} else
dec_mm_counter(mm, MM_FILEPAGES);
+discard:
page_remove_rmap(page);
page_cache_release(page);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 6d24fd63b209..f7a45600846f 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -707,13 +707,17 @@ enum page_references {
};
static enum page_references page_check_references(struct page *page,
- struct scan_control *sc)
+ struct scan_control *sc,
+ bool *freeable)
{
int referenced_ptes, referenced_page;
unsigned long vm_flags;
+ int pte_dirty;
+
+ VM_BUG_ON_PAGE(!PageLocked(page), page);
referenced_ptes = page_referenced(page, 1, sc->target_mem_cgroup,
- &vm_flags);
+ &vm_flags, &pte_dirty);
referenced_page = TestClearPageReferenced(page);
/*
@@ -754,6 +758,10 @@ static enum page_references page_check_references(struct page *page,
return PAGEREF_KEEP;
}
+ if (PageAnon(page) && !pte_dirty && !PageSwapCache(page) &&
+ !PageDirty(page))
+ *freeable = true;
+
/* Reclaim if clean, defer dirty pages to writeback */
if (referenced_page && !PageSwapBacked(page))
return PAGEREF_RECLAIM_CLEAN;
@@ -823,6 +831,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
int may_enter_fs;
enum page_references references = PAGEREF_RECLAIM_CLEAN;
bool dirty, writeback;
+ bool freeable = false;
cond_resched();
@@ -945,7 +954,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
}
if (!force_reclaim)
- references = page_check_references(page, sc);
+ references = page_check_references(page, sc,
+ &freeable);
switch (references) {
case PAGEREF_ACTIVATE:
@@ -961,7 +971,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
* Anonymous process memory has backing store?
* Try to allocate it some swap space here.
*/
- if (PageAnon(page) && !PageSwapCache(page)) {
+ if (PageAnon(page) && !PageSwapCache(page) && !freeable) {
if (!(sc->gfp_mask & __GFP_IO))
goto keep_locked;
if (!add_to_swap(page, page_list))
@@ -976,7 +986,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
* The page is mapped into the page tables of one or more
* processes. Try to unmap it here.
*/
- if (page_mapped(page) && mapping) {
+ if (page_mapped(page) && (mapping || freeable)) {
switch (try_to_unmap(page, ttu_flags)) {
case SWAP_FAIL:
goto activate_locked;
@@ -985,7 +995,20 @@ static unsigned long shrink_page_list(struct list_head *page_list,
case SWAP_MLOCK:
goto cull_mlocked;
case SWAP_SUCCESS:
- ; /* try to free the page below */
+ /* try to free the page below */
+ if (!freeable)
+ break;
+ /*
+ * Freeable anon page doesn't have mapping
+ * due to skipping of swapcache so we free
+ * page in here rather than __remove_mapping.
+ */
+ VM_BUG_ON_PAGE(PageSwapCache(page), page);
+ if (!page_freeze_refs(page, 1))
+ goto keep_locked;
+ __clear_page_locked(page);
+ count_vm_event(PGLAZYFREED);
+ goto free_it;
}
}
@@ -1727,7 +1750,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
}
if (page_referenced(page, 0, sc->target_mem_cgroup,
- &vm_flags)) {
+ &vm_flags, NULL)) {
nr_rotated += hpage_nr_pages(page);
/*
* Identify referenced, file-backed active pages and
diff --git a/mm/vmstat.c b/mm/vmstat.c
index eef6321c8470..da18337c6c66 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -794,6 +794,7 @@ const char * const vmstat_text[] = {
"pgfault",
"pgmajfault",
+ "pglazyfreed",
TEXTS_FOR_ZONES("pgrefill")
TEXTS_FOR_ZONES("pgsteal_kswapd")
--
2.0.0
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* Re: [PATCH RFC net-next 00/14] BPF syscall, maps, verifier, samples
From: Kees Cook @ 2014-06-30 23:09 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Arnaldo Carvalho de Melo, Jiri Olsa, Thomas Gleixner,
H. Peter Anvin, Andrew Morton, Linux API, Network Development,
LKML
In-Reply-To: <1403913966-4927-1-git-send-email-ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
On Fri, Jun 27, 2014 at 5:05 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
> Hi All,
>
> this patch set demonstrates the potential of eBPF.
>
> First patch "net: filter: split filter.c into two files" splits eBPF interpreter
> out of networking into kernel/bpf/. The goal for BPF subsystem is to be usable
> in NET-less configuration. Though the whole set is marked is RFC, the 1st patch
> is good to go. Similar version of the patch that was posted few weeks ago, but
> was deferred. I'm assuming due to lack of forward visibility. I hope that this
> patch set shows what eBPF is capable of and where it's heading.
>
> Other patches expose eBPF instruction set to user space and introduce concepts
> of maps and programs accessible via syscall.
>
> 'maps' is a generic storage of different types for sharing data between kernel
> and userspace. Maps are referrenced by global id. Root can create multiple
> maps of different types where key/value are opaque bytes of data. It's up to
> user space and eBPF program to decide what they store in the maps.
>
> eBPF programs are similar to kernel modules. They live in global space and
> have unique prog_id. Each program is a safe run-to-completion set of
> instructions. eBPF verifier statically determines that the program terminates
> and safe to execute. During verification the program takes a hold of maps
> that it intends to use, so selected maps cannot be removed until program is
> unloaded. The program can be attached to different events. These events can
> be packets, tracepoint events and other types in the future. New event triggers
> execution of the program which may store information about the event in the maps.
> Beyond storing data the programs may call into in-kernel helper functions
> which may, for example, dump stack, do trace_printk or other forms of live
> kernel debugging. Same program can be attached to multiple events. Different
> programs can access the same map:
>
> tracepoint tracepoint tracepoint sk_buff sk_buff
> event A event B event C on eth0 on eth1
> | | | | |
> | | | | |
> --> tracing <-- tracing socket socket
> prog_1 prog_2 prog_3 prog_4
> | | | |
> |--- -----| |-------| map_3
> map_1 map_2
>
> User space (via syscall) and eBPF programs access maps concurrently.
>
> Last two patches are sample code. 1st demonstrates stateful packet inspection.
> It counts tcp and udp packets on eth0. Should be easy to see how this eBPF
> framework can be used for network analytics.
> 2nd sample does simple 'drop monitor'. It attaches to kfree_skb tracepoint
> event and counts number of packet drops at particular $pc location.
> User space periodically summarizes what eBPF programs recorded.
> In these two samples the eBPF programs are tiny and written in 'assembler'
> with macroses. More complex programs can be written C (llvm backend is not
> part of this diff to reduce 'huge' perception).
> Since eBPF is fully JITed on x64, the cost of running eBPF program is very
> small even for high frequency events. Here are the numbers comparing
> flow_dissector in C vs eBPF:
> x86_64 skb_flow_dissect() same skb (all cached) - 42 nsec per call
> x86_64 skb_flow_dissect() different skbs (cache misses) - 141 nsec per call
> eBPF+jit skb_flow_dissect() same skb (all cached) - 51 nsec per call
> eBPF+jit skb_flow_dissect() different skbs (cache misses) - 135 nsec per call
>
> Detailed explanation on eBPF verifier and safety is in patch 08/14
This is very exciting! Thanks for working on it. :)
Between the new eBPF syscall and the new seccomp syscall, I'm really
looking forward to using lookup tables for seccomp filters. Under
certain types of filters, we'll likely see some non-trivial
performance improvements.
-Kees
--
Kees Cook
Chrome OS Security
^ permalink raw reply
* Re: [PATCH 5/5] man-pages: cap_rights_get: retrieve Capsicum fd rights
From: Andy Lutomirski @ 2014-06-30 22:28 UTC (permalink / raw)
To: David Drysdale
Cc: LSM List, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Greg Kroah-Hartman, Alexander Viro, Meredydd Luff, Kees Cook,
James Morris, Linux API
In-Reply-To: <1404124096-21445-17-git-send-email-drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
On Mon, Jun 30, 2014 at 3:28 AM, David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote:
> Signed-off-by: David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> ---
> man2/cap_rights_get.2 | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 126 insertions(+)
> create mode 100644 man2/cap_rights_get.2
>
> diff --git a/man2/cap_rights_get.2 b/man2/cap_rights_get.2
> new file mode 100644
> index 000000000000..966c0ed7e336
> --- /dev/null
> +++ b/man2/cap_rights_get.2
> @@ -0,0 +1,126 @@
> +.\"
> +.\" Copyright (c) 2008-2010 Robert N. M. Watson
> +.\" Copyright (c) 2012-2013 The FreeBSD Foundation
> +.\" Copyright (c) 2013-2014 Google, Inc.
> +.\" All rights reserved.
> +.\"
> +.\" %%%LICENSE_START(BSD_2_CLAUSE)
> +.\" Redistribution and use in source and binary forms, with or without
> +.\" modification, are permitted provided that the following conditions
> +.\" are met:
> +.\" 1. Redistributions of source code must retain the above copyright
> +.\" notice, this list of conditions and the following disclaimer.
> +.\" 2. Redistributions in binary form must reproduce the above copyright
> +.\" notice, this list of conditions and the following disclaimer in the
> +.\" documentation and/or other materials provided with the distribution.
> +.\"
> +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> +.\" SUCH DAMAGE.
> +.\" %%%LICENSE_END
> +.\"
> +.TH CAP_RIGHTS_GET 2 2014-05-07 "Linux" "Linux Programmer's Manual"
> +.SH NAME
> +cap_rights_get \- retrieve Capsicum capability rights
> +.SH SYNOPSIS
> +.nf
> +.B #include <sys/capsicum.h>
> +.sp
> +.BI "int cap_rights_get(int " fd ", struct cap_rights *" rights ,
> +.BI " unsigned int *" fcntls ,
> +.BI " int *" nioctls ", unsigned int *" ioctls );
> +.SH DESCRIPTION
> +Obtain the current Capsicum capability rights for a file descriptor.
> +.PP
> +The function will fill the
> +.I rights
> +argument (if non-NULL) with the primary capability rights of the
> +.I fd
> +descriptor. The result can be examined with the
> +.BR cap_rights_is_set (3)
> +family of functions. The complete list of primary rights can be found in the
> +.BR rights (7)
> +manual page.
> +.PP
> +If the
> +.I fcntls
> +argument is non-NULL, it will be filled in with a bitmask of allowed
> +.BR fcntl (2)
> +commands; see
> +.BR cap_rights_limit (2)
> +for values. If the file descriptor does not have the
> +.B CAP_FCNTL
> +primary right, the returned
> +.I fcntls
> +value will be zero.
> +.PP
> +If the
> +.I nioctls
> +argument is non-NULL, it will be filled in with the number of allowed
> +.BR ioctl (2)
> +commands, or with the value CAP_IOCTLS_ALL to indicate that all
> +.BR ioctl (2)
> +commands are allowed. If the file descriptor does not have the
> +.B CAP_IOCTL
> +primary right, the returned
> +.I nioctls
> +value will be zero.
> +.PP
> +The
> +.I ioctls
> +argument (if non-NULL) should point at memory that can hold up to
> +.I nioctls
> +values.
> +The system call populates the provided buffer with up to
> +.I nioctls
> +elements, but always returns the total number of
I assume you mean "up to the initial value of *nioctls elements" or
something. Can you clarify?
--Andy
^ permalink raw reply
* Re: [PATCH 1/5] man-pages: open.2: describe O_BENEATH_ONLY flag
From: Andy Lutomirski @ 2014-06-30 22:22 UTC (permalink / raw)
To: David Drysdale
Cc: LSM List, linux-kernel@vger.kernel.org, Greg Kroah-Hartman,
Alexander Viro, Meredydd Luff, Kees Cook, James Morris, Linux API
In-Reply-To: <1404124096-21445-13-git-send-email-drysdale@google.com>
On Mon, Jun 30, 2014 at 3:28 AM, David Drysdale <drysdale@google.com> wrote:
> Signed-off-by: David Drysdale <drysdale@google.com>
> ---
> man2/open.2 | 33 +++++++++++++++++++++++++++++++--
> 1 file changed, 31 insertions(+), 2 deletions(-)
>
> diff --git a/man2/open.2 b/man2/open.2
> index 3824ab5be1f0..ba0da01c1a4f 100644
> --- a/man2/open.2
> +++ b/man2/open.2
> @@ -713,7 +713,7 @@ in a fully formed state (using
> as described above).
> .RE
> .IP
> -.B O_TMPFILE
> +.B O_TMPFILE " (since Linux 3.??)"
> requires support by the underlying filesystem;
> only a subset of Linux filesystems provide that support.
> In the initial implementation, support was provided in
> @@ -723,6 +723,31 @@ XFS support was added
> .\" commit ab29743117f9f4c22ac44c13c1647fb24fb2bafe
> in Linux 3.15.
> .TP
> +.B O_BENEATH_ONLY
> +Ensure that the
> +.I pathname
> +is beneath the current working directory (for
> +.BR open (2))
> +or the
> +.I dirfd
> +(for
> +.BR openat (2)).
> +If the
> +.I pathname
> +is absolute or contains a path component of "..", the
> +.BR open ()
> +fails with the error
> +.BR EACCES.
> +This occurs even if ".." path component would not actually
> +escape the original directory; for example, a
> +.I pathname
> +of "subdir/../filename" would be rejected.
> +Path components that are symbolic links to absolute paths, or that are
> +relative paths containing a ".." component, are cause the
"are cause" is a typo. Do you mean "will also cause"?
--Andy
^ permalink raw reply
* Re: [PATCH RFC net-next 03/14] bpf: introduce syscall(BPF, ...) and BPF maps
From: Andy Lutomirski @ 2014-06-30 22:09 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Arnaldo Carvalho de Melo, Jiri Olsa, Thomas Gleixner,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMEtUuyKY=haqP11VgXHdfHBkqfB-KxuswygUd7hDPLkOFz9HQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Sat, Jun 28, 2014 at 11:36 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
> On Sat, Jun 28, 2014 at 6:52 PM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>> On Sat, Jun 28, 2014 at 1:49 PM, Alexei Starovoitov <ast-uqk4Ao+rVK7QFizaE/u3fw@public.gmane.orgm> wrote:
>>>
>>> Sorry I don't like 'fd' direction at all.
>>> 1. it will make the whole thing very socket specific and 'net' dependent.
>>> but the goal here is to be able to use eBPF for tracing in embedded
>>> setups. So it's gotta be net independent.
>>> 2. sockets are already overloaded with all sorts of stuff. Adding more
>>> types of sockets will complicate it a lot.
>>> 3. and most important. read/write operations on sockets are not
>>> done every nanosecond, whereas lookup operations on bpf maps
>>> are done every dozen instructions, so we cannot have any overhead
>>> when accessing maps.
>>> In other words the verifier is done as static analyzer. I moved all
>>> the complexity to verify time, so at run-time the programs are as
>>> fast as possible. I'm strongly against run-time checks in critical path,
>>> since they kill performance and make the whole approach a lot less usable.
>>
>> I may have described my suggestion poorly. I'm suggesting that all of
>> these global ids be replaced *for userspace's benefit* with fds. That
>> is, a map would have an associated struct inode, and, when you load an
>> eBPF program, you'd pass fds into the kernel instead of global ids.
>> The kernel would still compile the eBPF program to use the global ids,
>> though.
>
> Hmm. If I understood you correctly, you're suggesting to do it similar
> to ipc/mqueue, shmem, sockets do. By registering and mounting
> a file system and providing all superblock and inode hooks… and
> probably have its own namespace type… hmm… may be. That's
> quite a bit of work to put lightly. As I said in the other email the first
> step is root only and all these complexity just not worth doing
> at this stage.
The downside of not doing it right away is that it's harder to
retrofit in without breaking early users.
You might be able to get away with using anon_inodes. That will
prevent repoening via /proc/self/fd from working (I think), but that's
a good thing until someone fixes the /proc reopen hole. Sigh.
--Andy
^ permalink raw reply
* Re: Does it make sense to define a constant for openat and such that is guaranteed not to be used for special purposes later on?
From: Andy Lutomirski @ 2014-06-30 22:08 UTC (permalink / raw)
To: Steven Stewart-Gallus; +Cc: Linux API
In-Reply-To: <fb54be9c497f.53af14a5-BTv7Ps/Sm75C8prJL3GQQw@public.gmane.org>
On Sat, Jun 28, 2014 at 12:16 PM, Steven Stewart-Gallus
<sstewartgallus00-QKvm5KDIoDa7M0a00MdBSQ@public.gmane.org> wrote:
> Hello,
>
> For system calls such as openat I might wish to use the value -1 for
> the directory file descriptor parameter to indicate that a path passed
> in must be an absolute path. However, it has occurred to me that such
> a usage isn't defined by POSIX and isn't safe for the future. In the
> future -1 may be taken to be used for some other special purpose. I
> would like a solution for that problem.
>
> It'd be nice if we could define a constant (maybe call it AT_FDNODIR)
> to maybe -1 that is set aside to mean that no directory is to be used
> and that will not ever be ever used for some other purpose in the
> future.
I like this. Want to submit a patch?
--Andy
^ permalink raw reply
* Re: [PATCH 01/11] fs: add O_BENEATH_ONLY flag to openat(2)
From: Andy Lutomirski @ 2014-06-30 21:11 UTC (permalink / raw)
To: Andi Kleen
Cc: David Drysdale, LSM List, linux-kernel@vger.kernel.org,
Greg Kroah-Hartman, Alexander Viro, Meredydd Luff, Kees Cook,
James Morris, Linux API
In-Reply-To: <87mwcuw2pj.fsf@tassilo.jf.intel.com>
On Mon, Jun 30, 2014 at 1:40 PM, Andi Kleen <andi@firstfloor.org> wrote:
> David Drysdale <drysdale@google.com> writes:
>
>> Add a new O_BENEATH_ONLY flag for openat(2) which restricts the
>> provided path, rejecting (with -EACCES) paths that are not beneath
>> the provided dfd. In particular, reject:
>> - paths that contain .. components
>> - paths that begin with /
>> - symlinks that have paths as above.
>
> How about bind mounts?
What's the problematic scenario?
--Andy
^ permalink raw reply
* Re: [PATCH 01/11] fs: add O_BENEATH_ONLY flag to openat(2)
From: Andi Kleen @ 2014-06-30 20:40 UTC (permalink / raw)
To: David Drysdale
Cc: linux-security-module, linux-kernel, Greg Kroah-Hartman,
Alexander Viro, Meredydd Luff, Kees Cook, James Morris, linux-api
In-Reply-To: <1404124096-21445-2-git-send-email-drysdale@google.com>
David Drysdale <drysdale@google.com> writes:
> Add a new O_BENEATH_ONLY flag for openat(2) which restricts the
> provided path, rejecting (with -EACCES) paths that are not beneath
> the provided dfd. In particular, reject:
> - paths that contain .. components
> - paths that begin with /
> - symlinks that have paths as above.
How about bind mounts?
-Andi
--
ak@linux.intel.com -- Speaking for myself only
^ permalink raw reply
* Re: [PATCH RFC net-next 07/14] bpf: expand BPF syscall with program load/unload
From: Alexei Starovoitov @ 2014-06-30 20:39 UTC (permalink / raw)
To: Andy Lutomirski, David Laight
Cc: Greg KH, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, Arnaldo Carvalho de Melo, Jiri Olsa,
Thomas Gleixner, H. Peter Anvin, Andrew Morton, Kees Cook,
Linux API, Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <CALCETrUs8mmVK70rwkQz=Dzu2ZjPYU_TMuydnXsJM8jAxTv0WQ@mail.gmail.com>
On Sat, Jun 28, 2014 at 8:35 AM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Sat, Jun 28, 2014 at 8:21 AM, Greg KH <gregkh@linuxfoundation.org> wrote:
>> On Sat, Jun 28, 2014 at 12:26:14AM -0700, Alexei Starovoitov wrote:
>>> On Fri, Jun 27, 2014 at 11:28 PM, Andy Lutomirski <luto@amacapital.net> wrote:
>>> > On Fri, Jun 27, 2014 at 11:12 PM, Alexei Starovoitov <ast@plumgrid.com> wrote:
>>> > If you want to add GPL-only functions in the future, that would be one
>>> > thing. But if someone writes a nice eBPF compiler, and someone else
>>> > writes a little program that filters on network packets, I see no
>>> > reason to claim that the little program is a derivative work of the
>>> > kernel and therefore must be GPL.
>>>
>>> I think we have to draw a line somewhere. Say, tomorrow I want
>>> to modify libpcap to emit eBPF based on existing tcpdump syntax.
>>> Would it mean that tcpdump filter strings are GPLed? Definitely not,
>>> since they existed before and can function without new libpcap.
>>> But if I write a new packet filtering program in C, compile it
>>> using LLVM->eBPF and call into in-kernel helper functions
>>> (like bpf_map_lookup_elem()), I think it's exactly the derivative work.
>>> It's analogous to kernel modules. If module wants to call
>>> export_symbol_gpl() functions, it needs to be GPLed. Here all helper
>>> functions are GPL. So we just have a blank check for eBPF program.
>>
>> I agree, these eBFP programs should be GPL-compatible licensed as well.
>
> I think I'd be happy with an export_symbol_gpl analogue. I might
> argue that bpf_map_lookup_elem shouldn't be gpl-only, though.
ok. sounds like module-like approach will be more acceptable to potential
user base. Will change it. Last thing I want to do is to scary users away.
^ permalink raw reply
* Re: [patch 0/4] timerfd c/r support, v4
From: Cyrill Gorcunov @ 2014-06-30 19:43 UTC (permalink / raw)
To: Thomas Gleixner, Michael Kerrisk
Cc: linux-kernel, linux-api, Andrew Morton, Andrey Vagin,
Pavel Emelyanov, Vladimir Davydov
In-Reply-To: <20140623185431.396309193@openvz.org>
On Mon, Jun 23, 2014 at 10:54:31PM +0400, Cyrill Gorcunov wrote:
>
> Hi guys, here is an updated version of c/r support for timerfd files. The main change
> is in how @ticks are restored in patch 3 -- I switched to ioctl code, which is wrapped
> with CONFIG because I still think that while there is only one ioctl designated
> solely for c/r needs no need to build it all the time until explicitly requested.
> Please take a look once time permit. Comments are highly appreciated.
> Also note the last patch is for man-page git repo, not for kernel.
Gentlemen, could you please point me if there something preventing the
series from being picked up? Or there some way to improve the series?
^ permalink raw reply
* Re: [PATCH 4/5] man-pages: cap_rights_limit.2: limit FD rights for Capsicum
From: David Drysdale @ 2014-06-30 16:32 UTC (permalink / raw)
To: Andy Lutomirski
Cc: LSM List, linux-kernel@vger.kernel.org, Greg Kroah-Hartman,
Alexander Viro, Meredydd Luff, Kees Cook, James Morris, Linux API
In-Reply-To: <CALCETrWYQdAp1E-MNu59XS8DD0oO1dA8EvoqDrMaH2YLos8iSg@mail.gmail.com>
On Mon, Jun 30, 2014 at 09:06:41AM -0700, Andy Lutomirski wrote:
> On Mon, Jun 30, 2014 at 8:35 AM, David Drysdale <drysdale@google.com> wrote:
> > On Mon, Jun 30, 2014 at 07:53:57AM -0700, Andy Lutomirski wrote:
> >> On Mon, Jun 30, 2014 at 3:28 AM, David Drysdale <drysdale@google.com> wrote:
> >> > Signed-off-by: David Drysdale <drysdale@google.com>
> >> > ---
> >> > man2/cap_rights_limit.2 | 171 ++++++++++++++++++++++++++++++++++++++++++++++++
> >> > 1 file changed, 171 insertions(+)
> >> > create mode 100644 man2/cap_rights_limit.2
> >> >
> >> > diff --git a/man2/cap_rights_limit.2 b/man2/cap_rights_limit.2
> >> > new file mode 100644
> >> > index 000000000000..3484ee1076aa
> >> > --- /dev/null
> >> > +++ b/man2/cap_rights_limit.2
> >> > @@ -0,0 +1,171 @@
> >> > +.\"
> >> > +.\" Copyright (c) 2008-2010 Robert N. M. Watson
> >> > +.\" Copyright (c) 2012-2013 The FreeBSD Foundation
> >> > +.\" Copyright (c) 2013-2014 Google, Inc.
> >> > +.\" All rights reserved.
> >> > +.\"
> >> > +.\" %%%LICENSE_START(BSD_2_CLAUSE)
> >> > +.\" Redistribution and use in source and binary forms, with or without
> >> > +.\" modification, are permitted provided that the following conditions
> >> > +.\" are met:
> >> > +.\" 1. Redistributions of source code must retain the above copyright
> >> > +.\" notice, this list of conditions and the following disclaimer.
> >> > +.\" 2. Redistributions in binary form must reproduce the above copyright
> >> > +.\" notice, this list of conditions and the following disclaimer in the
> >> > +.\" documentation and/or other materials provided with the distribution.
> >> > +.\"
> >> > +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> >> > +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> >> > +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> >> > +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> >> > +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> >> > +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> >> > +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> >> > +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> >> > +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> >> > +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> >> > +.\" SUCH DAMAGE.
> >> > +.\" %%%LICENSE_END
> >> > +.\"
> >> > +.TH CAP_RIGHTS_LIMIT 2 2014-05-07 "Linux" "Linux Programmer's Manual"
> >> > +.SH NAME
> >> > +cap_rights_limit \- limit Capsicum capability rights
> >> > +.SH SYNOPSIS
> >> > +.nf
> >> > +.B #include <sys/capsicum.h>
> >> > +.sp
> >> > +.BI "int cap_rights_limit(int " fd ", const struct cap_rights *" rights ,
> >> > +.BI " unsigned int " fcntls ,
> >> > +.BI " int " nioctls ", unsigned int *" ioctls );
> >>
> >> Am I missing the docs for struct cap_rights somewhere?
> >
> > There's a little bit of discussion in rights.7 (mail 3/5 of the
> > man-pages set), but there isn't a structure description.
> >
> > I was trying to keep the structure opaque to userspace, which would
> > be expected to manipulate the rights with various utility functions
> > rather than directly.
> >
> > But I now realize this leaves a gap -- the description of this syscall
> > doesn't include a full description of its ABI.
> >
> > So I'll add in a description of the structure to this page -- basically:
> >
> > struct cap_rights {
> > __u64 cr_rights[2];
> > };
> >
> > with a slightly complicated scheme to encode rights into the bitmask
> > array. (The encoding scheme is taken from the FreeBSD implementation,
> > which I've tried to stick to unless there's good reason to change.)
>
> How does extensibility work? For example, what happens when someone
> needs to add a new right for whatever reason and they fall off the end
> of the list?
>
> Linux so-called capabilities have done this a few times, resulting in
> a giant mess.
>
> --Andy
The rights encoding scheme is supposed to cope with extensions, so let me
have a go at explaining it.
The size of the array in the structure can potentially change in future,
so a less abbreviated version is:
#define CAP_RIGHTS_VERSION_00 0
#define CAP_RIGHTS_VERSION_01 1
#define CAP_RIGHTS_VERSION_02 2
#define CAP_RIGHTS_VERSION_03 3
#define CAP_RIGHTS_VERSION CAP_RIGHTS_VERSION_00
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The encoding rules are then:
- There are between 2 and 5 entries in the array.
- The number of entries in the array is indicated by the top 2 bits of
cr_rights[0] (as array size minus 2); this allows for future
expansion (up to 285 distinct rights):
0b00 = 2 entries
0b01 = 3 entries
0b10 = 4 entries
0b11 = 5 entries
- The top 2 bits of cr_rights[i] are 0b00 for i>0.
- The next 5 bits of each array entry indicate its position in the
array:
0b00001 for cr_rights[0]
0b00010 for cr_rights[1]
0b00100 for cr_rights[2]
0b01000 for cr_rights[3]
0b10000 for cr_rights[4]
- The remaining 57 bits of each entry are used to hold rights values,
so the current structure can hold 114 rights, and the maximum is
285.
So a future kernel (with an expanded array) can cope with an old binary
(that uses a narrow array) by reading the first u64 from the structure,
and using the top 2 bits to figure out how much more memory to copy
from userspace. Slightly inefficient, but I wouldn't expect rights
setting to be a performance critical operation.
Of course, we can deviate from the FreeBSD implementation details if
we want to -- these details are deliberately hidden from userspace
programs in the rights-manipulation library functions, so a different
implementation under the covers wouldn't affect Capsicum-using
applications. But I figured it's best to stay close unless there's
a good reason to diverge.
^ permalink raw reply
* Re: [PATCH 4/5] man-pages: cap_rights_limit.2: limit FD rights for Capsicum
From: Andy Lutomirski @ 2014-06-30 16:06 UTC (permalink / raw)
To: David Drysdale
Cc: LSM List, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Greg Kroah-Hartman, Alexander Viro, Meredydd Luff, Kees Cook,
James Morris, Linux API
In-Reply-To: <20140630153503.GA10375-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
On Mon, Jun 30, 2014 at 8:35 AM, David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote:
> On Mon, Jun 30, 2014 at 07:53:57AM -0700, Andy Lutomirski wrote:
>> On Mon, Jun 30, 2014 at 3:28 AM, David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote:
>> > Signed-off-by: David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
>> > ---
>> > man2/cap_rights_limit.2 | 171 ++++++++++++++++++++++++++++++++++++++++++++++++
>> > 1 file changed, 171 insertions(+)
>> > create mode 100644 man2/cap_rights_limit.2
>> >
>> > diff --git a/man2/cap_rights_limit.2 b/man2/cap_rights_limit.2
>> > new file mode 100644
>> > index 000000000000..3484ee1076aa
>> > --- /dev/null
>> > +++ b/man2/cap_rights_limit.2
>> > @@ -0,0 +1,171 @@
>> > +.\"
>> > +.\" Copyright (c) 2008-2010 Robert N. M. Watson
>> > +.\" Copyright (c) 2012-2013 The FreeBSD Foundation
>> > +.\" Copyright (c) 2013-2014 Google, Inc.
>> > +.\" All rights reserved.
>> > +.\"
>> > +.\" %%%LICENSE_START(BSD_2_CLAUSE)
>> > +.\" Redistribution and use in source and binary forms, with or without
>> > +.\" modification, are permitted provided that the following conditions
>> > +.\" are met:
>> > +.\" 1. Redistributions of source code must retain the above copyright
>> > +.\" notice, this list of conditions and the following disclaimer.
>> > +.\" 2. Redistributions in binary form must reproduce the above copyright
>> > +.\" notice, this list of conditions and the following disclaimer in the
>> > +.\" documentation and/or other materials provided with the distribution.
>> > +.\"
>> > +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
>> > +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
>> > +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
>> > +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
>> > +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
>> > +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
>> > +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
>> > +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
>> > +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
>> > +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>> > +.\" SUCH DAMAGE.
>> > +.\" %%%LICENSE_END
>> > +.\"
>> > +.TH CAP_RIGHTS_LIMIT 2 2014-05-07 "Linux" "Linux Programmer's Manual"
>> > +.SH NAME
>> > +cap_rights_limit \- limit Capsicum capability rights
>> > +.SH SYNOPSIS
>> > +.nf
>> > +.B #include <sys/capsicum.h>
>> > +.sp
>> > +.BI "int cap_rights_limit(int " fd ", const struct cap_rights *" rights ,
>> > +.BI " unsigned int " fcntls ,
>> > +.BI " int " nioctls ", unsigned int *" ioctls );
>>
>> Am I missing the docs for struct cap_rights somewhere?
>
> There's a little bit of discussion in rights.7 (mail 3/5 of the
> man-pages set), but there isn't a structure description.
>
> I was trying to keep the structure opaque to userspace, which would
> be expected to manipulate the rights with various utility functions
> rather than directly.
>
> But I now realize this leaves a gap -- the description of this syscall
> doesn't include a full description of its ABI.
>
> So I'll add in a description of the structure to this page -- basically:
>
> struct cap_rights {
> __u64 cr_rights[2];
> };
>
> with a slightly complicated scheme to encode rights into the bitmask
> array. (The encoding scheme is taken from the FreeBSD implementation,
> which I've tried to stick to unless there's good reason to change.)
How does extensibility work? For example, what happens when someone
needs to add a new right for whatever reason and they fall off the end
of the list?
Linux so-called capabilities have done this a few times, resulting in
a giant mess.
--Andy
^ permalink raw reply
* Re: [PATCH 09/11] capsicum: implementations of new LSM hooks
From: Andy Lutomirski @ 2014-06-30 16:05 UTC (permalink / raw)
To: David Drysdale
Cc: LSM List, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Greg Kroah-Hartman, Alexander Viro, Meredydd Luff, Kees Cook,
James Morris, Linux API
In-Reply-To: <1404124096-21445-10-git-send-email-drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
On Mon, Jun 30, 2014 at 3:28 AM, David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote:
> If the LSM does not provide implementations of the .file_lookup and
> .file_install LSM hooks, always use the Capsicum implementations.
>
> The Capsicum implementation of file_lookup checks for a Capsicum
> capability wrapper file and unwraps to if the appropriate rights
> are available.
>
> The Capsicum implementation of file_install checks whether the file
> has restricted rights associated with it. If it does, it is replaced
> with a Capsicum capability wrapper file before installation into the
> fdtable.
I think I fall on the "no LSM" side of the fence. This kind of stuff
should be available regardless of selected LSM (as it is in your
code), but until someone has a use case for the LSM hooks in real
LSMs, I don't really see the point.
--Andy
^ permalink raw reply
* Re: [PATCH 01/11] fs: add O_BENEATH_ONLY flag to openat(2)
From: Andy Lutomirski @ 2014-06-30 15:53 UTC (permalink / raw)
To: David Drysdale
Cc: Al Viro, LSM List, Greg Kroah-Hartman, James Morris, Kees Cook,
Linux API, Meredydd Luff, linux-kernel@vger.kernel.org
In-Reply-To: <20140630154928.GB10375@google.com>
On Mon, Jun 30, 2014 at 8:49 AM, David Drysdale <drysdale@google.com> wrote:
> On Mon, Jun 30, 2014 at 07:49:41AM -0700, Andy Lutomirski wrote:
>> On Jun 30, 2014 3:36 AM, "David Drysdale" <drysdale@google.com> wrote:
>> >
>> > Add a new O_BENEATH_ONLY flag for openat(2) which restricts the
>> > provided path, rejecting (with -EACCES) paths that are not beneath
>> > the provided dfd. In particular, reject:
>> > - paths that contain .. components
>> > - paths that begin with /
>> > - symlinks that have paths as above.
>>
>> I like this a lot. However, I think I'd like it even better if it
>> were AT_BENEATH_ONLY so that it could be added to the rest of the *at
>> family.
>>
>> --Andy
>
> Wouldn't it need to be both O_BENEATH_ONLY (for openat()) and
> AT_BENEATH_ONLY (for other *at() functions), like O_NOFOLLOW and
> AT_SYMLINK_NOFOLLOW? (I.e. aren't the AT_* flags in a different
> numbering space than O_* flags?)
>
> Or am I misunderstanding?
>
Ugh, you're probably right. I wish openat had separate flags and
atflags arguments. Oh well.
--Andy
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply
* Re: [PATCH 01/11] fs: add O_BENEATH_ONLY flag to openat(2)
From: David Drysdale @ 2014-06-30 15:49 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Al Viro, LSM List, Greg Kroah-Hartman, James Morris, Kees Cook,
Linux API, Meredydd Luff, linux-kernel@vger.kernel.org
In-Reply-To: <CALCETrU=HLmw9n-DxPkFV1xP5wtzQ7-YF3-uao6YiGZODA9kdw@mail.gmail.com>
On Mon, Jun 30, 2014 at 07:49:41AM -0700, Andy Lutomirski wrote:
> On Jun 30, 2014 3:36 AM, "David Drysdale" <drysdale@google.com> wrote:
> >
> > Add a new O_BENEATH_ONLY flag for openat(2) which restricts the
> > provided path, rejecting (with -EACCES) paths that are not beneath
> > the provided dfd. In particular, reject:
> > - paths that contain .. components
> > - paths that begin with /
> > - symlinks that have paths as above.
>
> I like this a lot. However, I think I'd like it even better if it
> were AT_BENEATH_ONLY so that it could be added to the rest of the *at
> family.
>
> --Andy
Wouldn't it need to be both O_BENEATH_ONLY (for openat()) and
AT_BENEATH_ONLY (for other *at() functions), like O_NOFOLLOW and
AT_SYMLINK_NOFOLLOW? (I.e. aren't the AT_* flags in a different
numbering space than O_* flags?)
Or am I misunderstanding?
^ permalink raw reply
* Re: [PATCH 4/5] man-pages: cap_rights_limit.2: limit FD rights for Capsicum
From: David Drysdale @ 2014-06-30 15:35 UTC (permalink / raw)
To: Andy Lutomirski
Cc: LSM List, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Greg Kroah-Hartman, Alexander Viro, Meredydd Luff, Kees Cook,
James Morris, Linux API
In-Reply-To: <CALCETrUi71FgVABRF4C+n_STc02j=GxRwBqDaoC+NLeAP9Ui3w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Mon, Jun 30, 2014 at 07:53:57AM -0700, Andy Lutomirski wrote:
> On Mon, Jun 30, 2014 at 3:28 AM, David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote:
> > Signed-off-by: David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> > ---
> > man2/cap_rights_limit.2 | 171 ++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 171 insertions(+)
> > create mode 100644 man2/cap_rights_limit.2
> >
> > diff --git a/man2/cap_rights_limit.2 b/man2/cap_rights_limit.2
> > new file mode 100644
> > index 000000000000..3484ee1076aa
> > --- /dev/null
> > +++ b/man2/cap_rights_limit.2
> > @@ -0,0 +1,171 @@
> > +.\"
> > +.\" Copyright (c) 2008-2010 Robert N. M. Watson
> > +.\" Copyright (c) 2012-2013 The FreeBSD Foundation
> > +.\" Copyright (c) 2013-2014 Google, Inc.
> > +.\" All rights reserved.
> > +.\"
> > +.\" %%%LICENSE_START(BSD_2_CLAUSE)
> > +.\" Redistribution and use in source and binary forms, with or without
> > +.\" modification, are permitted provided that the following conditions
> > +.\" are met:
> > +.\" 1. Redistributions of source code must retain the above copyright
> > +.\" notice, this list of conditions and the following disclaimer.
> > +.\" 2. Redistributions in binary form must reproduce the above copyright
> > +.\" notice, this list of conditions and the following disclaimer in the
> > +.\" documentation and/or other materials provided with the distribution.
> > +.\"
> > +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> > +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> > +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> > +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> > +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> > +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> > +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> > +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> > +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> > +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> > +.\" SUCH DAMAGE.
> > +.\" %%%LICENSE_END
> > +.\"
> > +.TH CAP_RIGHTS_LIMIT 2 2014-05-07 "Linux" "Linux Programmer's Manual"
> > +.SH NAME
> > +cap_rights_limit \- limit Capsicum capability rights
> > +.SH SYNOPSIS
> > +.nf
> > +.B #include <sys/capsicum.h>
> > +.sp
> > +.BI "int cap_rights_limit(int " fd ", const struct cap_rights *" rights ,
> > +.BI " unsigned int " fcntls ,
> > +.BI " int " nioctls ", unsigned int *" ioctls );
>
> Am I missing the docs for struct cap_rights somewhere?
There's a little bit of discussion in rights.7 (mail 3/5 of the
man-pages set), but there isn't a structure description.
I was trying to keep the structure opaque to userspace, which would
be expected to manipulate the rights with various utility functions
rather than directly.
But I now realize this leaves a gap -- the description of this syscall
doesn't include a full description of its ABI.
So I'll add in a description of the structure to this page -- basically:
struct cap_rights {
__u64 cr_rights[2];
};
with a slightly complicated scheme to encode rights into the bitmask
array. (The encoding scheme is taken from the FreeBSD implementation,
which I've tried to stick to unless there's good reason to change.)
> > +.SH DESCRIPTION
> > +When a file descriptor is created by a function such as
> > +.BR accept (2),
> > +.BR accept4 (2),
> > +.BR creat (2),
> > +.BR epoll_create (2),
> > +.BR eventfd (2),
> > +.BR mq_open (2),
> > +.BR open (2),
> > +.BR openat (2),
> > +.BR pdfork (2),
> > +.BR pipe (2),
> > +.BR pipe2 (2),
> > +.BR signalfd (2),
> > +.BR socket (2),
> > +.BR socketpair (2)
> > +or
> > +.BR timerfd_create (2),
> > +it implicitly has all Capsicum capability rights.
> > +Those rights can be reduced (but never expanded) by using the
> > +.BR cap_rights_limit ()
> > +system call.
> > +Once Capsicum capability rights are reduced, operations on the file descriptor
> > +.I fd
> > +will be limited to those permitted by the remainder of the arguments.
> > +.PP
> > +The
> > +.I rights
> > +argument describes the primary rights for the file descriptor, and
> > +should be prepared using
> > +.BR cap_rights_init (3)
> > +family of functions. The complete list of primary rights can be found in the
> > +.BR rights (7)
> > +manual page.
> > +.PP
> > +If a file descriptor is granted the
> > +.B CAP_FCNTL
> > +primary capability right, the list of allowed
> > +.BR fcntl (2)
> > +commands can be selectively reduced (but never expanded) with the
> > +.I fcntls
> > +argument. The following flags may be specified in the
> > +.I fcntls
> > +argument:
> > +.TP
> > +.B CAP_FCNTL_GETFL
> > +Permit
> > +.B F_GETFL
> > +command.
> > +.TP
> > +.B CAP_FCNTL_SETFL
> > +Permit
> > +.B F_SETFL
> > +command.
> > +.TP
> > +.B CAP_FCNTL_GETOWN
> > +Permit
> > +.B F_GETOWN
> > +command.
> > +.TP
> > +.B CAP_FCNTL_SETOWN
> > +Permit
> > +.B F_SETOWN
> > +command.
> > +.PP
> > +A value of
> > +.B CAP_FCNTL_ALL
> > +for the
> > +.I fcntls
> > +argument leaves the set of allowed
> > +.BR fcntl (2)
> > +commands unchanged.
>
> What about the locking fcntl operations? (Arguably the old crappy
> POSIX lock operations should be flat-out disallowed on capability fds,
> but I see nothing wrong with selectively allowing the new open file
> description locks.)
>
> --Andy
The locking operations are policed against a separate CAP_FLOCK right,
consistently with flock(2). I'll try to improve the wording -- there
are actually a few fcntl operations that are covered by different
rights because they're analogous to other functionality (e.g.
F_GETPIPE_SZ/F_SETPIPE_SZ needs CAP_GETSOCKOPT/CAP_SETSOCKOPT).
^ permalink raw reply
* Re: [PATCH 4/5] man-pages: cap_rights_limit.2: limit FD rights for Capsicum
From: Andy Lutomirski @ 2014-06-30 14:53 UTC (permalink / raw)
To: David Drysdale
Cc: LSM List, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Greg Kroah-Hartman, Alexander Viro, Meredydd Luff, Kees Cook,
James Morris, Linux API
In-Reply-To: <1404124096-21445-16-git-send-email-drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
On Mon, Jun 30, 2014 at 3:28 AM, David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote:
> Signed-off-by: David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> ---
> man2/cap_rights_limit.2 | 171 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 171 insertions(+)
> create mode 100644 man2/cap_rights_limit.2
>
> diff --git a/man2/cap_rights_limit.2 b/man2/cap_rights_limit.2
> new file mode 100644
> index 000000000000..3484ee1076aa
> --- /dev/null
> +++ b/man2/cap_rights_limit.2
> @@ -0,0 +1,171 @@
> +.\"
> +.\" Copyright (c) 2008-2010 Robert N. M. Watson
> +.\" Copyright (c) 2012-2013 The FreeBSD Foundation
> +.\" Copyright (c) 2013-2014 Google, Inc.
> +.\" All rights reserved.
> +.\"
> +.\" %%%LICENSE_START(BSD_2_CLAUSE)
> +.\" Redistribution and use in source and binary forms, with or without
> +.\" modification, are permitted provided that the following conditions
> +.\" are met:
> +.\" 1. Redistributions of source code must retain the above copyright
> +.\" notice, this list of conditions and the following disclaimer.
> +.\" 2. Redistributions in binary form must reproduce the above copyright
> +.\" notice, this list of conditions and the following disclaimer in the
> +.\" documentation and/or other materials provided with the distribution.
> +.\"
> +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> +.\" SUCH DAMAGE.
> +.\" %%%LICENSE_END
> +.\"
> +.TH CAP_RIGHTS_LIMIT 2 2014-05-07 "Linux" "Linux Programmer's Manual"
> +.SH NAME
> +cap_rights_limit \- limit Capsicum capability rights
> +.SH SYNOPSIS
> +.nf
> +.B #include <sys/capsicum.h>
> +.sp
> +.BI "int cap_rights_limit(int " fd ", const struct cap_rights *" rights ,
> +.BI " unsigned int " fcntls ,
> +.BI " int " nioctls ", unsigned int *" ioctls );
Am I missing the docs for struct cap_rights somewhere?
> +.SH DESCRIPTION
> +When a file descriptor is created by a function such as
> +.BR accept (2),
> +.BR accept4 (2),
> +.BR creat (2),
> +.BR epoll_create (2),
> +.BR eventfd (2),
> +.BR mq_open (2),
> +.BR open (2),
> +.BR openat (2),
> +.BR pdfork (2),
> +.BR pipe (2),
> +.BR pipe2 (2),
> +.BR signalfd (2),
> +.BR socket (2),
> +.BR socketpair (2)
> +or
> +.BR timerfd_create (2),
> +it implicitly has all Capsicum capability rights.
> +Those rights can be reduced (but never expanded) by using the
> +.BR cap_rights_limit ()
> +system call.
> +Once Capsicum capability rights are reduced, operations on the file descriptor
> +.I fd
> +will be limited to those permitted by the remainder of the arguments.
> +.PP
> +The
> +.I rights
> +argument describes the primary rights for the file descriptor, and
> +should be prepared using
> +.BR cap_rights_init (3)
> +family of functions. The complete list of primary rights can be found in the
> +.BR rights (7)
> +manual page.
> +.PP
> +If a file descriptor is granted the
> +.B CAP_FCNTL
> +primary capability right, the list of allowed
> +.BR fcntl (2)
> +commands can be selectively reduced (but never expanded) with the
> +.I fcntls
> +argument. The following flags may be specified in the
> +.I fcntls
> +argument:
> +.TP
> +.B CAP_FCNTL_GETFL
> +Permit
> +.B F_GETFL
> +command.
> +.TP
> +.B CAP_FCNTL_SETFL
> +Permit
> +.B F_SETFL
> +command.
> +.TP
> +.B CAP_FCNTL_GETOWN
> +Permit
> +.B F_GETOWN
> +command.
> +.TP
> +.B CAP_FCNTL_SETOWN
> +Permit
> +.B F_SETOWN
> +command.
> +.PP
> +A value of
> +.B CAP_FCNTL_ALL
> +for the
> +.I fcntls
> +argument leaves the set of allowed
> +.BR fcntl (2)
> +commands unchanged.
What about the locking fcntl operations? (Arguably the old crappy
POSIX lock operations should be flat-out disallowed on capability fds,
but I see nothing wrong with selectively allowing the new open file
description locks.)
--Andy
^ permalink raw reply
* Re: [PATCH 01/11] fs: add O_BENEATH_ONLY flag to openat(2)
From: Andy Lutomirski @ 2014-06-30 14:49 UTC (permalink / raw)
To: David Drysdale
Cc: Al Viro, LSM List, Greg Kroah-Hartman, James Morris, Kees Cook,
Linux API, Meredydd Luff, linux-kernel@vger.kernel.org
In-Reply-To: <1404124096-21445-2-git-send-email-drysdale@google.com>
On Jun 30, 2014 3:36 AM, "David Drysdale" <drysdale@google.com> wrote:
>
> Add a new O_BENEATH_ONLY flag for openat(2) which restricts the
> provided path, rejecting (with -EACCES) paths that are not beneath
> the provided dfd. In particular, reject:
> - paths that contain .. components
> - paths that begin with /
> - symlinks that have paths as above.
I like this a lot. However, I think I'd like it even better if it
were AT_BENEATH_ONLY so that it could be added to the rest of the *at
family.
--Andy
^ permalink raw reply
* [PATCH 5/5] man-pages: cap_rights_get: retrieve Capsicum fd rights
From: David Drysdale @ 2014-06-30 10:28 UTC (permalink / raw)
To: linux-security-module, linux-kernel, Greg Kroah-Hartman
Cc: Alexander Viro, Meredydd Luff, Kees Cook, James Morris, linux-api,
David Drysdale
In-Reply-To: <1404124096-21445-1-git-send-email-drysdale@google.com>
Signed-off-by: David Drysdale <drysdale@google.com>
---
man2/cap_rights_get.2 | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 126 insertions(+)
create mode 100644 man2/cap_rights_get.2
diff --git a/man2/cap_rights_get.2 b/man2/cap_rights_get.2
new file mode 100644
index 000000000000..966c0ed7e336
--- /dev/null
+++ b/man2/cap_rights_get.2
@@ -0,0 +1,126 @@
+.\"
+.\" Copyright (c) 2008-2010 Robert N. M. Watson
+.\" Copyright (c) 2012-2013 The FreeBSD Foundation
+.\" Copyright (c) 2013-2014 Google, Inc.
+.\" All rights reserved.
+.\"
+.\" %%%LICENSE_START(BSD_2_CLAUSE)
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\" %%%LICENSE_END
+.\"
+.TH CAP_RIGHTS_GET 2 2014-05-07 "Linux" "Linux Programmer's Manual"
+.SH NAME
+cap_rights_get \- retrieve Capsicum capability rights
+.SH SYNOPSIS
+.nf
+.B #include <sys/capsicum.h>
+.sp
+.BI "int cap_rights_get(int " fd ", struct cap_rights *" rights ,
+.BI " unsigned int *" fcntls ,
+.BI " int *" nioctls ", unsigned int *" ioctls );
+.SH DESCRIPTION
+Obtain the current Capsicum capability rights for a file descriptor.
+.PP
+The function will fill the
+.I rights
+argument (if non-NULL) with the primary capability rights of the
+.I fd
+descriptor. The result can be examined with the
+.BR cap_rights_is_set (3)
+family of functions. The complete list of primary rights can be found in the
+.BR rights (7)
+manual page.
+.PP
+If the
+.I fcntls
+argument is non-NULL, it will be filled in with a bitmask of allowed
+.BR fcntl (2)
+commands; see
+.BR cap_rights_limit (2)
+for values. If the file descriptor does not have the
+.B CAP_FCNTL
+primary right, the returned
+.I fcntls
+value will be zero.
+.PP
+If the
+.I nioctls
+argument is non-NULL, it will be filled in with the number of allowed
+.BR ioctl (2)
+commands, or with the value CAP_IOCTLS_ALL to indicate that all
+.BR ioctl (2)
+commands are allowed. If the file descriptor does not have the
+.B CAP_IOCTL
+primary right, the returned
+.I nioctls
+value will be zero.
+.PP
+The
+.I ioctls
+argument (if non-NULL) should point at memory that can hold up to
+.I nioctls
+values.
+The system call populates the provided buffer with up to
+.I nioctls
+elements, but always returns the total number of
+.BR ioctl (2)
+commands allowed for the given file descriptor in
+.I nioctls
+as described above.
+.PP
+If all
+.BR ioctl (2)
+commands are allowed (the
+.B CAP_IOCTL
+primary capability right is assigned to the file descriptor and the
+set of allowed
+.BR ioctl (2)
+commands was never limited for this file descriptor), the
+system call will not modify the buffer pointed to by the
+.I ioctls
+argument.
+.PP
+Capsicum capability rights assigned to a file descriptor can be reduced with the
+.BR cap_rights_limit (2)
+system call.
+.SH RETURN VALUE
+.BR cap_rights_get ()
+returns zero on success. On error, -1 is returned and
+.I errno
+is set appropriately.
+.SH ERRORS
+.TP
+.B EBADF
+.I fd
+isn't a valid open file descriptor.
+.TP
+.B EFAULT
+Invalid pointer argument.
+.SH VERSION
+Capsicum support was added to the kernel in version 3.???.
+.SH SEE ALSO
+.BR cap_enter (2),
+.BR cap_rights_limit (2),
+.BR cap_rights_init (3),
+.BR capsicum (7),
+.BR rights (7)
+
--
2.0.0.526.g5318336
^ permalink raw reply related
* [PATCH 4/5] man-pages: cap_rights_limit.2: limit FD rights for Capsicum
From: David Drysdale @ 2014-06-30 10:28 UTC (permalink / raw)
To: linux-security-module, linux-kernel, Greg Kroah-Hartman
Cc: Alexander Viro, Meredydd Luff, Kees Cook, James Morris, linux-api,
David Drysdale
In-Reply-To: <1404124096-21445-1-git-send-email-drysdale@google.com>
Signed-off-by: David Drysdale <drysdale@google.com>
---
man2/cap_rights_limit.2 | 171 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 171 insertions(+)
create mode 100644 man2/cap_rights_limit.2
diff --git a/man2/cap_rights_limit.2 b/man2/cap_rights_limit.2
new file mode 100644
index 000000000000..3484ee1076aa
--- /dev/null
+++ b/man2/cap_rights_limit.2
@@ -0,0 +1,171 @@
+.\"
+.\" Copyright (c) 2008-2010 Robert N. M. Watson
+.\" Copyright (c) 2012-2013 The FreeBSD Foundation
+.\" Copyright (c) 2013-2014 Google, Inc.
+.\" All rights reserved.
+.\"
+.\" %%%LICENSE_START(BSD_2_CLAUSE)
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\" %%%LICENSE_END
+.\"
+.TH CAP_RIGHTS_LIMIT 2 2014-05-07 "Linux" "Linux Programmer's Manual"
+.SH NAME
+cap_rights_limit \- limit Capsicum capability rights
+.SH SYNOPSIS
+.nf
+.B #include <sys/capsicum.h>
+.sp
+.BI "int cap_rights_limit(int " fd ", const struct cap_rights *" rights ,
+.BI " unsigned int " fcntls ,
+.BI " int " nioctls ", unsigned int *" ioctls );
+.SH DESCRIPTION
+When a file descriptor is created by a function such as
+.BR accept (2),
+.BR accept4 (2),
+.BR creat (2),
+.BR epoll_create (2),
+.BR eventfd (2),
+.BR mq_open (2),
+.BR open (2),
+.BR openat (2),
+.BR pdfork (2),
+.BR pipe (2),
+.BR pipe2 (2),
+.BR signalfd (2),
+.BR socket (2),
+.BR socketpair (2)
+or
+.BR timerfd_create (2),
+it implicitly has all Capsicum capability rights.
+Those rights can be reduced (but never expanded) by using the
+.BR cap_rights_limit ()
+system call.
+Once Capsicum capability rights are reduced, operations on the file descriptor
+.I fd
+will be limited to those permitted by the remainder of the arguments.
+.PP
+The
+.I rights
+argument describes the primary rights for the file descriptor, and
+should be prepared using
+.BR cap_rights_init (3)
+family of functions. The complete list of primary rights can be found in the
+.BR rights (7)
+manual page.
+.PP
+If a file descriptor is granted the
+.B CAP_FCNTL
+primary capability right, the list of allowed
+.BR fcntl (2)
+commands can be selectively reduced (but never expanded) with the
+.I fcntls
+argument. The following flags may be specified in the
+.I fcntls
+argument:
+.TP
+.B CAP_FCNTL_GETFL
+Permit
+.B F_GETFL
+command.
+.TP
+.B CAP_FCNTL_SETFL
+Permit
+.B F_SETFL
+command.
+.TP
+.B CAP_FCNTL_GETOWN
+Permit
+.B F_GETOWN
+command.
+.TP
+.B CAP_FCNTL_SETOWN
+Permit
+.B F_SETOWN
+command.
+.PP
+A value of
+.B CAP_FCNTL_ALL
+for the
+.I fcntls
+argument leaves the set of allowed
+.BR fcntl (2)
+commands unchanged.
+.PP
+If a file descriptor is granted the
+.B CAP_IOCTL
+capability right, the list of allowed
+.BR ioctl (2)
+commands can be selectively reduced (but never expanded) using the
+.I nioctls
+and
+.I ioctls
+arguments.
+The
+.I ioctls
+argument is an array of
+.BR ioctl (2)
+command values and the
+.I nioctls
+argument specifies the number of elements in the array.
+.PP
+If the
+.I nioctls
+argument is -1 or 0, the
+.I ioctls
+argument is ignored, and either all
+.BR ioctl (2)
+operations or no
+.BR ioctl (2)
+operations (respectively) will be allowed.
+.PP
+Capsicum capability rights assigned to a file descriptor can be obtained with the
+.BR cap_rights_get (2)
+system call.
+.SH RETURN VALUE
+.BR cap_rights_limit ()
+returns zero on success. On error, -1 is returned and
+.I errno
+is set appropriately.
+.SH ERRORS
+.TP
+.B EBADF
+.I fd
+isn't a valid open file descriptor.
+.TP
+.B EINVAL
+An invalid set of rights has been requested in
+.IR rights .
+.TP
+.B ENOMEM
+Out of memory.
+.TP
+.B ENOTCAPABLE
+The arguments contain capability rights not present for the given file descriptor (Capsicum
+capability rights list can only be reduced, never expanded).
+.SH VERSION
+Capsicum support was added to the kernel in version 3.???.
+.SH SEE ALSO
+.BR cap_enter (2),
+.BR cap_rights_get (2),
+.BR cap_rights_init (3),
+.BR capsicum (7),
+.BR rights (7)
--
2.0.0.526.g5318336
^ permalink raw reply related
* [PATCH 3/5] man-pages: rights.7: Describe Capsicum primary rights
From: David Drysdale @ 2014-06-30 10:28 UTC (permalink / raw)
To: linux-security-module, linux-kernel, Greg Kroah-Hartman
Cc: Alexander Viro, Meredydd Luff, Kees Cook, James Morris, linux-api,
David Drysdale
In-Reply-To: <1404124096-21445-1-git-send-email-drysdale@google.com>
Signed-off-by: David Drysdale <drysdale@google.com>
---
man7/rights.7 | 525 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 525 insertions(+)
create mode 100644 man7/rights.7
diff --git a/man7/rights.7 b/man7/rights.7
new file mode 100644
index 000000000000..33bb8e48d12f
--- /dev/null
+++ b/man7/rights.7
@@ -0,0 +1,525 @@
+.\"
+.\" Copyright (c) 2014 Google, Inc.
+.\" Copyright (c) 2012-2013 The FreeBSD Foundation
+.\" Copyright (c) 2008-2010 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed at the University of Cambridge Computer
+.\" Laboratory with support from a grant from Google, Inc.
+.\"
+.\" %%%LICENSE_START(BSD_2_CLAUSE)
+.\" Portions of this documentation were written by Pawel Jakub Dawidek
+.\" under sponsorship from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\" %%%LICENSE_END
+.\"
+.TH RIGHTS 7 2014-05-07 "Linux" "Linux Programmer's Manual"
+.SH NAME
+Capsicum capability rights for file descriptors
+.SH SYNOPSIS
+.B #include <linux/capsicum.h>
+.SH DESCRIPTION
+When a file descriptor is created by a function such as
+.BR accept (2),
+.BR accept4 (2),
+.BR creat (2),
+.BR epoll_create (2),
+.BR eventfd (2),
+.BR mq_open (2),
+.BR open (2),
+.BR openat (2),
+.BR pdfork (2),
+.BR pipe (2),
+.BR pipe2 (2),
+.BR signalfd (2),
+.BR socket (2),
+.BR socketpair (2)
+or
+.BR timerfd_create (2),
+it implicitly has all Capsicum capability rights.
+Those rights can be reduced (but never expanded) by using the
+.BR cap_rights_limit (2)
+system call.
+Once capability rights are reduced, operations on the file descriptor will be
+limited to those permitted by the associated rights.
+.Pp
+The list of primary capability rights is provided below. In addition,
+.BR ioctl (2)
+and
+.BR fcntl (2)
+can also be restricted to only allow specific commands.
+.PP
+The
+.I "struct cap_rights"
+type is used to store a list of primary capability rights; the
+.BR cap_rights_init (3)
+family of functions should be used to manage the structure.
+.SH RIGHTS
+The following rights may be specified in a rights mask:
+.TP
+.B CAP_ACCEPT
+Permit
+.BR accept (2)
+and
+.BR accept4 (2).
+.TP
+.B CAP_BIND
+Permit
+.BR bind (2).
+Note that sockets can also become bound implicitly as a result of
+.BR connect (2)
+or
+.BR send (2),
+and that socket options set with
+.BR setsockopt (2)
+may also affect binding behavior.
+.TP
+.B CAP_CONNECT
+Permit
+.BR connect (2);
+also required for
+.BR sendto (2)
+with a non-NULL destination address.
+.TP
+.B CAP_CREATE
+Permit
+.BR openat (2)
+with the
+.B O_CREAT
+flag.
+.TP
+.B CAP_EVENT
+Permit
+.BR select (2),
+.BR poll (2),
+and
+.BR epoll (7)
+to be used in monitoring the file descriptor for events.
+.TP
+.B CAP_EXTATTR_DELETE
+Permit
+.BR fremovexattr (2).
+.TP
+.B CAP_EXTATTR_GET
+Permit
+.BR fgetxattr (2).
+.TP
+.B CAP_EXTATTR_LIST
+Permit
+.BR flistxattr (2).
+.TP
+.B CAP_EXTATTR_SET
+Permit
+.BR fsetxattr (2).
+.TP
+.B CAP_FCHDIR
+Permit
+.BR fchdir (2).
+.TP
+.B CAP_FCHMOD
+Permit
+.BR fchmod (2)
+and
+.BR fchmodat (2)
+if the
+.B CAP_LOOKUP
+right is also present.
+.TP
+.B CAP_FCHMODAT
+An alias to
+.B CAP_FCHMOD
+and
+.BR CAP_LOOKUP .
+.TP
+.B CAP_FCHOWN
+Permit
+.BR fchown (2)
+and
+.BR fchownat (2)
+if the
+.B CAP_LOOKUP
+right is also present.
+.TP
+.B CAP_FCHOWNAT
+An alias to
+.B CAP_FCHOWN
+and
+.BR CAP_LOOKUP .
+.TP
+.B CAP_FCNTL
+Permit
+.BR fcntl (2).
+Note that only the
+.BR F_GETFL ,
+.BR F_SETFL ,
+.B F_GETOWN ,
+.B F_SETOWN ,
+.B F_GETOWN_EX
+and
+.B F_SETOWN_EX
+commands require this capability right.
+Also note that the list of permitted commands can be further limited with the
+.BR cap_rights_limit (2)
+system call.
+.TP
+.B CAP_FEXECVE
+Permit
+.BR execveat (2)
+and
+.BR openat (2)
+with the
+.B O_EXEC
+flag;
+.B CAP_READ
+is also required.
+.TP
+.B CAP_FLOCK
+Permit
+.BR flock (2)
+and
+.BR fcntl (2)
+(with
+.BR F_GETLK ,
+.BR F_SETLK
+or
+.B F_SETLKW
+flag).
+.TP
+.B CAP_FSTAT
+Permit
+.BR fstat (2).
+.TP
+.B CAP_FSTATFS
+Permit
+.BR fstatfs (2).
+.TP
+.B CAP_FSYNC
+Permit
+.BR fsync (2)
+and
+.BR openat (2)
+with the
+.B O_SYNC
+flag.
+.TP
+.B CAP_FTRUNCATE
+Permit
+.BR ftruncate (2)
+and
+.BR openat (2)
+with the
+.B O_TRUNC
+flag.
+.TP
+.B CAP_FUTIMES
+Permit
+.BR futimesat (2)
+if the
+.B CAP_LOOKUP
+right is also present.
+.TP
+.B CAP_FUTIMESAT
+An alias to
+.B CAP_FUTIMES
+and
+.BR CAP_LOOKUP .
+.TP
+.B CAP_GETPEERNAME
+Permit
+.BR getpeername (2).
+.TP
+.B CAP_GETSOCKNAME
+Permit
+.BR getsockname (2).
+.TP
+.B CAP_GETSOCKOPT
+Permit
+.BR getsockopt (2).
+.TP
+.B CAP_IOCTL
+Permit
+.BR ioctl (2).
+Be aware that this system call has enormous scope, including potentially
+global scope for some objects.
+The list of permitted ioctl commands can be further limited with the
+.BR cap_rights_limit (2)
+system call.
+.TP
+.B CAP_LINKAT
+Permit
+.BR linkat (2)
+and
+.BR renameat (2)
+on the destination directory descriptor.
+This right includes the
+.B CAP_LOOKUP
+right.
+.TP
+.B CAP_LISTEN
+Permit
+.BR listen (2);
+not much use (generally) without
+.BR CAP_BIND .
+.TP
+.B CAP_LOOKUP
+Permit the file descriptor to be used as a starting directory for calls such as
+.BR linkat (2),
+.BR openat (2),
+and
+.BR unlinkat (2).
+.TP
+.B CAP_MKDIRAT
+Permit
+.BR mkdirat (2).
+This right includes the
+.B CAP_LOOKUP
+right.
+.TP
+.B CAP_MKFIFOAT
+Permit
+.BR mkfifoat (2).
+This right includes the
+.B CAP_LOOKUP
+right.
+.TP
+.B CAP_MKNODAT
+Permit
+.BR mknodat (2).
+This right includes the
+.B CAP_LOOKUP
+right.
+.TP
+.B CAP_MMAP
+Permit
+.BR mmap (2)
+with the
+.B PROT_NONE
+protection.
+.TP
+.B CAP_MMAP_R
+Permit
+.BR mmap (2)
+with the
+.B PROT_READ
+protection.
+This right includes the
+.B CAP_READ
+and
+.B CAP_SEEK
+rights.
+.TP
+.B CAP_MMAP_RW
+An alias to
+.B CAP_MMAP_R
+and
+.BR CAP_MMAP_W .
+.TP
+.B CAP_MMAP_RWX
+An alias to
+.BR CAP_MMAP_R ,
+.B CAP_MMAP_W
+and
+.BR CAP_MMAP_X .
+.TP
+.B CAP_MMAP_RX
+An alias to
+.B CAP_MMAP_R
+and
+.BR CAP_MMAP_X .
+.TP
+.B CAP_MMAP_W
+Permit
+.BR mmap (2)
+with the
+.B PROT_WRITE
+protection.
+This right includes the
+.B CAP_WRITE
+and
+.B CAP_SEEK
+rights.
+.TP
+.B CAP_MMAP_WX
+An alias to
+.B CAP_MMAP_W
+and
+.BR CAP_MMAP_X .
+.TP
+.B CAP_MMAP_X
+Permit
+.BR mmap (2)
+with the
+.B PROT_EXEC
+protection.
+This right includes the
+.B CAP_SEEK
+right.
+.TP
+.B CAP_PDGETPID
+Permit
+.BR pdgetpid (2).
+.TP
+.B CAP_PDKILL
+Permit
+.BR pdkill (2).
+.TP
+.B CAP_PDWAIT
+Permit
+.BR pdwait4 (2).
+.TP
+.B CAP_PEELOFF
+Permit
+.BR sctp_peeloff (3).
+.TP
+.B CAP_PREAD
+An alias to
+.B CAP_READ
+and
+.BR CAP_SEEK .
+.TP
+.B CAP_PWRITE
+An alias to
+.B CAP_SEEK
+and
+.BR CAP_WRITE .
+.TP
+.B CAP_READ
+Permit
+.BR openat (2)
+with the
+.BR O_RDONLY flag,
+.BR read (2),
+.BR readv (2),
+.BR recv (2),
+.BR recvfrom (2),
+.BR recvmsg (2),
+.BR pread (2)
+(
+.B CAP_SEEK
+is also required),
+.BR preadv (2)
+(
+.B CAP_SEEK
+is also required) and related system calls.
+.TP
+.B CAP_RECV
+An alias to
+.BR CAP_READ .
+.TP
+.B CAP_RENAMEAT
+Permit
+.BR renameat (2).
+This right is required on the source directory descriptor.
+This right includes the
+.B CAP_LOOKUP
+right.
+.TP
+.B CAP_SEEK
+Permit operations that seek on the file descriptor, such as
+.BR lseek (2),
+but also required for I/O system calls that can read or write at any position
+in the file, such as
+.BR pread (2)
+and
+.BR pwrite (2).
+.TP
+.B CAP_SEND
+An alias to
+.BR CAP_WRITE .
+.TP
+.B CAP_SETSOCKOPT
+Permit
+.BR setsockopt (2);
+this controls various aspects of socket behavior and may affect binding,
+connecting, and other behaviors with global scope.
+.TP
+.B CAP_SHUTDOWN
+Permit explicit
+.BR shutdown (2);
+closing the socket will also generally shut down any connections on it.
+.TP
+.B CAP_SYMLINKAT
+Permit
+.BR symlinkat (2).
+This right includes the
+.B CAP_LOOKUP
+right.
+.TP
+.B CAP_UNLINKAT
+Permit
+.BR unlinkat (2)
+and
+.BR renameat (2).
+This right is only required for
+.BR renameat (2)
+on the destination directory descriptor if the destination object already
+exists and will be removed by the rename.
+This right includes the
+.B CAP_LOOKUP
+right.
+.TP
+.B CAP_WRITE
+Allow
+.BR openat (2)
+with
+.B O_WRONLY
+and
+.B O_APPEND
+flags set,
+.BR send (2),
+.BR sendmsg (2),
+.BR sendto (2),
+.BR write (2),
+.BR writev (2),
+.BR pwrite (2),
+.BR pwritev (2)
+and related system calls.
+For
+.BR sendto (2)
+with a non-NULL connection address,
+.B CAP_CONNECT
+is also required.
+For
+.BR openat (2)
+with the
+.B O_WRONLY
+flag, but without the
+.B O_APPEND
+flag,
+.B CAP_SEEK
+is also required.
+For
+.BR pwrite (2)
+and
+.BR pwritev (2)
+.B CAP_SEEK
+is also required.
+.SH VERSIONS
+Capsicum support was originally added to the kernel in version 3.???.
+.SH SEE ALSO
+.BR cap_enter (3),
+.BR cap_fcntls_limit (3),
+.BR cap_ioctls_limit (3),
+.BR cap_rights_limit (2),
+.BR cap_rights_limit (3),
+.BR capsicum (7)
--
2.0.0.526.g5318336
^ permalink raw reply related
* [PATCH 2/5] man-pages: capsicum.7: describe Capsicum capability framework
From: David Drysdale @ 2014-06-30 10:28 UTC (permalink / raw)
To: linux-security-module, linux-kernel, Greg Kroah-Hartman
Cc: Alexander Viro, Meredydd Luff, Kees Cook, James Morris, linux-api,
David Drysdale
In-Reply-To: <1404124096-21445-1-git-send-email-drysdale@google.com>
Signed-off-by: David Drysdale <drysdale@google.com>
---
man7/capsicum.7 | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
create mode 100644 man7/capsicum.7
diff --git a/man7/capsicum.7 b/man7/capsicum.7
new file mode 100644
index 000000000000..e736060bb5bc
--- /dev/null
+++ b/man7/capsicum.7
@@ -0,0 +1,97 @@
+.\"
+.\" Copyright (c) 2014 Google, Inc.
+.\" Copyright (c) 2011, 2013 Robert N. M. Watson
+.\" Copyright (c) 2011 Jonathan Anderson
+.\" All rights reserved.
+.\"
+.\" %%%LICENSE_START(BSD_2_CLAUSE)
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\" %%%LICENSE_END
+.\"
+.TH CAPSICUM 7 2014-05-07 "Linux" "Linux Programmer's Manual"
+.SH NAME
+capsicum \- lightweight OS capability and sandbox framework
+.SH SYNOPSIS
+.B #include <sys/capsicum.h>
+.SH DESCRIPTION
+Capsicum is a lightweight OS capability and sandbox framework implementing a hybrid
+capability system model.
+Capsicum can be used for application and library compartmentalisation, the
+decomposition of larger bodies of software into isolated (sandboxed)
+components in order to implement security policies and limit the impact of
+software vulnerabilities.
+.PP
+Capsicum provides three core kernel mechanisms,
+.IR "Capsicum capabilities",
+.I "capability mode"
+and
+.IR "process descriptors",
+each described below.
+
+.SS Capsicum Capabilities
+A
+.I Capsicum capability
+is a file descriptor that has been limited so that only
+certain operations can be performed on it.
+For example, a file descriptor returned by
+.BR open (2)
+may be refined using
+.BR cap_rights_limit (2)
+so that only
+.BR read (2)
+and
+.BR write (2)
+can be called on it, but not
+.BR fchmod (2).
+The complete list of the capability rights can be found in the
+.BR rights (7)
+manual page.
+
+.SS Capability Mode
+Capsicum capability mode is a process mode, entered by invoking
+.BR cap_enter (3),
+in which access to global OS namespaces (such as the file system and PID
+namespaces) is restricted; only explicitly delegated rights, referenced by
+memory mappings or file descriptors, may be used.
+Once set, the flag is inherited by future children processes, and may not be
+cleared.
+
+.SS Process Descriptors
+.I Process descriptors
+are file descriptors representing processes, allowing parent processes to manage
+child processes without requiring access to the PID namespace, and are described in
+greater detail in
+.BR procdesc (7).
+.SH VERSIONS
+Capsicum support is available in the kernel since version 3.???.
+.SH SEE ALSO
+.BR cap_enter (3),
+.BR cap_getmode (3) ,
+.BR cap_rights_get (2),
+.BR cap_rights_limit (2) ,
+.BR pdfork (2),
+.BR pdgetpid (2),
+.BR pdkill (2),
+.BR pdwait4 (2),
+.BR procdesc (7),
+.BR rights (7)
+
--
2.0.0.526.g5318336
^ permalink raw reply related
* [PATCH 1/5] man-pages: open.2: describe O_BENEATH_ONLY flag
From: David Drysdale @ 2014-06-30 10:28 UTC (permalink / raw)
To: linux-security-module, linux-kernel, Greg Kroah-Hartman
Cc: Alexander Viro, Meredydd Luff, Kees Cook, James Morris, linux-api,
David Drysdale
In-Reply-To: <1404124096-21445-1-git-send-email-drysdale@google.com>
Signed-off-by: David Drysdale <drysdale@google.com>
---
man2/open.2 | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/man2/open.2 b/man2/open.2
index 3824ab5be1f0..ba0da01c1a4f 100644
--- a/man2/open.2
+++ b/man2/open.2
@@ -713,7 +713,7 @@ in a fully formed state (using
as described above).
.RE
.IP
-.B O_TMPFILE
+.B O_TMPFILE " (since Linux 3.??)"
requires support by the underlying filesystem;
only a subset of Linux filesystems provide that support.
In the initial implementation, support was provided in
@@ -723,6 +723,31 @@ XFS support was added
.\" commit ab29743117f9f4c22ac44c13c1647fb24fb2bafe
in Linux 3.15.
.TP
+.B O_BENEATH_ONLY
+Ensure that the
+.I pathname
+is beneath the current working directory (for
+.BR open (2))
+or the
+.I dirfd
+(for
+.BR openat (2)).
+If the
+.I pathname
+is absolute or contains a path component of "..", the
+.BR open ()
+fails with the error
+.BR EACCES.
+This occurs even if ".." path component would not actually
+escape the original directory; for example, a
+.I pathname
+of "subdir/../filename" would be rejected.
+Path components that are symbolic links to absolute paths, or that are
+relative paths containing a ".." component, are cause the
+.BR open ()
+operation to fail with the error
+.BR EACCES.
+.TP
.B O_TRUNC
If the file already exists and is a regular file and the access mode allows
writing (i.e., is
@@ -799,7 +824,11 @@ The requested access to the file is not allowed, or search permission
is denied for one of the directories in the path prefix of
.IR pathname ,
or the file did not exist yet and write access to the parent directory
-is not allowed.
+is not allowed, or the
+.B O_BENEATH_ONLY
+flag was specified and the
+.I pathname
+was not beneath the relevant directory.
(See also
.BR path_resolution (7).)
.TP
--
2.0.0.526.g5318336
^ permalink raw reply related
* [PATCH 11/11] capsicum: add syscalls to limit FD rights
From: David Drysdale @ 2014-06-30 10:28 UTC (permalink / raw)
To: linux-security-module, linux-kernel, Greg Kroah-Hartman
Cc: Alexander Viro, Meredydd Luff, Kees Cook, James Morris, linux-api,
David Drysdale
In-Reply-To: <1404124096-21445-1-git-send-email-drysdale@google.com>
Add the cap_rights_get(2) and cap_rights_set(2) syscalls to
allow retrieval and modification of the rights associated with
a file descriptor.
When a normal file descriptor has its rights restricted in any
way, it becomes a Capsicum capability file descriptor. This is
a wrapper struct file that is installed in the fdtable in place
of the original file. From this point on, when the FD is converted
to a struct file by fget() (or equivalent), the wrapper is checked
for the appropriate rights and the wrapped inner normal file is
returned.
When a Capsicum capability file descriptor has its rights restricted
further (they cannot be expanded), a new wrapper is created with
the restricted rights, also wrapping the same inner normal file.
In other words, the .underlying field in a struct capsicum_capability
is always a normal file, never another Capsicum capability file.
These syscalls specify the different components of the compound
rights structure separately, allowing components to be unspecified
for no change.
Note that in FreeBSD 10.x the function of this pair of syscalls
is implemented as 3 distinct pairs of syscalls, one pair for each
component of the compound rights (primary/fcntl/ioctl).
Signed-off-by: David Drysdale <drysdale@google.com>
---
arch/x86/syscalls/syscall_64.tbl | 2 +
include/linux/syscalls.h | 12 ++++
kernel/sys_ni.c | 4 ++
security/capsicum.c | 143 +++++++++++++++++++++++++++++++++++++++
4 files changed, 161 insertions(+)
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index 04376ac3d9ef..d408116dace5 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -323,6 +323,8 @@
314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr
316 common renameat2 sys_renameat2
+318 common cap_rights_limit sys_cap_rights_limit
+319 common cap_rights_get sys_cap_rights_get
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a4a0588c5397..55666f3a4185 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -65,6 +65,7 @@ struct old_linux_dirent;
struct perf_event_attr;
struct file_handle;
struct sigaltstack;
+struct cap_rights;
#include <linux/types.h>
#include <linux/aio_abi.h>
@@ -866,4 +867,15 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2);
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
+asmlinkage long sys_cap_rights_limit(unsigned int orig_fd,
+ const struct cap_rights __user *new_rights,
+ unsigned int fcntls,
+ int nioctls,
+ unsigned int __user *ioctls);
+asmlinkage long sys_cap_rights_get(unsigned int fd,
+ struct cap_rights __user *rightsp,
+ unsigned int __user *fcntls,
+ int __user *nioctls,
+ unsigned int __user *ioctls);
+
#endif
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index bc8d1b74a6b9..2f09e5ee64f7 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -211,3 +211,7 @@ cond_syscall(compat_sys_open_by_handle_at);
/* compare kernel pointers */
cond_syscall(sys_kcmp);
+
+/* capsicum object capabilities */
+cond_syscall(sys_cap_rights_get);
+cond_syscall(sys_cap_rights_limit);
diff --git a/security/capsicum.c b/security/capsicum.c
index 83677eef3fb6..4e4458801866 100644
--- a/security/capsicum.c
+++ b/security/capsicum.c
@@ -125,6 +125,149 @@ out_err:
return ERR_PTR(err);
}
+/* Takes ownership of rights->ioctls */
+static int capsicum_rights_limit(unsigned int fd,
+ struct capsicum_rights *rights)
+{
+ int rc = -EBADF;
+ struct capsicum_capability *cap;
+ struct file *capf = NULL;
+ struct file *file; /* current file for fd */
+ struct file *underlying; /* base file for capability */
+ struct files_struct *files = current->files;
+ struct fdtable *fdt;
+
+ /* Allocate capability before taking files->file_lock */
+ capf = capsicum_cap_alloc(rights, true);
+ rights->ioctls = NULL; /* capsicum_cap_alloc took ownership */
+ if (IS_ERR(capf))
+ return PTR_ERR(capf);
+ cap = capf->private_data;
+
+ spin_lock(&files->file_lock);
+ fdt = files_fdtable(files);
+ if (fd >= fdt->max_fds)
+ goto out_err;
+ file = fdt->fd[fd];
+ if (!file)
+ goto out_err;
+
+ /* If we're limiting an existing Capsicum capability object, ensure
+ * we wrap its underlying normal file. */
+ if (capsicum_is_cap(file)) {
+ struct capsicum_capability *old_cap = file->private_data;
+ /* Reject attempts to widen existing rights */
+ if (!cap_rights_contains(&old_cap->rights, &cap->rights)) {
+ rc = -ENOTCAPABLE;
+ goto out_err;
+ }
+ underlying = old_cap->underlying;
+ } else {
+ underlying = file;
+ }
+ if (!atomic_long_inc_not_zero(&underlying->f_count)) {
+ rc = -EBADF;
+ goto out_err;
+ }
+ cap->underlying = underlying;
+
+ fput(file);
+ rcu_assign_pointer(fdt->fd[fd], capf);
+ spin_unlock(&files->file_lock);
+ return 0;
+out_err:
+ spin_unlock(&files->file_lock);
+ fput(capf);
+ return rc;
+}
+
+SYSCALL_DEFINE5(cap_rights_limit,
+ unsigned int, fd,
+ const struct cap_rights __user *, new_rights,
+ unsigned int, new_fcntls,
+ int, nioctls,
+ unsigned int __user *, new_ioctls)
+{
+ struct capsicum_rights rights;
+
+ if (!new_rights)
+ return -EFAULT;
+ if (nioctls < 0 && nioctls != -1)
+ return -EINVAL;
+ if (copy_from_user(&rights.primary, new_rights,
+ sizeof(struct cap_rights)))
+ return -EFAULT;
+ rights.fcntls = new_fcntls;
+ rights.nioctls = nioctls;
+ if (rights.nioctls > 0) {
+ size_t size;
+ if (!new_ioctls)
+ return -EINVAL;
+ size = rights.nioctls * sizeof(unsigned int);
+ rights.ioctls = kmalloc(size, GFP_KERNEL);
+ if (!rights.ioctls)
+ return -ENOMEM;
+ if (copy_from_user(rights.ioctls, new_ioctls, size)) {
+ kfree(rights.ioctls);
+ return -EFAULT;
+ }
+ } else {
+ rights.ioctls = NULL;
+ }
+ if (cap_rights_regularize(&rights))
+ return -ENOTCAPABLE;
+
+ return capsicum_rights_limit(fd, &rights);
+}
+
+SYSCALL_DEFINE5(cap_rights_get,
+ unsigned int, fd,
+ struct cap_rights __user *, rightsp,
+ unsigned int __user *, fcntls,
+ int __user *, nioctls,
+ unsigned int __user *, ioctls)
+{
+ int result = -EFAULT;
+ struct file *file;
+ struct capsicum_rights *rights = &all_rights;
+ int ioctls_to_copy = -1;
+
+ file = fget_raw(fd);
+ if (file == NULL)
+ return -EBADF;
+ if (capsicum_is_cap(file)) {
+ struct capsicum_capability *cap = file->private_data;
+ rights = &cap->rights;
+ }
+
+ if (rightsp) {
+ if (copy_to_user(rightsp, &rights->primary,
+ sizeof(struct cap_rights)))
+ goto out;
+ }
+ if (fcntls) {
+ if (put_user(rights->fcntls, fcntls))
+ goto out;
+ }
+ if (nioctls) {
+ int n;
+ if (get_user(n, nioctls))
+ goto out;
+ if (put_user(rights->nioctls, nioctls))
+ goto out;
+ ioctls_to_copy = min(rights->nioctls, n);
+ }
+ if (ioctls && ioctls_to_copy > 0) {
+ if (copy_to_user(ioctls, rights->ioctls,
+ ioctls_to_copy * sizeof(unsigned int)))
+ goto out;
+ }
+ result = 0;
+out:
+ fput(file);
+ return result;
+}
+
/*
* File operations functions.
*/
--
2.0.0.526.g5318336
^ permalink raw reply related
* [PATCH 10/11] capsicum: invocation of new LSM hooks
From: David Drysdale @ 2014-06-30 10:28 UTC (permalink / raw)
To: linux-security-module, linux-kernel, Greg Kroah-Hartman
Cc: Alexander Viro, Meredydd Luff, Kees Cook, James Morris, linux-api,
David Drysdale
In-Reply-To: <1404124096-21445-1-git-send-email-drysdale@google.com>
Places that call fcheck() to convert a file descriptor into a
struct file need to call the new .file_lookup LSM hook. The
most important instances of this are in the fget() function,
but there are a few other direct users of fcheck().
If a new file descriptor is created from an existing file
descriptor, then any rights associated with the original FD
need to be propagated to the new FD. The .file_install LSM
hook takes care of this, by potentially changing the struct
file that is about to be installed into the FD table. This
affects accept(2) and openat(2); for the latter, the rights
associated with the dfd need to be propagated through the
code in fs/namei.c to allow this.
The path walking code in fs/namei.c is also modified to enable
the O_BENEATH_ONLY flag if the process is in capability mode,
or if the dfd is a Capsicum capability.
Signed-off-by: David Drysdale <drysdale@google.com>
---
arch/powerpc/platforms/cell/spufs/coredump.c | 2 +
fs/file.c | 2 +-
fs/locks.c | 2 +
fs/namei.c | 217 ++++++++++++++++++++-------
fs/notify/dnotify/dnotify.c | 2 +
fs/proc/fd.c | 16 +-
net/socket.c | 10 +-
7 files changed, 192 insertions(+), 59 deletions(-)
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index be6212ddbf06..589fad12c715 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -29,6 +29,7 @@
#include <linux/syscalls.h>
#include <linux/coredump.h>
#include <linux/binfmts.h>
+#include <linux/security.h>
#include <asm/uaccess.h>
@@ -101,6 +102,7 @@ static struct spu_context *coredump_next_context(int *fd)
return NULL;
*fd = n - 1;
file = fcheck(*fd);
+ file = security_file_lookup(file, NULL, NULL);
return SPUFS_I(file_inode(file))->i_ctx;
}
diff --git a/fs/file.c b/fs/file.c
index 562cc82ba442..5a784234fd3a 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -742,7 +742,7 @@ static struct file *unwrap_file(struct file *orig,
return ERR_PTR(-EBADF);
if (IS_ERR(orig))
return orig;
- f = orig; /* TODO: pass to an LSM hook here */
+ f = security_file_lookup(orig, required_rights, actual_rights);
if (f != orig && update_refcnt) {
/* We're not returning the original, and the calling code
* has already incremented the refcount on it, we need to
diff --git a/fs/locks.c b/fs/locks.c
index 375fac3392b9..fd95ced5ced1 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2121,6 +2121,7 @@ again:
*/
spin_lock(¤t->files->file_lock);
f = fcheck(fd);
+ f = security_file_lookup(f, NULL, NULL);
spin_unlock(¤t->files->file_lock);
if (!error && f != filp && flock.l_type != F_UNLCK) {
flock.l_type = F_UNLCK;
@@ -2255,6 +2256,7 @@ again:
*/
spin_lock(¤t->files->file_lock);
f = fcheck(fd);
+ f = security_file_lookup(f, NULL, NULL);
spin_unlock(¤t->files->file_lock);
if (!error && f != filp && flock.l_type != F_UNLCK) {
flock.l_type = F_UNLCK;
diff --git a/fs/namei.c b/fs/namei.c
index c93f7993960e..001baf46b7a5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -34,6 +34,7 @@
#include <linux/device_cgroup.h>
#include <linux/fs_struct.h>
#include <linux/posix_acl.h>
+#include <linux/capsicum.h>
#include <asm/uaccess.h>
#include "internal.h"
@@ -1750,7 +1751,7 @@ static int link_path_walk(const char *name, struct nameidata *nd,
{
struct path next;
int err;
-
+
while (*name == '/') {
if (flags & LOOKUP_BENEATH_ONLY) {
err = -EACCES;
@@ -1836,15 +1837,18 @@ exit:
return err;
}
-static int path_init(int dfd, const char *name, unsigned int flags,
- struct nameidata *nd, struct file **fp)
+static int path_init(int dfd, const char *name, unsigned int *flags,
+ struct nameidata *nd, struct file **fp,
+ const struct capsicum_rights **dfd_rights,
+ const struct capsicum_rights *rights)
{
int retval = 0;
nd->last_type = LAST_ROOT; /* if there are only slashes... */
- nd->flags = flags | LOOKUP_JUMPED;
+ nd->flags = (*flags) | LOOKUP_PARENT | LOOKUP_JUMPED;
nd->depth = 0;
- if (flags & LOOKUP_ROOT) {
+
+ if ((*flags) & LOOKUP_ROOT) {
struct dentry *root = nd->root.dentry;
struct inode *inode = root->d_inode;
if (*name) {
@@ -1856,7 +1860,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
}
nd->path = nd->root;
nd->inode = inode;
- if (flags & LOOKUP_RCU) {
+ if ((*flags) & LOOKUP_RCU) {
rcu_read_lock();
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
nd->m_seq = read_seqbegin(&mount_lock);
@@ -1870,9 +1874,11 @@ static int path_init(int dfd, const char *name, unsigned int flags,
nd->m_seq = read_seqbegin(&mount_lock);
if (*name=='/') {
- if (flags & LOOKUP_BENEATH_ONLY)
+ if ((*flags) & LOOKUP_BENEATH_ONLY)
return -EACCES;
- if (flags & LOOKUP_RCU) {
+ if (dfd_rights)
+ *dfd_rights = NULL;
+ if ((*flags) & LOOKUP_RCU) {
rcu_read_lock();
set_root_rcu(nd);
} else {
@@ -1881,7 +1887,9 @@ static int path_init(int dfd, const char *name, unsigned int flags,
}
nd->path = nd->root;
} else if (dfd == AT_FDCWD) {
- if (flags & LOOKUP_RCU) {
+ if (dfd_rights)
+ *dfd_rights = NULL;
+ if ((*flags) & LOOKUP_RCU) {
struct fs_struct *fs = current->fs;
unsigned seq;
@@ -1897,11 +1905,13 @@ static int path_init(int dfd, const char *name, unsigned int flags,
}
} else {
/* Caller must check execute permissions on the starting path component */
- struct fd f = fdget_raw(dfd);
+ struct fd f = fdget_raw_rights(dfd, dfd_rights, rights);
struct dentry *dentry;
- if (!f.file)
- return -EBADF;
+ if (IS_ERR(f.file))
+ return PTR_ERR(f.file);
+ if (!cap_rights_is_all(*dfd_rights))
+ *flags |= LOOKUP_BENEATH_ONLY;
dentry = f.file->f_path.dentry;
@@ -1913,7 +1923,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
}
nd->path = f.file->f_path;
- if (flags & LOOKUP_RCU) {
+ if ((*flags) & LOOKUP_RCU) {
if (f.flags & FDPUT_FPUT)
*fp = f.file;
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
@@ -1938,9 +1948,12 @@ static inline int lookup_last(struct nameidata *nd, struct path *path)
}
/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
-static int path_lookupat(int dfd, const char *name,
- unsigned int flags, struct nameidata *nd)
+static int path_lookupat(int dfd,
+ const char *name, unsigned int flags,
+ struct nameidata *nd,
+ const struct capsicum_rights *rights)
{
+ const struct capsicum_rights *dfd_rights;
struct file *base = NULL;
struct path path;
int err;
@@ -1959,7 +1972,7 @@ static int path_lookupat(int dfd, const char *name,
* be handled by restarting a traditional ref-walk (which will always
* be able to complete).
*/
- err = path_init(dfd, name, flags | LOOKUP_PARENT, nd, &base);
+ err = path_init(dfd, name, &flags, nd, &base, &dfd_rights, rights);
if (unlikely(err))
return err;
@@ -2004,27 +2017,32 @@ static int path_lookupat(int dfd, const char *name,
return err;
}
-static int filename_lookup(int dfd, struct filename *name,
- unsigned int flags, struct nameidata *nd)
+static int filename_lookup(int dfd,
+ struct filename *name, unsigned int flags,
+ struct nameidata *nd,
+ const struct capsicum_rights *rights)
{
- int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd);
+ int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd,
+ rights);
if (unlikely(retval == -ECHILD))
- retval = path_lookupat(dfd, name->name, flags, nd);
+ retval = path_lookupat(dfd, name->name, flags, nd, rights);
if (unlikely(retval == -ESTALE))
- retval = path_lookupat(dfd, name->name,
- flags | LOOKUP_REVAL, nd);
+ retval = path_lookupat(dfd, name->name, flags | LOOKUP_REVAL,
+ nd, rights);
if (likely(!retval))
audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
return retval;
}
-static int do_path_lookup(int dfd, const char *name,
- unsigned int flags, struct nameidata *nd)
+static int do_path_lookup(int dfd,
+ const char *name, unsigned int flags,
+ struct nameidata *nd,
+ const struct capsicum_rights *rights)
{
struct filename filename = { .name = name };
- return filename_lookup(dfd, &filename, flags, nd);
+ return filename_lookup(dfd, &filename, flags, nd, rights);
}
/* does lookup, returns the object with parent locked */
@@ -2032,7 +2050,8 @@ struct dentry *kern_path_locked(const char *name, struct path *path)
{
struct nameidata nd;
struct dentry *d;
- int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd);
+ int err;
+ err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd, NULL);
if (err)
return ERR_PTR(err);
if (nd.last_type != LAST_NORM) {
@@ -2053,7 +2072,8 @@ struct dentry *kern_path_locked(const char *name, struct path *path)
int kern_path(const char *name, unsigned int flags, struct path *path)
{
struct nameidata nd;
- int res = do_path_lookup(AT_FDCWD, name, flags, &nd);
+ int res;
+ res = do_path_lookup(AT_FDCWD, name, flags, &nd, NULL);
if (!res)
*path = nd.path;
return res;
@@ -2078,7 +2098,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
nd.root.mnt = mnt;
BUG_ON(flags & LOOKUP_PARENT);
/* the first argument of do_path_lookup() is ignored with LOOKUP_ROOT */
- err = do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, &nd);
+ err = do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, &nd, NULL);
if (!err)
*path = nd.path;
return err;
@@ -2161,8 +2181,7 @@ static int user_path_at_empty_rights(int dfd,
if (!IS_ERR(tmp)) {
BUG_ON(flags & LOOKUP_PARENT);
-
- err = filename_lookup(dfd, tmp, flags, &nd);
+ err = filename_lookup(dfd, tmp, flags, &nd, rights);
putname(tmp);
if (!err)
*path = nd.path;
@@ -2211,7 +2230,7 @@ int _user_path_atr(int dfd,
*/
static struct filename *
user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
- unsigned int flags)
+ unsigned int flags, const struct capsicum_rights *rights)
{
struct filename *s = getname(path);
int error;
@@ -2222,7 +2241,7 @@ user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
if (IS_ERR(s))
return s;
- error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd);
+ error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd, rights);
if (error) {
putname(s);
return ERR_PTR(error);
@@ -2338,9 +2357,11 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags
{
struct file *base = NULL;
struct nameidata nd;
+ const struct capsicum_rights *dfd_rights;
int err;
- err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd, &base);
+ err = path_init(dfd, name, &flags, &nd, &base,
+ &dfd_rights, &lookup_rights);
if (unlikely(err))
return err;
@@ -3165,8 +3186,9 @@ static int do_tmpfile(int dfd, struct filename *pathname,
static const struct qstr name = QSTR_INIT("/", 1);
struct dentry *dentry, *child;
struct inode *dir;
- int error = path_lookupat(dfd, pathname->name,
- flags | LOOKUP_DIRECTORY, nd);
+ int error;
+ error = path_lookupat(dfd, pathname->name, flags | LOOKUP_DIRECTORY, nd,
+ &lookup_rights);
if (unlikely(error))
return error;
error = mnt_want_write(nd->path.mnt);
@@ -3218,15 +3240,42 @@ out:
return error;
}
+static void openat_primary_rights(struct capsicum_rights *rights,
+ unsigned int flags)
+{
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY:
+ cap_rights_set(rights, CAP_READ);
+ break;
+ case O_RDWR:
+ cap_rights_set(rights, CAP_READ);
+ /* FALLTHRU */
+ case O_WRONLY:
+ cap_rights_set(rights, CAP_WRITE);
+ if (!(flags & (O_APPEND | O_TRUNC)))
+ cap_rights_set(rights, CAP_SEEK);
+ break;
+ }
+ if (flags & O_CREAT)
+ cap_rights_set(rights, CAP_CREATE);
+ if (flags & O_TRUNC)
+ cap_rights_set(rights, CAP_FTRUNCATE);
+ if (flags & (O_DSYNC|FASYNC))
+ cap_rights_set(rights, CAP_FSYNC);
+}
+
static struct file *path_openat(int dfd, struct filename *pathname,
struct nameidata *nd, const struct open_flags *op, int flags)
{
+ struct capsicum_rights rights;
+ const struct capsicum_rights *dfd_rights;
struct file *base = NULL;
struct file *file;
struct path path;
int opened = 0;
int error;
+ cap_rights_init(&rights, CAP_LOOKUP);
file = get_empty_filp();
if (IS_ERR(file))
return file;
@@ -3238,7 +3287,9 @@ static struct file *path_openat(int dfd, struct filename *pathname,
goto out;
}
- error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base);
+ openat_primary_rights(&rights, file->f_flags);
+ error = path_init(dfd, pathname->name, &flags, nd, &base,
+ &dfd_rights, &rights);
if (unlikely(error))
goto out;
@@ -3268,6 +3319,16 @@ static struct file *path_openat(int dfd, struct filename *pathname,
error = do_last(nd, &path, file, op, &opened, pathname);
put_link(nd, &link, cookie);
}
+ if (!error) {
+ struct file *install_file;
+ install_file = security_file_install(dfd_rights, file);
+ if (IS_ERR(install_file)) {
+ error = PTR_ERR(install_file);
+ goto out;
+ } else {
+ file = install_file;
+ }
+ }
out:
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT))
path_put(&nd->root);
@@ -3326,8 +3387,12 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
return file;
}
-struct dentry *kern_path_create(int dfd, const char *pathname,
- struct path *path, unsigned int lookup_flags)
+static struct dentry *
+kern_path_create_rights(int dfd,
+ const char *pathname,
+ struct path *path,
+ unsigned int lookup_flags,
+ const struct capsicum_rights *rights)
{
struct dentry *dentry = ERR_PTR(-EEXIST);
struct nameidata nd;
@@ -3341,7 +3406,8 @@ struct dentry *kern_path_create(int dfd, const char *pathname,
*/
lookup_flags &= LOOKUP_REVAL;
- error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd);
+ error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd,
+ rights);
if (error)
return ERR_PTR(error);
@@ -3395,6 +3461,13 @@ out:
path_put(&nd.path);
return dentry;
}
+
+struct dentry *kern_path_create(int dfd, const char *pathname,
+ struct path *path, unsigned int lookup_flags)
+{
+ return kern_path_create_rights(dfd, pathname, path, lookup_flags,
+ &lookup_rights);
+}
EXPORT_SYMBOL(kern_path_create);
void done_path_create(struct path *path, struct dentry *dentry)
@@ -3406,17 +3479,29 @@ void done_path_create(struct path *path, struct dentry *dentry)
}
EXPORT_SYMBOL(done_path_create);
-struct dentry *user_path_create(int dfd, const char __user *pathname,
- struct path *path, unsigned int lookup_flags)
+static struct dentry *
+user_path_create_rights(int dfd,
+ const char __user *pathname,
+ struct path *path,
+ unsigned int lookup_flags,
+ const struct capsicum_rights *rights)
{
struct filename *tmp = getname(pathname);
struct dentry *res;
if (IS_ERR(tmp))
return ERR_CAST(tmp);
- res = kern_path_create(dfd, tmp->name, path, lookup_flags);
+ res = kern_path_create_rights(dfd, tmp->name, path, lookup_flags,
+ rights);
putname(tmp);
return res;
}
+
+struct dentry *user_path_create(int dfd, const char __user *pathname,
+ struct path *path, unsigned int lookup_flags)
+{
+ return user_path_create_rights(dfd, pathname, path, lookup_flags,
+ &lookup_rights);
+}
EXPORT_SYMBOL(user_path_create);
int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
@@ -3467,16 +3552,28 @@ static int may_mknod(umode_t mode)
SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
unsigned, dev)
{
+ struct capsicum_rights rights;
struct dentry *dentry;
struct path path;
int error;
unsigned int lookup_flags = 0;
+ cap_rights_init(&rights, CAP_LOOKUP);
error = may_mknod(mode);
if (error)
return error;
+
+ switch (mode & S_IFMT) {
+ case S_IFCHR: case S_IFBLK:
+ cap_rights_set(&rights, CAP_MKNODAT);
+ break;
+ case S_IFIFO:
+ cap_rights_set(&rights, CAP_MKFIFOAT);
+ break;
+ }
retry:
- dentry = user_path_create(dfd, filename, &path, lookup_flags);
+ dentry = user_path_create_rights(dfd, filename, &path, lookup_flags,
+ &rights);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
@@ -3543,9 +3640,12 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_DIRECTORY;
+ struct capsicum_rights rights;
+ cap_rights_init(&rights, CAP_LOOKUP, CAP_MKDIRAT);
retry:
- dentry = user_path_create(dfd, pathname, &path, lookup_flags);
+ dentry = user_path_create_rights(dfd, pathname, &path, lookup_flags,
+ &rights);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
@@ -3636,9 +3736,11 @@ static long do_rmdir(int dfd, const char __user *pathname)
struct filename *name;
struct dentry *dentry;
struct nameidata nd;
+ struct capsicum_rights rights;
unsigned int lookup_flags = 0;
+ cap_rights_init(&rights, CAP_UNLINKAT);
retry:
- name = user_path_parent(dfd, pathname, &nd, lookup_flags);
+ name = user_path_parent(dfd, pathname, &nd, lookup_flags, &rights);
if (IS_ERR(name))
return PTR_ERR(name);
@@ -3763,8 +3865,10 @@ static long do_unlinkat(int dfd, const char __user *pathname)
struct inode *inode = NULL;
struct inode *delegated_inode = NULL;
unsigned int lookup_flags = 0;
+ struct capsicum_rights rights;
+ cap_rights_init(&rights, CAP_UNLINKAT);
retry:
- name = user_path_parent(dfd, pathname, &nd, lookup_flags);
+ name = user_path_parent(dfd, pathname, &nd, lookup_flags, &rights);
if (IS_ERR(name))
return PTR_ERR(name);
@@ -3870,12 +3974,15 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
struct dentry *dentry;
struct path path;
unsigned int lookup_flags = 0;
+ struct capsicum_rights rights;
from = getname(oldname);
if (IS_ERR(from))
return PTR_ERR(from);
+ cap_rights_init(&rights, CAP_SYMLINKAT);
retry:
- dentry = user_path_create(newdfd, newname, &path, lookup_flags);
+ dentry = user_path_create_rights(newdfd, newname, &path, lookup_flags,
+ &rights);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out_putname;
@@ -3986,6 +4093,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
struct dentry *new_dentry;
struct path old_path, new_path;
struct inode *delegated_inode = NULL;
+ struct capsicum_rights rights;
int how = 0;
int error;
@@ -4004,13 +4112,14 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
if (flags & AT_SYMLINK_FOLLOW)
how |= LOOKUP_FOLLOW;
+ cap_rights_init(&rights, CAP_LINKAT);
retry:
error = user_path_at(olddfd, oldname, how, &old_path);
if (error)
return error;
- new_dentry = user_path_create(newdfd, newname, &new_path,
- (how & LOOKUP_REVAL));
+ new_dentry = user_path_create_rights(newdfd, newname, &new_path,
+ (how & LOOKUP_REVAL), &rights);
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))
goto out;
@@ -4241,6 +4350,8 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
struct inode *delegated_inode = NULL;
struct filename *from;
struct filename *to;
+ struct capsicum_rights old_rights;
+ struct capsicum_rights new_rights;
unsigned int lookup_flags = 0;
bool should_retry = false;
int error;
@@ -4251,14 +4362,18 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
if ((flags & RENAME_NOREPLACE) && (flags & RENAME_EXCHANGE))
return -EINVAL;
+ cap_rights_init(&old_rights, CAP_RENAMEAT);
+ cap_rights_init(&new_rights, CAP_LINKAT);
retry:
- from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags);
+ from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags,
+ &old_rights);
if (IS_ERR(from)) {
error = PTR_ERR(from);
goto exit;
}
- to = user_path_parent(newdfd, newname, &newnd, lookup_flags);
+ to = user_path_parent(newdfd, newname, &newnd, lookup_flags,
+ &new_rights);
if (IS_ERR(to)) {
error = PTR_ERR(to);
goto exit1;
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index abc8cbcfe90e..33a269166b05 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/fdtable.h>
#include <linux/fsnotify_backend.h>
+#include <linux/security.h>
int dir_notify_enable __read_mostly = 1;
@@ -327,6 +328,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
rcu_read_lock();
f = fcheck(fd);
+ f = security_file_lookup(f, NULL, NULL);
rcu_read_unlock();
/* if (f != filp) means that we lost a race and another task/thread
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 0788d093f5d8..d260dd1acdee 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -20,6 +20,7 @@ static int seq_show(struct seq_file *m, void *v)
struct files_struct *files = NULL;
int f_flags = 0, ret = -ENOENT;
struct file *file = NULL;
+ struct file *underlying = NULL;
struct task_struct *task;
task = get_proc_task(m->private);
@@ -36,12 +37,13 @@ static int seq_show(struct seq_file *m, void *v)
file = fcheck_files(files, fd);
if (file) {
struct fdtable *fdt = files_fdtable(files);
-
- f_flags = file->f_flags;
+ underlying = security_file_lookup(file, NULL, NULL);
+ f_flags = underlying->f_flags;
if (close_on_exec(fd, fdt))
f_flags |= O_CLOEXEC;
get_file(file);
+ get_file(underlying);
ret = 0;
}
spin_unlock(&files->file_lock);
@@ -50,10 +52,11 @@ static int seq_show(struct seq_file *m, void *v)
if (!ret) {
seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n",
- (long long)file->f_pos, f_flags,
- real_mount(file->f_path.mnt)->mnt_id);
+ (long long)underlying->f_pos, f_flags,
+ real_mount(underlying->f_path.mnt)->mnt_id);
if (file->f_op->show_fdinfo)
ret = file->f_op->show_fdinfo(m, file);
+ fput(underlying);
fput(file);
}
@@ -95,7 +98,9 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
rcu_read_lock();
file = fcheck_files(files, fd);
if (file) {
- unsigned f_mode = file->f_mode;
+ unsigned f_mode;
+ file = security_file_lookup(file, NULL, NULL);
+ f_mode = file->f_mode;
rcu_read_unlock();
put_files_struct(files);
@@ -158,6 +163,7 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
spin_lock(&files->file_lock);
fd_file = fcheck_files(files, fd);
if (fd_file) {
+ fd_file = security_file_lookup(fd_file, NULL, NULL);
*path = fd_file->f_path;
path_get(&fd_file->f_path);
ret = 0;
diff --git a/net/socket.c b/net/socket.c
index dbc00f0b992a..f635dc3f9a3c 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1669,6 +1669,7 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
{
struct socket *sock, *newsock;
struct file *newfile;
+ struct file *installfile;
int err, len, newfd, fput_needed;
struct sockaddr_storage address;
struct capsicum_rights rights;
@@ -1736,7 +1737,12 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
/* File flags are not inherited via accept() unlike another OSes. */
- fd_install(newfd, newfile);
+ installfile = security_file_install(listen_rights, newfile);
+ if (IS_ERR(installfile)) {
+ err = PTR_ERR(installfile);
+ goto out_fd;
+ }
+ fd_install(newfd, installfile);
err = newfd;
out_put:
@@ -2115,7 +2121,7 @@ static int ___sys_sendmsg(struct socket *sock_noaddr, struct socket *sock_addr,
}
sock = (msg_sys->msg_name ? sock_addr : sock_noaddr);
if (!sock)
- return -EBADF;
+ return -ENOTCAPABLE;
if (msg_sys->msg_iovlen > UIO_FASTIOV) {
err = -EMSGSIZE;
--
2.0.0.526.g5318336
^ 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