+2015-01-02 15:15 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.22
+
+2015-01-01 12:01 Christos Zoulas <christos@zoulas.com>
+
+ * add indirect relative for TIFF/Exif
+
+2014-12-16 18:10 Christos Zoulas <christos@zoulas.com>
+
+ * restructure elf note printing to avoid repeated messages
+ * add note limit, suggested by Alexander Cherepanov
+
+2014-12-16 16:53 Christos Zoulas <christos@zoulas.com>
+
+ * Bail out on partial pread()'s (Alexander Cherepanov)
+ * Fix incorrect bounds check in file_printable (Alexander Cherepanov)
+
+2014-12-11 20:01 Christos Zoulas <christos@zoulas.com>
+
+ * PR/405: ignore SIGPIPE from uncompress programs
+ * change printable -> file_printable and use it in
+ more places for safety
+ * in ELF, instead of "(uses dynamic libraries)" when PT_INTERP
+ is present print the interpreter name.
+
2014-12-10 20:01 Christos Zoulas <christos@zoulas.com>
* release 5.21
- reduce the number of recursion levels from 20 to 10
- preserve error messages in indirect magic handling
+ This is tracked as CVE-2014-8116 and CVE-2014-8117
+
2014-11-12 10:30 Christos Zoulas <christos@zoulas.com>
* fix bogus free in the user buffer case.
## README for file(1) Command ##
- @(#) $File: README,v 1.46 2013/03/25 14:33:10 christos Exp $
+ @(#) $File: README,v 1.48 2014/03/07 13:55:30 christos Exp $
Mailing List: file@mx.gw.com
Mailing List archives: http://mx.gw.com/pipermail/file/
https://github.com/file/file
-The major changes for 5.x are CDF file parsing, indirect magic, and
-overhaul in mime and ascii encoding handling.
+The major changes for 5.x are CDF file parsing, indirect magic, name/use
+(recursion) and overhaul in mime and ascii encoding handling.
The major feature of 4.x is the refactoring of the code into a library,
and the re-write of the file command in terms of that library. The library
COPYING - read this first.
README - read this second (you are currently reading this file).
INSTALL - read on how to install
-
src/apprentice.c - parses /etc/magic to learn magic
+src/asctime_r.c - replacement for OS's that don't have it.
src/apptype.c - used for OS/2 specific application type magic
src/asprintf.c - replacement for OS's that don't have it.
src/ascmagic.c - third & last set of tests, based on hardwired assumptions.
-src/asctime_r.c - for systems that don't have it.
-src/asprintf.c - for systems that don't have it.
-src/cdf.c - parser for Microsoft Compound Document Files
+src/asctime_r.c - replacement for OS's that don't have it.
+src/asprintf.c - replacement for OS's that don't have it.
+src/cdf.[ch] - parser for Microsoft Compound Document Files
src/cdf_time.c - time converter for CDF.
src/compress.c - handles decompressing files to look inside.
-src/ctime_r.c - for systems that don't have it.
+src/ctime_r.c - replacement for OS's that don't have it.
+src/elfclass.h - common code for elf 32/64.
src/encoding.c - handles unicode encodings
src/file.c - the main program
src/file.h - header file
+src/file_opts.h - list of options
+src/fmtcheck.c - replacement for OS's that don't have it.
src/fsmagic.c - first set of tests the program runs, based on filesystem info
src/funcs.c - utilility functions
-src/getopt_long.c - for systems that don't have it.
-src/getline.c - for systems that don't have it.
+src/getline.c - replacement for OS's that don't have it.
+src/getopt_long.c - replacement for OS's that don't have it.
src/is_tar.c, tar.h - knows about tarchives (courtesy John Gilmore).
src/names.h - header file for ascmagic.c
+src/magic.h.in - source file for magic.h
src/magic.c - the libmagic api
+src/pread.c - replacement for OS's that don't have it.
src/print.c - print results, errors, warnings.
src/readcdf.c - CDF wrapper.
src/readelf.[ch] - Stand-alone elf parsing code.
src/softmagic.c - 2nd set of tests, based on /etc/magic
-src/strlcat.c - for systems that don't have it.
-src/strlcpy.c - for systems that don't have it.
+src/mygetopt.h - replacement for OS's that don't have it.
+src/strcasestr.c - replacement for OS's that don't have it.
+src/strlcat.c - replacement for OS's that don't have it.
+src/strlcpy.c - replacement for OS's that don't have it.
+src/tar.h - tar file definitions
src/vasprintf.c - for systems that don't have it.
doc/file.man - man page for the command
doc/magic.man - man page for the magic file, courtesy Guy Harris.
dnl Process this file with autoconf to produce a configure script.
-AC_INIT([file],[5.21],[christos@astron.com])
+AC_INIT([file],[5.22],[christos@astron.com])
AM_INIT_AUTOMAKE([subdir-objects foreign])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
-.\" $File: file.man,v 1.109 2014/11/28 02:35:05 christos Exp $
-.Dd November 27, 2014
+.\" $File: file.man,v 1.110 2014/11/28 02:46:39 christos Exp $
+.Dd December 16, 2014
.Dt FILE __CSECTION__
.Os
.Sh NAME
.It Sy "Name" Ta Sy "Default" Ta Sy "Explanation"
.It Li indir Ta 15 Ta recursion limit for indirect magic
.It Li name Ta 30 Ta use count limit for name/use magic
+.It Li elf_notes Ta 256 Ta max ELF notes processed
.It Li elf_phnum Ta 128 Ta max ELF program sections processed
.It Li elf_shnum Ta 32768 Ta max ELF sections processed
.El
-.\" $File: libmagic.man,v 1.32 2014/11/28 02:35:05 christos Exp $
+.\" $File: libmagic.man,v 1.33 2014/11/28 02:46:39 christos Exp $
.\"
.\" Copyright (c) Christos Zoulas 2003.
.\" All Rights Reserved.
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 27, 2014
+.Dd December 16, 2014
.Dt LIBMAGIC 3
.Os
.Sh NAME
.It Sy "Parameter" Ta Sy "Type" Ta Sy "Default"
.It Li MAGIC_PARAM_INDIR_MAX Ta size_t Ta 15
.It Li MAGIC_PARAM_NAME_MAX Ta size_t Ta 30
+.It Li MAGIC_PARAM_ELF_NOTES_MAX Ta size_t Ta 256
.It Li MAGIC_PARAM_ELF_PHNUM_MAX Ta size_t Ta 128
.It Li MAGIC_PARAM_ELF_SHNUM_MAX Ta size_t Ta 32768
.El
parameter controls the maximum number of calls for name/use.
.Pp
The
+.Dv MAGIC_PARAM_NOTES_MAX
+parameter controls how many ELF notes will be processed.
+.Pp
+The
.Dv MAGIC_PARAM_PHNUM_MAX
-parameter controls how many elf program sections will be processed.
+parameter controls how many ELF program sections will be processed.
.Pp
The
.Dv MAGIC_PARAM_SHNUM_MAX
-parameter controls how many elf sections will be processed.
+parameter controls how many ELF sections will be processed.
.Pp
The
.Fn magic_version
-.\" $File: magic.man,v 1.83 2014/06/03 17:36:13 christos Exp $
-.Dd June 3, 2014
+.\" $File: magic.man,v 1.84 2014/06/03 19:01:34 christos Exp $
+.Dd January 1, 2015
.Dt MAGIC __FSECTION__
.Os
.\" install as magic.4 on USG, magic.5 on V7, Berkeley and Linux systems.
than UTC.
.It Dv indirect
Starting at the given offset, consult the magic database again.
+The offset of th
+.Dv indirect
+magic is by default absolute in the file, but one can specify
+.Dv /r
+to indicate that the offset is relative from the beginning of the entry.
.It Dv name
Define a
.Dq named
#------------------------------------------------------------------------------
-# $File: cafebabe,v 1.15 2014/03/14 18:47:29 christos Exp $
+# $File: cafebabe,v 1.16 2014/04/30 21:41:02 christos Exp $
# Cafe Babes unite!
#
# Since Java bytecode and Mach-O universal binaries have the same magic number,
0 name mach-o \b [
>0 use mach-o-cpu \b
->&(8.L) indirect \b:
+>(8.L) indirect \b:
>0 belong x \b]
0 belong 0xcafebabe
#------------------------------------------------------------------------------
-# $File: filesystems,v 1.106 2014/10/23 17:17:09 christos Exp $
+# $File: filesystems,v 1.107 2014/12/03 18:02:52 christos Exp $
# filesystems: file(1) magic for different filesystems
#
0 name partid
>>(11.s-2) uleshort 0xAA55 DOS/MBR boot sector
# for sector sizes with 512 or more Bytes
>0x1FE leshort 0xAA55 DOS/MBR boot sector
+
+# keep old DOS/MBR boot sector as dummy for mbr and bootloader displaying
+# only for sector sizes with 512 or more Bytes
+0x1FE leshort 0xAA55 DOS/MBR boot sector
+#
+# to display information (50) before DOS BPB (strength=70) and after DOS floppy (120) like in old file version
+!:strength +65
>2 string OSBS OS/BS MBR
# added by Joerg Jenderek at Feb 2013 according to http://thestarman.pcministry.com/asm/mbr/
# and http://en.wikipedia.org/wiki/Master_Boot_Record
#------------------------------------------------------------------------------
-# $File: images,v 1.96 2014/12/08 16:05:47 christos Exp $
+# $File: images,v 1.101 2015/01/01 04:16:51 christos Exp $
# images: file(1) magic for image formats (see also "iff", and "c-lang" for
# XPM bitmaps)
#
# never changed. The TIFF specification recommends testing for it.
0 string MM\x00\x2a TIFF image data, big-endian
!:mime image/tiff
->(4.L) use tiff_ifd
+>(4.L) use \^tiff_ifd
0 string II\x2a\x00 TIFF image data, little-endian
!:mime image/tiff
>(4.l) use tiff_ifd
>2 use tiff_entry
0 name tiff_entry
+# NewSubFileType
+>0 leshort 0xfe
+>>12 use tiff_entry
>0 leshort 0x100
>>4 lelong 1
>>>12 use tiff_entry
->>>8 lelong x \b, width=%d
+>>>8 leshort x \b, width=%d
>0 leshort 0x101
>>4 lelong 1
->>>8 lelong x \b, height=%d
+>>>8 leshort x \b, height=%d
>>>12 use tiff_entry
>0 leshort 0x102
->>8 lelong x \b, bps=%d
+>>8 leshort x \b, bps=%d
>>12 use tiff_entry
>0 leshort 0x103
>>4 lelong 1 \b, compression=
->>>8 lelong 1 \bnone
->>>8 lelong 2 \bhuffman
->>>8 lelong 3 \bbi-level group 3
->>>8 lelong 4 \bbi-level group 4
->>>8 lelong 5 \bLZW
->>>8 lelong 6 \bJPEG (old)
->>>8 lelong 7 \bJPEG
->>>8 lelong 8 \bdeflate
->>>8 lelong 9 \bJBIG, ITU-T T.85
->>>8 lelong 0xa \bJBIG, ITU-T T.43
->>>8 lelong 0x7ffe \bNeXT RLE 2-bit
->>>8 lelong 0x8005 \bPackBits (Macintosh RLE)
->>>8 lelong 0x8029 \bThunderscan RLE
->>>8 lelong 0x807f \bRasterPadding (CT or MP)
->>>8 lelong 0x8080 \bRLE (Line Work)
->>>8 lelong 0x8081 \bRLE (High-Res Cont-Tone)
->>>8 lelong 0x8082 \bRLE (Binary Line Work)
->>>8 lelong 0x80b2 \bDeflate (PKZIP)
->>>8 lelong 0x80b3 \bKodak DCS
->>>8 lelong 0x8765 \bJBIG
->>>8 lelong 0x8798 \bJPEG2000
->>>8 lelong 0x8799 \bNikon NEF Compressed
+>>>8 leshort 1 \bnone
+>>>8 leshort 2 \bhuffman
+>>>8 leshort 3 \bbi-level group 3
+>>>8 leshort 4 \bbi-level group 4
+>>>8 leshort 5 \bLZW
+>>>8 leshort 6 \bJPEG (old)
+>>>8 leshort 7 \bJPEG
+>>>8 leshort 8 \bdeflate
+>>>8 leshort 9 \bJBIG, ITU-T T.85
+>>>8 leshort 0xa \bJBIG, ITU-T T.43
+>>>8 leshort 0x7ffe \bNeXT RLE 2-bit
+>>>8 leshort 0x8005 \bPackBits (Macintosh RLE)
+>>>8 leshort 0x8029 \bThunderscan RLE
+>>>8 leshort 0x807f \bRasterPadding (CT or MP)
+>>>8 leshort 0x8080 \bRLE (Line Work)
+>>>8 leshort 0x8081 \bRLE (High-Res Cont-Tone)
+>>>8 leshort 0x8082 \bRLE (Binary Line Work)
+>>>8 leshort 0x80b2 \bDeflate (PKZIP)
+>>>8 leshort 0x80b3 \bKodak DCS
+>>>8 leshort 0x8765 \bJBIG
+>>>8 leshort 0x8798 \bJPEG2000
+>>>8 leshort 0x8799 \bNikon NEF Compressed
>>>8 default x
->>>>8 lelong x \b(unknown 0x%x)
+>>>>8 leshort x \b(unknown 0x%x)
>>>12 use tiff_entry
>0 leshort 0x106 \b, PhotometricIntepretation=
->>8 lelong 0 \bWhiteIsZero
->>8 lelong 1 \bBlackIsZero
->>8 lelong 2 \bRGB
->>8 lelong 3 \bRGB Palette
->>8 lelong 4 \bTransparency Mask
->>8 lelong 5 \bCMYK
->>8 lelong 6 \bYCbCr
->>8 lelong 8 \bCIELab
->>>8 lelong x \b(unknown=0x%x)
+>>8 leshort 0 \bWhiteIsZero
+>>8 leshort 1 \bBlackIsZero
+>>8 leshort 2 \bRGB
+>>8 leshort 3 \bRGB Palette
+>>8 leshort 4 \bTransparency Mask
+>>8 leshort 5 \bCMYK
+>>8 leshort 6 \bYCbCr
+>>8 leshort 8 \bCIELab
+>>>8 leshort x \b(unknown=0x%x)
>>12 use tiff_entry
# FillOrder
>0 leshort 0x10a
>0 leshort 0x10e
>>(8.l) string x \b, description=%s
>>>12 use tiff_entry
+# Make
+>0 leshort 0x10f
+>>(8.l) string x \b, manufacturer=%s
+>>>12 use tiff_entry
+# Model
+>0 leshort 0x110
+>>(8.l) string x \b, model=%s
+>>>12 use tiff_entry
# StripOffsets
>0 leshort 0x111
>>12 use tiff_entry
-# NewSubFileType
->0 leshort 0xfe
+# Orientation
+>0 leshort 0x112 \b, orientation=
+>>8 leshort 1 \bupper-left
+>>8 leshort 3 \blower-right
+>>8 leshort 6 \bupper-right
+>>8 leshort 8 \blower-left
+>>8 leshort 9 \bundefined
+>>8 default x
+>>>8 leshort x \b[*%d*]
+>>12 use tiff_entry
+# XResolution
+>0 leshort 0x11a
+>>8 lelong x \b, xresolution=%d
+>>12 use tiff_entry
+# YResolution
+>0 leshort 0x11b
+>>8 lelong x \b, yresolution=%d
+>>12 use tiff_entry
+# ResolutionUnit
+>0 leshort 0x128
+>>8 leshort x \b, resolutionunit=%d
+>>12 use tiff_entry
+# Software
+>0 leshort 0x131
+>>(8.l) string x \b, software=%s
>>12 use tiff_entry
# Datetime
>0 leshort 0x132
>>(8.l) string x \b, datetime=%s
->>>12 use tiff_entry
+>>12 use tiff_entry
# HostComputer
>0 leshort 0x13c
>>(8.l) string x \b, hostcomputer=%s
->>>12 use tiff_entry
+>>12 use tiff_entry
+# WhitePoint
+>0 leshort 0x13e
+>>12 use tiff_entry
+# PrimaryChromaticities
+>0 leshort 0x13f
+>>12 use tiff_entry
+# YCbCrCoefficients
+>0 leshort 0x211
+>>12 use tiff_entry
+# YCbCrPositioning
+>0 leshort 0x213
+>>12 use tiff_entry
+# ReferenceBlackWhite
+>0 leshort 0x214
+>>12 use tiff_entry
+# Copyright
+>0 leshort 0x8298
+>>(8.l) string x \b, copyright=%s
+>>12 use tiff_entry
+# ExifOffset
+>0 leshort 0x8769
+>>12 use tiff_entry
+# GPS IFD
+>0 leshort 0x8825 \b, GPS-Data
+>>12 use tiff_entry
+
#>0 leshort x \b, unknown=0x%x
+#>>12 use tiff_entry
0 string MM\x00\x2b Big TIFF image data, big-endian
!:mime image/tiff
#------------------------------------------------------------------------------
-# $File: jpeg,v 1.20 2014/08/05 07:32:31 christos Exp $
+# $File: jpeg,v 1.24 2015/01/01 17:07:34 christos Exp $
# JPEG images
# SunOS 5.5.1 had
#
# Next, show thumbnail info, if it exists:
>>18 byte !0 \b, thumbnail %dx
>>>19 byte x \b%d
-
-# EXIF moved down here to avoid reporting a bogus version number,
-# and EXIF version number printing added.
-# - Patrik R=E5dman <patrik+file-magic@iki.fi>
->6 string Exif \b, EXIF standard
-# Look for EXIF IFD offset in IFD 0, and then look for EXIF version tag in EXIF IFD.
-# All possible combinations of entries have to be enumerated, since no looping
-# is possible. And both endians are possible...
-# The combinations included below are from real-world JPEGs.
-# Little-endian
->>12 string II
-# IFD 0 Entry #5:
->>>70 leshort 0x8769
-# EXIF IFD Entry #1:
->>>>(78.l+14) leshort 0x9000
->>>>>(78.l+23) byte x %c
->>>>>(78.l+24) byte x \b.%c
->>>>>(78.l+25) byte !0x30 \b%c
-# IFD 0 Entry #9:
->>>118 leshort 0x8769
-# EXIF IFD Entry #3:
->>>>(126.l+38) leshort 0x9000
->>>>>(126.l+47) byte x %c
->>>>>(126.l+48) byte x \b.%c
->>>>>(126.l+49) byte !0x30 \b%c
-# IFD 0 Entry #10
->>>130 leshort 0x8769
-# EXIF IFD Entry #3:
->>>>(138.l+38) leshort 0x9000
->>>>>(138.l+47) byte x %c
->>>>>(138.l+48) byte x \b.%c
->>>>>(138.l+49) byte !0x30 \b%c
-# EXIF IFD Entry #4:
->>>>(138.l+50) leshort 0x9000
->>>>>(138.l+59) byte x %c
->>>>>(138.l+60) byte x \b.%c
->>>>>(138.l+61) byte !0x30 \b%c
-# EXIF IFD Entry #5:
->>>>(138.l+62) leshort 0x9000
->>>>>(138.l+71) byte x %c
->>>>>(138.l+72) byte x \b.%c
->>>>>(138.l+73) byte !0x30 \b%c
-# IFD 0 Entry #11
->>>142 leshort 0x8769
-# EXIF IFD Entry #3:
->>>>(150.l+38) leshort 0x9000
->>>>>(150.l+47) byte x %c
->>>>>(150.l+48) byte x \b.%c
->>>>>(150.l+49) byte !0x30 \b%c
-# EXIF IFD Entry #4:
->>>>(150.l+50) leshort 0x9000
->>>>>(150.l+59) byte x %c
->>>>>(150.l+60) byte x \b.%c
->>>>>(150.l+61) byte !0x30 \b%c
-# EXIF IFD Entry #5:
->>>>(150.l+62) leshort 0x9000
->>>>>(150.l+71) byte x %c
->>>>>(150.l+72) byte x \b.%c
->>>>>(150.l+73) byte !0x30 \b%c
-# Big-endian
->>12 string MM
-# IFD 0 Entry #9:
->>>118 beshort 0x8769
-# EXIF IFD Entry #1:
->>>>(126.L+14) beshort 0x9000
->>>>>(126.L+23) byte x %c
->>>>>(126.L+24) byte x \b.%c
->>>>>(126.L+25) byte !0x30 \b%c
-# EXIF IFD Entry #3:
->>>>(126.L+38) beshort 0x9000
->>>>>(126.L+47) byte x %c
->>>>>(126.L+48) byte x \b.%c
->>>>>(126.L+49) byte !0x30 \b%c
-# IFD 0 Entry #10
->>>130 beshort 0x8769
-# EXIF IFD Entry #3:
->>>>(138.L+38) beshort 0x9000
->>>>>(138.L+47) byte x %c
->>>>>(138.L+48) byte x \b.%c
->>>>>(138.L+49) byte !0x30 \b%c
-# EXIF IFD Entry #5:
->>>>(138.L+62) beshort 0x9000
->>>>>(138.L+71) byte x %c
->>>>>(138.L+72) byte x \b.%c
->>>>>(138.L+73) byte !0x30 \b%c
-# IFD 0 Entry #11
->>>142 beshort 0x8769
-# EXIF IFD Entry #4:
->>>>(150.L+50) beshort 0x9000
->>>>>(150.L+59) byte x %c
->>>>>(150.L+60) byte x \b.%c
->>>>>(150.L+61) byte !0x30 \b%c
+>6 string Exif \b, Exif standard: [
+>>12 indirect/r x
+>>12 string x \b]
# Jump to the first segment
>(4.S+4) use jpeg_segment
>0 beshort 0xFFC4
>>(2.S+2) use jpeg_segment
+>0 beshort 0xFFE1
+#>>(2.S+2) use jpeg_segment
+>>4 string Exif \b, Exif Standard: [
+>>>10 indirect/r x
+>>>10 string x \b]
+
# Application specific markers
>0 beshort&0xFFE0 =0xFFE0
>>(2.S+2) use jpeg_segment
>0 beshort&0xFFD0 =0xFFD0
>>(2.S+2) use jpeg_segment
+#>0 beshort x unknown 0x%x
+#>>(2.S+2) use jpeg_segment
+
# HSI is Handmade Software's proprietary JPEG encoding scheme
0 string hsi1 JPEG image data, HSI proprietary
--- /dev/null
+
+#------------------------------------------------------------------------------
+# $File: qt,v 1.1 2014/12/12 16:48:39 christos Exp $
+# qt: file(1) magic for Qt
+
+# http://doc.qt.io/qt-5/resources.html
+0 string \<!DOCTYPE\040RCC\> Qt Resource Collection file
+
+# https://qt.gitorious.org/qt/qtbase/source/\
+# 5367fa356233da4c0f28172a8f817791525f5457:\
+# src/tools/rcc/rcc.cpp#L840
+0 string qres\0\0 Qt Binary Resource file
+0 search/1024 The\040Resource\040Compiler\040for\040Qt Qt C-code resource file
+
+# https://qt.gitorious.org/qt/qtbase/source/\
+# 5367fa356233da4c0f28172a8f817791525f5457:\
+# src/corelib/kernel/qtranslator.cpp#L62
+0 string \x3c\xb8\x64\x18\xca\xef\x9c\x95
+>8 string \xcd\x21\x1c\xbf\x60\xa1\xbd\xdd Qt Translation file
#
-# $File: Makefile.am,v 1.99 2014/08/04 06:26:16 christos Exp $
+# $File: Makefile.am,v 1.100 2014/12/10 18:45:43 christos Exp $
#
MAGIC_FRAGMENT_BASE = Magdir
MAGIC_DIR = $(top_srcdir)/magic
$(MAGIC_FRAGMENT_DIR)/pwsafe \
$(MAGIC_FRAGMENT_DIR)/pyramid \
$(MAGIC_FRAGMENT_DIR)/python \
+$(MAGIC_FRAGMENT_DIR)/qt \
$(MAGIC_FRAGMENT_DIR)/revision \
$(MAGIC_FRAGMENT_DIR)/riff \
$(MAGIC_FRAGMENT_DIR)/rpm \
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: apprentice.c,v 1.226 2014/11/28 02:35:05 christos Exp $")
+FILE_RCSID("@(#)$File: apprentice.c,v 1.228 2014/12/16 23:18:40 christos Exp $")
#endif /* lint */
#include "magic.h"
ms->name_max = FILE_NAME_MAX;
ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
+ ms->elf_notes_max = FILE_ELF_NOTES_MAX;
return ms;
free:
free(ms);
}
#endif /* ENABLE_CONDITIONALS */
+private int
+parse_indirect_modifier(struct magic_set *ms, struct magic *m, const char **lp)
+{
+ const char *l = *lp;
+
+ while (!isspace((unsigned char)*++l))
+ switch (*l) {
+ case CHAR_INDIRECT_RELATIVE:
+ m->str_flags |= INDIRECT_RELATIVE;
+ break;
+ default:
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "indirect modifier `%c' "
+ "invalid", *l);
+ *lp = l;
+ return -1;
+ }
+ *lp = l;
+ return 0;
+}
+
+private void
+parse_op_modifier(struct magic_set *ms, struct magic *m, const char **lp,
+ int op)
+{
+ const char *l = *lp;
+ char *t;
+ uint64_t val;
+
+ ++l;
+ m->mask_op |= op;
+ val = (uint64_t)strtoull(l, &t, 0);
+ l = t;
+ m->num_mask = file_signextend(ms, m, val);
+ eatsize(&l);
+ *lp = l;
+}
+
+private int
+parse_string_modifier(struct magic_set *ms, struct magic *m, const char **lp)
+{
+ const char *l = *lp;
+ char *t;
+ int have_range = 0;
+
+ while (!isspace((unsigned char)*++l)) {
+ switch (*l) {
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ case '6': case '7': case '8':
+ case '9':
+ if (have_range && (ms->flags & MAGIC_CHECK))
+ file_magwarn(ms, "multiple ranges");
+ have_range = 1;
+ m->str_range = CAST(uint32_t, strtoul(l, &t, 0));
+ if (m->str_range == 0)
+ file_magwarn(ms, "zero range");
+ l = t - 1;
+ break;
+ case CHAR_COMPACT_WHITESPACE:
+ m->str_flags |= STRING_COMPACT_WHITESPACE;
+ break;
+ case CHAR_COMPACT_OPTIONAL_WHITESPACE:
+ m->str_flags |= STRING_COMPACT_OPTIONAL_WHITESPACE;
+ break;
+ case CHAR_IGNORE_LOWERCASE:
+ m->str_flags |= STRING_IGNORE_LOWERCASE;
+ break;
+ case CHAR_IGNORE_UPPERCASE:
+ m->str_flags |= STRING_IGNORE_UPPERCASE;
+ break;
+ case CHAR_REGEX_OFFSET_START:
+ m->str_flags |= REGEX_OFFSET_START;
+ break;
+ case CHAR_BINTEST:
+ m->str_flags |= STRING_BINTEST;
+ break;
+ case CHAR_TEXTTEST:
+ m->str_flags |= STRING_TEXTTEST;
+ break;
+ case CHAR_TRIM:
+ m->str_flags |= STRING_TRIM;
+ break;
+ case CHAR_PSTRING_1_LE:
+#define SET_LENGTH(a) m->str_flags = (m->str_flags & ~PSTRING_LEN) | (a)
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ SET_LENGTH(PSTRING_1_LE);
+ break;
+ case CHAR_PSTRING_2_BE:
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ SET_LENGTH(PSTRING_2_BE);
+ break;
+ case CHAR_PSTRING_2_LE:
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ SET_LENGTH(PSTRING_2_LE);
+ break;
+ case CHAR_PSTRING_4_BE:
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ SET_LENGTH(PSTRING_4_BE);
+ break;
+ case CHAR_PSTRING_4_LE:
+ switch (m->type) {
+ case FILE_PSTRING:
+ case FILE_REGEX:
+ break;
+ default:
+ goto bad;
+ }
+ SET_LENGTH(PSTRING_4_LE);
+ break;
+ case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF:
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF;
+ break;
+ default:
+ bad:
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "string modifier `%c' "
+ "invalid", *l);
+ goto out;
+ }
+ /* allow multiple '/' for readability */
+ if (l[1] == '/' && !isspace((unsigned char)l[2]))
+ l++;
+ }
+ if (string_modifier_check(ms, m) == -1)
+ goto out;
+ *lp = l;
+ return 0;
+out:
+ *lp = l;
+ return -1;
+}
+
/*
* parse one line from magic file, put into magic[index++] if valid
*/
m->str_range = 0;
m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0;
if ((op = get_op(*l)) != -1) {
- if (!IS_STRING(m->type)) {
- uint64_t val;
- ++l;
- m->mask_op |= op;
- val = (uint64_t)strtoull(l, &t, 0);
- l = t;
- m->num_mask = file_signextend(ms, m, val);
- eatsize(&l);
- }
- else if (op == FILE_OPDIVIDE) {
- int have_range = 0;
- while (!isspace((unsigned char)*++l)) {
- switch (*l) {
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8':
- case '9':
- if (have_range &&
- (ms->flags & MAGIC_CHECK))
- file_magwarn(ms,
- "multiple ranges");
- have_range = 1;
- m->str_range = CAST(uint32_t,
- strtoul(l, &t, 0));
- if (m->str_range == 0)
- file_magwarn(ms,
- "zero range");
- l = t - 1;
- break;
- case CHAR_COMPACT_WHITESPACE:
- m->str_flags |=
- STRING_COMPACT_WHITESPACE;
- break;
- case CHAR_COMPACT_OPTIONAL_WHITESPACE:
- m->str_flags |=
- STRING_COMPACT_OPTIONAL_WHITESPACE;
- break;
- case CHAR_IGNORE_LOWERCASE:
- m->str_flags |= STRING_IGNORE_LOWERCASE;
- break;
- case CHAR_IGNORE_UPPERCASE:
- m->str_flags |= STRING_IGNORE_UPPERCASE;
- break;
- case CHAR_REGEX_OFFSET_START:
- m->str_flags |= REGEX_OFFSET_START;
- break;
- case CHAR_BINTEST:
- m->str_flags |= STRING_BINTEST;
- break;
- case CHAR_TEXTTEST:
- m->str_flags |= STRING_TEXTTEST;
- break;
- case CHAR_TRIM:
- m->str_flags |= STRING_TRIM;
- break;
- case CHAR_PSTRING_1_LE:
- if (m->type != FILE_PSTRING)
- goto bad;
- m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_1_LE;
- break;
- case CHAR_PSTRING_2_BE:
- if (m->type != FILE_PSTRING)
- goto bad;
- m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_2_BE;
- break;
- case CHAR_PSTRING_2_LE:
- if (m->type != FILE_PSTRING)
- goto bad;
- m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_2_LE;
- break;
- case CHAR_PSTRING_4_BE:
- if (m->type != FILE_PSTRING)
- goto bad;
- m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_4_BE;
- break;
- case CHAR_PSTRING_4_LE:
- switch (m->type) {
- case FILE_PSTRING:
- case FILE_REGEX:
- break;
- default:
- goto bad;
- }
- m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_4_LE;
- break;
- case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF:
- if (m->type != FILE_PSTRING)
- goto bad;
- m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF;
- break;
- default:
- bad:
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms,
- "string extension `%c' "
- "invalid", *l);
- return -1;
- }
- /* allow multiple '/' for readability */
- if (l[1] == '/' &&
- !isspace((unsigned char)l[2]))
- l++;
+ if (IS_STRING(m->type)) {
+ int r;
+
+ if (op != FILE_OPDIVIDE) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms,
+ "invalid string/indirect op: "
+ "`%c'", *t);
+ return -1;
}
- if (string_modifier_check(ms, m) == -1)
+
+ if (m->type == FILE_INDIRECT)
+ r = parse_indirect_modifier(ms, m, &l);
+ else
+ r = parse_string_modifier(ms, m, &l);
+ if (r == -1)
return -1;
- }
- else {
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "invalid string op: %c", *t);
- return -1;
- }
+ } else
+ parse_op_modifier(ms, m, &l, op);
}
+
/*
* We used to set mask to all 1's here, instead let's just not do
* anything if mask = 0 (unless you have a better idea)
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: compress.c,v 1.74 2014/10/26 20:23:30 christos Exp $")
+FILE_RCSID("@(#)$File: compress.c,v 1.76 2014/12/11 11:47:08 christos Exp $")
#endif
#include "magic.h"
#endif
#include <string.h>
#include <errno.h>
+#include <signal.h>
#if !defined(__MINGW32__) && !defined(WIN32)
#include <sys/ioctl.h>
#endif
size_t i, nsz;
int rv = 0;
int mime = ms->flags & MAGIC_MIME;
+ sig_t osigpipe;
if ((ms->flags & MAGIC_COMPRESS) == 0)
return 0;
+ osigpipe = signal(SIGPIPE, SIG_IGN);
for (i = 0; i < ncompr; i++) {
if (nbytes < compr[i].maglen)
continue;
}
}
error:
+ (void)signal(SIGPIPE, osigpipe);
free(newbuf);
ms->flags |= MAGIC_COMPRESS;
return rv;
strerror(errno));
#endif
n = NODATA;
- } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ } else if (!WIFEXITED(status)) {
#ifdef DEBUG
- (void)fprintf(stderr, "Child status (0x%x)\n", status);
+ (void)fprintf(stderr, "Child not exited (0x%x)\n",
+ status);
+#endif
+ } else if (WEXITSTATUS(status) != 0) {
+#ifdef DEBUG
+ (void)fprintf(stderr, "Child exited (0x%d)\n",
+ WEXITSTATUS(status));
#endif
- n = NODATA;
}
(void) close(fdin[0]);
swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
type = elf_getu16(swap, elfhdr.e_type);
+ notecount = ms->elf_notes_max;
switch (type) {
#ifdef ELFCORE
case ET_CORE:
phnum = elf_getu16(swap, elfhdr.e_phnum);
if (phnum > ms->elf_phnum_max)
- return toomany(ms, "program", phnum);
+ return toomany(ms, "program headers", phnum);
flags |= FLAGS_IS_CORE;
if (dophn_core(ms, clazz, swap, fd,
(off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
(size_t)elf_getu16(swap, elfhdr.e_phentsize),
- fsize, &flags) == -1)
+ fsize, &flags, ¬ecount) == -1)
return -1;
break;
#endif
if (dophn_exec(ms, clazz, swap, fd,
(off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
(size_t)elf_getu16(swap, elfhdr.e_phentsize),
- fsize, &flags, shnum) == -1)
+ fsize, shnum, &flags, ¬ecount) == -1)
return -1;
/*FALLTHROUGH*/
case ET_REL:
shnum = elf_getu16(swap, elfhdr.e_shnum);
if (shnum > ms->elf_shnum_max)
- return toomany(ms, "section", shnum);
+ return toomany(ms, "section headers", shnum);
if (doshn(ms, clazz, swap, fd,
(off_t)elf_getu(swap, elfhdr.e_shoff), shnum,
(size_t)elf_getu16(swap, elfhdr.e_shentsize),
- fsize, &flags, elf_getu16(swap, elfhdr.e_machine),
- (int)elf_getu16(swap, elfhdr.e_shstrndx)) == -1)
+ fsize, elf_getu16(swap, elfhdr.e_machine),
+ (int)elf_getu16(swap, elfhdr.e_shstrndx),
+ &flags, ¬ecount) == -1)
return -1;
break;
default:
break;
}
+ if (notecount == 0)
+ return toomany(ms, "notes", ms->elf_notes_max);
return 1;
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: file.c,v 1.158 2014/11/28 02:35:05 christos Exp $")
+FILE_RCSID("@(#)$File: file.c,v 1.159 2014/11/28 02:46:39 christos Exp $")
#endif /* lint */
#include "magic.h"
{ "name", MAGIC_PARAM_NAME_MAX, 0 },
{ "elf_phnum", MAGIC_PARAM_ELF_PHNUM_MAX, 0 },
{ "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0 },
+ { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0 },
};
private char *progname; /* used throughout */
*/
/*
* file.h - definitions for file(1) program
- * @(#)$File: file.h,v 1.160 2014/11/28 02:46:39 christos Exp $
+ * @(#)$File: file.h,v 1.163 2014/12/16 23:18:40 christos Exp $
*/
#ifndef __file_h__
(t) == FILE_LESTRING16 || \
(t) == FILE_REGEX || \
(t) == FILE_SEARCH || \
+ (t) == FILE_INDIRECT || \
(t) == FILE_NAME || \
(t) == FILE_USE)
#define STRING_IGNORE_CASE (STRING_IGNORE_LOWERCASE|STRING_IGNORE_UPPERCASE)
#define STRING_DEFAULT_RANGE 100
+#define INDIRECT_RELATIVE BIT(0)
+#define CHAR_INDIRECT_RELATIVE 'r'
/* list of magic entries */
struct mlist {
uint16_t name_max;
uint16_t elf_shnum_max;
uint16_t elf_phnum_max;
+ uint16_t elf_notes_max;
#define FILE_INDIR_MAX 15
#define FILE_NAME_MAX 30
#define FILE_ELF_SHNUM_MAX 32768
#define FILE_ELF_PHNUM_MAX 128
+#define FILE_ELF_NOTES_MAX 256
};
/* Type for Unicode characters */
size_t *);
protected size_t file_pstring_length_size(const struct magic *);
protected size_t file_pstring_get_length(const struct magic *, const char *);
+protected char * file_printable(char *, size_t, const char *);
#ifdef __EMX__
protected int file_os2_apptype(struct magic_set *, const char *, const void *,
size_t);
OPT('P', "parameter", 0, " set file engine parameter limits\n"
" indir 15 recursion limit for indirection\n"
" name 30 use limit for name/use magic\n"
+ " elf_notes 256 max ELF notes processed\n"
" elf_phnum 128 max ELF prog sections processed\n"
" elf_shnum 32768 max ELF sections processed\n")
OPT('r', "raw", 0, " don't translate unprintable chars to \\ooo\n")
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: funcs.c,v 1.76 2014/11/28 02:35:05 christos Exp $")
+FILE_RCSID("@(#)$File: funcs.c,v 1.78 2014/12/11 12:34:24 christos Exp $")
#endif /* lint */
#include "magic.h"
free(pb);
return rbuf;
}
+
+/*
+ * convert string to ascii printable format.
+ */
+protected char *
+file_printable(char *buf, size_t bufsiz, const char *str)
+{
+ char *ptr, *eptr;
+ const unsigned char *s = (const unsigned char *)str;
+
+ for (ptr = buf, eptr = ptr + bufsiz - 1; ptr < eptr && *s; s++) {
+ if (isprint(*s)) {
+ *ptr++ = *s;
+ continue;
+ }
+ if (ptr >= eptr - 3)
+ break;
+ *ptr++ = '\\';
+ *ptr++ = ((*s >> 6) & 7) + '0';
+ *ptr++ = ((*s >> 3) & 7) + '0';
+ *ptr++ = ((*s >> 0) & 7) + '0';
+ }
+ *ptr = '\0';
+ return buf;
+}
}
}
-ssize_t
+public ssize_t
getline(char **buf, size_t *bufsiz, FILE *fp)
{
return getdelim(buf, bufsiz, '\n', fp);
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: magic.c,v 1.89 2014/11/28 02:46:39 christos Exp $")
+FILE_RCSID("@(#)$File: magic.c,v 1.90 2014/12/04 15:56:46 christos Exp $")
#endif /* lint */
#include "magic.h"
case MAGIC_PARAM_ELF_SHNUM_MAX:
ms->elf_shnum_max = *(const size_t *)val;
return 0;
+ case MAGIC_PARAM_ELF_NOTES_MAX:
+ ms->elf_notes_max = *(const size_t *)val;
+ return 0;
default:
errno = EINVAL;
return -1;
case MAGIC_PARAM_ELF_SHNUM_MAX:
*(size_t *)val = ms->elf_shnum_max;
return 0;
+ case MAGIC_PARAM_ELF_NOTES_MAX:
+ *(size_t *)val = ms->elf_notes_max;
+ return 0;
default:
errno = EINVAL;
return -1;
#define MAGIC_PARAM_NAME_MAX 1
#define MAGIC_PARAM_ELF_PHNUM_MAX 2
#define MAGIC_PARAM_ELF_SHNUM_MAX 3
+#define MAGIC_PARAM_ELF_NOTES_MAX 4
int magic_setparam(magic_t, int, const void *);
int magic_getparam(magic_t, int, void *);
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: readelf.c,v 1.110 2014/12/09 02:47:07 christos Exp $")
+FILE_RCSID("@(#)$File: readelf.c,v 1.116 2014/12/16 23:18:40 christos Exp $")
#endif
#ifdef BUILTIN_ELF
#ifdef ELFCORE
private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
- off_t, int *);
+ off_t, int *, uint16_t *);
#endif
private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
- off_t, int *, int);
+ off_t, int, int *, uint16_t *);
private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
- off_t, int *, int, int);
+ off_t, int, int, int *, uint16_t *);
private size_t donote(struct magic_set *, void *, size_t, size_t, int,
- int, size_t, int *);
+ int, size_t, int *, uint16_t *);
#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align)
private int
toomany(struct magic_set *ms, const char *name, uint16_t num)
{
- if (file_printf(ms, ", too many %s header sections (%u)", name, num
+ if (file_printf(ms, ", too many %s (%u)", name, num
) == -1)
return -1;
return 0;
"NetBSD",
};
-#define FLAGS_DID_CORE 0x01
-#define FLAGS_DID_NOTE 0x02
-#define FLAGS_DID_BUILD_ID 0x04
-#define FLAGS_DID_CORE_STYLE 0x08
-#define FLAGS_IS_CORE 0x10
+#define FLAGS_DID_CORE 0x001
+#define FLAGS_DID_OS_NOTE 0x002
+#define FLAGS_DID_BUILD_ID 0x004
+#define FLAGS_DID_CORE_STYLE 0x008
+#define FLAGS_DID_NETBSD_PAX 0x010
+#define FLAGS_DID_NETBSD_MARCH 0x020
+#define FLAGS_DID_NETBSD_CMODEL 0x040
+#define FLAGS_DID_NETBSD_UNKNOWN 0x080
+#define FLAGS_IS_CORE 0x100
private int
dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
- int num, size_t size, off_t fsize, int *flags)
+ int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
{
Elf32_Phdr ph32;
Elf64_Phdr ph64;
* Loop through all the program headers.
*/
for ( ; num; num--) {
- if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
+ if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
file_badread(ms);
return -1;
}
if (offset >= (size_t)bufsize)
break;
offset = donote(ms, nbuf, offset, (size_t)bufsize,
- clazz, swap, 4, flags);
+ clazz, swap, 4, flags, notecount);
if (offset == 0)
break;
}
}
-private size_t
-donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
- int clazz, int swap, size_t align, int *flags)
+private int
+do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
+ size_t noff, size_t doff, int *flags)
{
- Elf32_Nhdr nh32;
- Elf64_Nhdr nh64;
- size_t noff, doff;
-#ifdef ELFCORE
- int os_style = -1;
-#endif
- uint32_t namesz, descsz;
- unsigned char *nbuf = CAST(unsigned char *, vbuf);
-
- if (xnh_sizeof + offset > size) {
- /*
- * We're out of note headers.
- */
- return xnh_sizeof + offset;
- }
-
- (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
- offset += xnh_sizeof;
-
- namesz = xnh_namesz;
- descsz = xnh_descsz;
- if ((namesz == 0) && (descsz == 0)) {
- /*
- * We're out of note headers.
- */
- return (offset >= size) ? offset : size;
- }
-
- if (namesz & 0x80000000) {
- (void)file_printf(ms, ", bad note name size 0x%lx",
- (unsigned long)namesz);
- return 0;
- }
-
- if (descsz & 0x80000000) {
- (void)file_printf(ms, ", bad note description size 0x%lx",
- (unsigned long)descsz);
- return 0;
- }
-
-
- noff = offset;
- doff = ELF_ALIGN(offset + namesz);
-
- if (offset + namesz > size) {
- /*
- * We're past the end of the buffer.
- */
- return doff;
- }
-
- offset = ELF_ALIGN(doff + descsz);
- if (doff + descsz > size) {
- /*
- * We're past the end of the buffer.
- */
- return (offset >= size) ? offset : size;
+ if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
+ type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
+ uint8_t desc[20];
+ uint32_t i;
+ *flags |= FLAGS_DID_BUILD_ID;
+ if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
+ "sha1") == -1)
+ return 1;
+ (void)memcpy(desc, &nbuf[doff], descsz);
+ for (i = 0; i < descsz; i++)
+ if (file_printf(ms, "%02x", desc[i]) == -1)
+ return 1;
+ return 1;
}
+ return 0;
+}
- if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) ==
- (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID))
- goto core;
-
+private int
+do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap, uint32_t namesz, uint32_t descsz,
+ size_t noff, size_t doff, int *flags)
+{
if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
- xnh_type == NT_GNU_VERSION && descsz == 2) {
+ type == NT_GNU_VERSION && descsz == 2) {
+ *flags |= FLAGS_DID_OS_NOTE;
file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]);
+ return 1;
}
+
if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
- xnh_type == NT_GNU_VERSION && descsz == 16) {
+ type == NT_GNU_VERSION && descsz == 16) {
uint32_t desc[4];
(void)memcpy(desc, &nbuf[doff], sizeof(desc));
+ *flags |= FLAGS_DID_OS_NOTE;
if (file_printf(ms, ", for GNU/") == -1)
- return size;
+ return 1;
switch (elf_getu32(swap, desc[0])) {
case GNU_OS_LINUX:
if (file_printf(ms, "Linux") == -1)
- return size;
+ return 1;
break;
case GNU_OS_HURD:
if (file_printf(ms, "Hurd") == -1)
- return size;
+ return 1;
break;
case GNU_OS_SOLARIS:
if (file_printf(ms, "Solaris") == -1)
- return size;
+ return 1;
break;
case GNU_OS_KFREEBSD:
if (file_printf(ms, "kFreeBSD") == -1)
- return size;
+ return 1;
break;
case GNU_OS_KNETBSD:
if (file_printf(ms, "kNetBSD") == -1)
- return size;
+ return 1;
break;
default:
if (file_printf(ms, "<unknown>") == -1)
- return size;
+ return 1;
}
if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
- return size;
- *flags |= FLAGS_DID_NOTE;
- return size;
+ return 1;
+ return 1;
}
- if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
- xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
- uint8_t desc[20];
- uint32_t i;
- if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
- "sha1") == -1)
- return size;
- (void)memcpy(desc, &nbuf[doff], descsz);
- for (i = 0; i < descsz; i++)
- if (file_printf(ms, "%02x", desc[i]) == -1)
- return size;
- *flags |= FLAGS_DID_BUILD_ID;
+ if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
+ if (type == NT_NETBSD_VERSION && descsz == 4) {
+ *flags |= FLAGS_DID_OS_NOTE;
+ do_note_netbsd_version(ms, swap, &nbuf[doff]);
+ return 1;
+ }
+ }
+
+ if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
+ if (type == NT_FREEBSD_VERSION && descsz == 4) {
+ *flags |= FLAGS_DID_OS_NOTE;
+ do_note_freebsd_version(ms, swap, &nbuf[doff]);
+ return 1;
+ }
+ }
+
+ if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
+ type == NT_OPENBSD_VERSION && descsz == 4) {
+ *flags |= FLAGS_DID_OS_NOTE;
+ if (file_printf(ms, ", for OpenBSD") == -1)
+ return 1;
+ /* Content of note is always 0 */
+ return 1;
+ }
+
+ if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
+ type == NT_DRAGONFLY_VERSION && descsz == 4) {
+ uint32_t desc;
+ *flags |= FLAGS_DID_OS_NOTE;
+ if (file_printf(ms, ", for DragonFly") == -1)
+ return 1;
+ (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
+ desc = elf_getu32(swap, desc);
+ if (file_printf(ms, " %d.%d.%d", desc / 100000,
+ desc / 10000 % 10, desc % 10000) == -1)
+ return 1;
+ return 1;
}
+ return 0;
+}
+private int
+do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap, uint32_t namesz, uint32_t descsz,
+ size_t noff, size_t doff, int *flags)
+{
if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
- xnh_type == NT_NETBSD_PAX && descsz == 4) {
+ type == NT_NETBSD_PAX && descsz == 4) {
static const char *pax[] = {
"+mprotect",
"-mprotect",
size_t i;
int did = 0;
+ *flags |= FLAGS_DID_NETBSD_PAX;
(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
desc = elf_getu32(swap, desc);
if (desc && file_printf(ms, ", PaX: ") == -1)
- return size;
+ return 1;
for (i = 0; i < __arraycount(pax); i++) {
if (((1 << i) & desc) == 0)
continue;
if (file_printf(ms, "%s%s", did++ ? "," : "",
pax[i]) == -1)
- return size;
+ return 1;
}
+ return 1;
}
+ return 0;
+}
- if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
- switch (xnh_type) {
- case NT_NETBSD_VERSION:
- if (descsz == 4) {
- do_note_netbsd_version(ms, swap, &nbuf[doff]);
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
- break;
- case NT_NETBSD_MARCH:
- if (file_printf(ms, ", compiled for: %.*s", (int)descsz,
- (const char *)&nbuf[doff]) == -1)
- return size;
- break;
- case NT_NETBSD_CMODEL:
- if (file_printf(ms, ", compiler model: %.*s",
- (int)descsz, (const char *)&nbuf[doff]) == -1)
- return size;
- break;
- default:
- if (file_printf(ms, ", note=%u", xnh_type) == -1)
- return size;
- break;
- }
- return size;
- }
-
- if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
- if (xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
- do_note_freebsd_version(ms, swap, &nbuf[doff]);
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
- }
-
- if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
- xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
- if (file_printf(ms, ", for OpenBSD") == -1)
- return size;
- /* Content of note is always 0 */
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
-
- if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
- xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
- uint32_t desc;
- if (file_printf(ms, ", for DragonFly") == -1)
- return size;
- (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
- desc = elf_getu32(swap, desc);
- if (file_printf(ms, " %d.%d.%d", desc / 100000,
- desc / 10000 % 10, desc % 10000) == -1)
- return size;
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
-
-core:
+private int
+do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap, uint32_t namesz, uint32_t descsz,
+ size_t noff, size_t doff, int *flags, size_t size, int clazz)
+{
+#ifdef ELFCORE
+ int os_style = -1;
/*
* Sigh. The 2.0.36 kernel in Debian 2.1, at
* least, doesn't correctly implement name
os_style = OS_STYLE_NETBSD;
}
-#ifdef ELFCORE
- if ((*flags & FLAGS_DID_CORE) != 0)
- return size;
-
if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
if (file_printf(ms, ", %s-style", os_style_names[os_style])
== -1)
- return size;
+ return 1;
*flags |= FLAGS_DID_CORE_STYLE;
}
switch (os_style) {
case OS_STYLE_NETBSD:
- if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
+ if (type == NT_NETBSD_CORE_PROCINFO) {
+ char sbuf[512];
uint32_t signo;
/*
* Extract the program name. It is at
* including the terminating NUL.
*/
if (file_printf(ms, ", from '%.31s'",
- &nbuf[doff + 0x7c]) == -1)
- return size;
+ file_printable(sbuf, sizeof(sbuf),
+ (const char *)&nbuf[doff + 0x7c])) == -1)
+ return 1;
/*
* Extract the signal number. It is at
sizeof(signo));
if (file_printf(ms, " (signal %u)",
elf_getu32(swap, signo)) == -1)
- return size;
+ return 1;
*flags |= FLAGS_DID_CORE;
- return size;
+ return 1;
}
break;
default:
- if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
+ if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
size_t i, j;
unsigned char c;
/*
* Try next offsets, in case this match is
* in the middle of a string.
*/
- for (k = i + 1 ; k < NOFFSETS ; k++) {
+ for (k = i + 1 ; k < NOFFSETS; k++) {
size_t no;
int adjust = 1;
if (prpsoffsets(k) >= prpsoffsets(i))
cp--;
if (file_printf(ms, ", from '%.*s'",
(int)(cp - cname), cname) == -1)
- return size;
+ return 1;
*flags |= FLAGS_DID_CORE;
- return size;
+ return 1;
tryanother:
;
break;
}
#endif
+ return 0;
+}
+
+private size_t
+donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
+ int clazz, int swap, size_t align, int *flags, uint16_t *notecount)
+{
+ Elf32_Nhdr nh32;
+ Elf64_Nhdr nh64;
+ size_t noff, doff;
+ uint32_t namesz, descsz;
+ unsigned char *nbuf = CAST(unsigned char *, vbuf);
+
+ if (*notecount == 0)
+ return 0;
+ --*notecount;
+
+ if (xnh_sizeof + offset > size) {
+ /*
+ * We're out of note headers.
+ */
+ return xnh_sizeof + offset;
+ }
+
+ (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
+ offset += xnh_sizeof;
+
+ namesz = xnh_namesz;
+ descsz = xnh_descsz;
+ if ((namesz == 0) && (descsz == 0)) {
+ /*
+ * We're out of note headers.
+ */
+ return (offset >= size) ? offset : size;
+ }
+
+ if (namesz & 0x80000000) {
+ (void)file_printf(ms, ", bad note name size 0x%lx",
+ (unsigned long)namesz);
+ return 0;
+ }
+
+ if (descsz & 0x80000000) {
+ (void)file_printf(ms, ", bad note description size 0x%lx",
+ (unsigned long)descsz);
+ return 0;
+ }
+
+ noff = offset;
+ doff = ELF_ALIGN(offset + namesz);
+
+ if (offset + namesz > size) {
+ /*
+ * We're past the end of the buffer.
+ */
+ return doff;
+ }
+
+ offset = ELF_ALIGN(doff + descsz);
+ if (doff + descsz > size) {
+ /*
+ * We're past the end of the buffer.
+ */
+ return (offset >= size) ? offset : size;
+ }
+
+ if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
+ if (do_os_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags))
+ return size;
+ }
+
+ if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
+ if (do_bid_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags))
+ return size;
+ }
+
+ if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
+ if (do_pax_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags))
+ return size;
+ }
+
+ if ((*flags & FLAGS_DID_CORE) == 0) {
+ if (do_core_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags, size, clazz))
+ return size;
+ }
+
+ if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
+ if (descsz > 100)
+ descsz = 100;
+ switch (xnh_type) {
+ case NT_NETBSD_VERSION:
+ return size;
+ case NT_NETBSD_MARCH:
+ if (*flags & FLAGS_DID_NETBSD_MARCH)
+ return size;
+ *flags |= FLAGS_DID_NETBSD_MARCH;
+ if (file_printf(ms, ", compiled for: %.*s",
+ (int)descsz, (const char *)&nbuf[doff]) == -1)
+ return size;
+ break;
+ case NT_NETBSD_CMODEL:
+ if (*flags & FLAGS_DID_NETBSD_CMODEL)
+ return size;
+ *flags |= FLAGS_DID_NETBSD_CMODEL;
+ if (file_printf(ms, ", compiler model: %.*s",
+ (int)descsz, (const char *)&nbuf[doff]) == -1)
+ return size;
+ break;
+ default:
+ if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
+ return size;
+ *flags |= FLAGS_DID_NETBSD_UNKNOWN;
+ if (file_printf(ms, ", note=%u", xnh_type) == -1)
+ return size;
+ break;
+ }
+ return size;
+ }
+
return offset;
}
private int
doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
- size_t size, off_t fsize, int *flags, int mach, int strtab)
+ size_t size, off_t fsize, int mach, int strtab, int *flags,
+ uint16_t *notecount)
{
Elf32_Shdr sh32;
Elf64_Shdr sh64;
uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */
uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */
char name[50];
+ ssize_t namesize;
if (size != xsh_sizeof) {
if (file_printf(ms, ", corrupted section header size") == -1)
}
/* Read offset of name section to be able to read section names later */
- if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) == -1) {
+ if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) < (ssize_t)xsh_sizeof) {
file_badread(ms);
return -1;
}
for ( ; num; num--) {
/* Read the name of this section. */
- if (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) {
+ if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
file_badread(ms);
return -1;
}
- name[sizeof(name) - 1] = '\0';
+ name[namesize] = '\0';
if (strcmp(name, ".debug_info") == 0)
stripped = 0;
- if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) {
+ if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
file_badread(ms);
return -1;
}
" for note");
return -1;
}
- if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) {
+ if (pread(fd, nbuf, xsh_size, xsh_offset) < (ssize_t)xsh_size) {
file_badread(ms);
free(nbuf);
return -1;
if (noff >= (off_t)xsh_size)
break;
noff = donote(ms, nbuf, (size_t)noff,
- xsh_size, clazz, swap, 4, flags);
+ xsh_size, clazz, swap, 4, flags, notecount);
if (noff == 0)
break;
}
*/
private int
dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
- int num, size_t size, off_t fsize, int *flags, int sh_num)
+ int num, size_t size, off_t fsize, int sh_num, int *flags,
+ uint16_t *notecount)
{
Elf32_Phdr ph32;
Elf64_Phdr ph64;
const char *linking_style = "statically";
- const char *shared_libraries = "";
+ const char *interp = "";
unsigned char nbuf[BUFSIZ];
+ char ibuf[BUFSIZ];
ssize_t bufsize;
size_t offset, align, len;
}
for ( ; num; num--) {
- if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
+ if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
file_badread(ms);
return -1;
}
off += size;
+ bufsize = 0;
+ align = 4;
/* Things we can determine before we seek */
switch (xph_type) {
case PT_DYNAMIC:
linking_style = "dynamically";
break;
+ case PT_NOTE:
+ if (sh_num) /* Did this through section headers */
+ continue;
+ if (((align = xph_align) & 0x80000000UL) != 0 ||
+ align < 4) {
+ if (file_printf(ms,
+ ", invalid note alignment 0x%lx",
+ (unsigned long)align) == -1)
+ return -1;
+ align = 4;
+ }
+ /*FALLTHROUGH*/
case PT_INTERP:
- shared_libraries = " (uses shared libs)";
+ len = xph_filesz < sizeof(nbuf) ? xph_filesz
+ : sizeof(nbuf);
+ bufsize = pread(fd, nbuf, len, xph_offset);
+ if (bufsize == -1) {
+ file_badread(ms);
+ return -1;
+ }
break;
default:
if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
/* Things we can determine when we seek */
switch (xph_type) {
+ case PT_INTERP:
+ if (bufsize && nbuf[0]) {
+ nbuf[bufsize - 1] = '\0';
+ interp = (const char *)nbuf;
+ } else
+ interp = "*empty*";
+ break;
case PT_NOTE:
- if (((align = xph_align) & 0x80000000UL) != 0 ||
- align < 4) {
- if (file_printf(ms,
- ", invalid note alignment 0x%lx",
- (unsigned long)align) == -1)
- return -1;
- align = 4;
- }
- if (sh_num)
- break;
/*
* This is a PT_NOTE section; loop through all the notes
* in the section.
*/
- len = xph_filesz < sizeof(nbuf) ? xph_filesz
- : sizeof(nbuf);
- bufsize = pread(fd, nbuf, len, xph_offset);
- if (bufsize == -1) {
- file_badread(ms);
- return -1;
- }
offset = 0;
for (;;) {
if (offset >= (size_t)bufsize)
break;
offset = donote(ms, nbuf, offset,
(size_t)bufsize, clazz, swap, align,
- flags);
+ flags, notecount);
if (offset == 0)
break;
}
break;
}
}
- if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries)
+ if (file_printf(ms, ", %s linked", linking_style)
== -1)
- return -1;
+ return -1;
+ if (interp[0])
+ if (file_printf(ms, ", interpreter %s",
+ file_printable(ibuf, sizeof(ibuf), interp)) == -1)
+ return -1;
return 0;
}
int flags = 0;
Elf32_Ehdr elf32hdr;
Elf64_Ehdr elf64hdr;
- uint16_t type, phnum, shnum;
+ uint16_t type, phnum, shnum, notecount;
if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
return 0;
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: softmagic.c,v 1.202 2014/11/28 02:46:39 christos Exp $")
+FILE_RCSID("@(#)$File: softmagic.c,v 1.205 2015/01/01 04:12:23 christos Exp $")
#endif /* lint */
#include "magic.h"
}
#endif /* HAVE_STRNDUP */
-static char *
-printable(char *buf, size_t bufsiz, const char *str)
-{
- char *ptr, *eptr;
- const unsigned char *s = (const unsigned char *)str;
-
- for (ptr = buf, eptr = ptr + bufsiz - 1; ptr < eptr && *s; s++) {
- if (isprint(*s)) {
- *ptr++ = *s;
- continue;
- }
- if (ptr >= eptr + 4)
- break;
- *ptr++ = '\\';
- *ptr++ = ((*s >> 6) & 7) + '0';
- *ptr++ = ((*s >> 3) & 7) + '0';
- *ptr++ = ((*s >> 0) & 7) + '0';
- }
- *ptr = '\0';
- return buf;
-}
-
private int32_t
mprint(struct magic_set *ms, struct magic *m)
{
float vf;
double vd;
int64_t t = 0;
- char buf[128], tbuf[26];
+ char buf[128], tbuf[26], sbuf[512];
union VALUETYPE *p = &ms->ms_value;
switch (m->type) {
case FILE_BESTRING16:
case FILE_LESTRING16:
if (m->reln == '=' || m->reln == '!') {
- if (file_printf(ms, F(ms, m, "%s"), m->value.s) == -1)
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_printable(sbuf, sizeof(sbuf), m->value.s))
+ == -1)
return -1;
t = ms->offset + m->vallen;
}
else {
- char sbuf[512];
char *str = p->s;
/* compute t before we mangle the string? */
}
if (file_printf(ms, F(ms, m, "%s"),
- printable(sbuf, sizeof(sbuf), str)) == -1)
+ file_printable(sbuf, sizeof(sbuf), str)) == -1)
return -1;
if (m->type == FILE_PSTRING)
file_oomem(ms, ms->search.rm_len);
return -1;
}
- rval = file_printf(ms, F(ms, m, "%s"), cp);
+ rval = file_printf(ms, F(ms, m, "%s"),
+ file_printable(sbuf, sizeof(sbuf), cp));
free(cp);
if (rval == -1)
}
case FILE_SEARCH:
- if (file_printf(ms, F(ms, m, "%s"), m->value.s) == -1)
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_printable(sbuf, sizeof(sbuf), m->value.s)) == -1)
return -1;
if ((m->str_flags & REGEX_OFFSET_START))
t = ms->search.offset;
break;
case FILE_INDIRECT:
+ if (m->str_flags & INDIRECT_RELATIVE)
+ offset += o;
if (offset == 0)
return 0;