lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20170625171230.7613-1-enrico.weigelt@gr13.net>
Date:   Sun, 25 Jun 2017 19:12:30 +0200
From:   "Enrico Weigelt, metux IT consult" <enrico.weigelt@...3.net>
To:     linux-kernel@...r.kernel.org
Subject: [PATCH] lib: vsprintf: add printf format conversion %M for errno strings

Adding a new format conversion for *printf() and friends.

If CONFIG_ERRNO_PRINTF_VERBOSE is enabled, prints human-readable
strerror()-like texts, otherwise just the number.
---
 lib/Kconfig    |  19 +++++++
 lib/vsprintf.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 189 insertions(+), 2 deletions(-)

diff --git a/lib/Kconfig b/lib/Kconfig
index 0c8b78a9ae2e..b28ab2162435 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -7,6 +7,25 @@ config BINARY_PRINTF
 
 menu "Library routines"
 
+config ERRNO_PRINTF
+	bool "printf conversion %M for errno codes"
+	default n
+	help
+	  This option adds an %M modifier for *printf() for errno values.
+	  (and callers like printk() etc)
+
+	  In conjunction with ERRNO_PRINTF_VERBOSE, it prints human readable
+	  strerror()-like textsm, otherwise just numeric values
+
+config ERRNO_PRINTF_VERBOSE
+	bool "Verbose errno strings"
+	default y
+	depends on ERRNO_PRINTF
+	help
+	  Enable verbose error strings for ERRNO_PRINTF.
+
+	  Small embedded systems might disable it for reducing kernel size.
+
 config RAID6_PQ
 	tristate
 
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 2d41de3f98a1..9778e17fc178 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -382,7 +382,8 @@ enum format_type {
 	FORMAT_TYPE_UINT,
 	FORMAT_TYPE_INT,
 	FORMAT_TYPE_SIZE_T,
-	FORMAT_TYPE_PTRDIFF
+	FORMAT_TYPE_PTRDIFF,
+	FORMAT_TYPE_ERRNO,
 };
 
 struct printf_spec {
@@ -600,6 +601,164 @@ char *string(char *buf, char *end, const char *s, struct printf_spec spec)
 	return widen_string(buf, len, end, spec);
 }
 
+#if IS_ENABLED(CONFIG_ERRNO_PRINTF_VERBOSE)
+static noinline_for_stack
+const char *errno_to_str(int no)
+{
+	switch (no) {
+	case 0:			return "Success";
+	case EPERM:		return "Operation not permitted";
+	case ENOENT:		return "No such file or directory";
+	case ESRCH:		return "No such process";
+	case EINTR:		return "Interrupted system call";
+	case EIO:		return "I/O error";
+	case ENXIO:		return "No such device or address";
+	case E2BIG:		return "Argument list too long";
+	case ENOEXEC:		return "Exec format error";
+	case EBADF:		return "Bad file number";
+	case ECHILD:		return "No child processes";
+	case EAGAIN:		return "Try again";
+	case ENOMEM:		return "Out of memory";
+	case EACCES:		return "Permission denied";
+	case EFAULT:		return "Bad address";
+	case ENOTBLK:		return "Block device required";
+	case EBUSY:		return "Device or resource busy";
+	case EEXIST:		return "File exists";
+	case EXDEV:		return "Cross-device link";
+	case ENODEV:		return "No such device";
+	case ENOTDIR:		return "Not a directory";
+	case EISDIR:		return "Is a directory";
+	case EINVAL:		return "Invalid argument";
+	case ENFILE:		return "File table overflow";
+	case EMFILE:		return "Too many open files";
+	case ENOTTY:		return "Not a typewriter";
+	case ETXTBSY:		return "Text file busy";
+	case EFBIG:		return "File too large";
+	case ENOSPC:		return "No space left on device";
+	case ESPIPE:		return "Illegal seek";
+	case EROFS:		return "Read-only file system";
+	case EMLINK:		return "Too many links";
+	case EPIPE:		return "Broken pipe";
+	case EDOM:		return "Math argument out of domain of func";
+	case ERANGE:		return "Math result not representable";
+	case EDEADLK:		return "Resource deadlock would occur";
+	case ENAMETOOLONG:	return "File name too long";
+	case ENOLCK:		return "No record locks available";
+	case ENOSYS:		return "Invalid system call number";
+	case ENOTEMPTY:		return "Directory not empty";
+	case ELOOP:		return "Too many symbolic links encountered";
+	case ENOMSG:		return "No message of desired type";
+	case EIDRM:		return "Identifier removed";
+	case ECHRNG:		return "Channel number out of range";
+	case EL2NSYNC:		return "Level 2 not synchronized";
+	case EL3HLT:		return "Level 3 halted";
+	case EL3RST:		return "Level 3 reset";
+	case ELNRNG:		return "Link number out of range";
+	case EUNATCH:		return "Protocol driver not attached";
+	case ENOCSI:		return "No CSI structure available";
+	case EL2HLT:		return "Level 2 halted";
+	case EBADE:		return "Invalid exchange";
+	case EBADR:		return "Invalid request descriptor";
+	case EXFULL:		return "Exchange full";
+	case ENOANO:		return "No anode";
+	case EBADRQC:		return "Invalid request code";
+	case EBADSLT:		return "Invalid slot";
+	case EBFONT:		return "Bad font file format";
+	case ENOSTR:		return "Device not a stream";
+	case ENODATA:		return "No data available";
+	case ETIME:		return "Timer expired";
+	case ENOSR:		return "Out of streams resources";
+	case ENONET:		return "Machine is not on the network";
+	case ENOPKG:		return "Package not installed";
+	case EREMOTE:		return "Object is remote";
+	case ENOLINK:		return "Link has been severed";
+	case EADV:		return "Advertise error";
+	case ESRMNT:		return "Srmount error";
+	case ECOMM:		return "Communication error on send";
+	case EPROTO:		return "Protocol error";
+	case EMULTIHOP:		return "Multihop attempted";
+	case EDOTDOT:		return "RFS specific error";
+	case EBADMSG:		return "Not a data message";
+	case EOVERFLOW:		return "Value too large for defined data type";
+	case ENOTUNIQ:		return "Name not unique on network";
+	case EBADFD:		return "File descriptor in bad state";
+	case EREMCHG:		return "Remote address changed";
+	case ELIBACC:		return "Can not access a needed shared library";
+	case ELIBBAD:		return "Accessing a corrupted shared library";
+	case ELIBSCN:		return ".lib section in a.out corrupted";
+	case ELIBMAX:		return "Attempting to link in too many shared libraries";
+	case ELIBEXEC:		return "Cannot exec a shared library directly";
+	case EILSEQ:		return "Illegal byte sequence";
+	case ERESTART:		return "Interrupted system call should be restarted";
+	case ESTRPIPE:		return "Streams pipe error";
+	case EUSERS:		return "Too many users";
+	case EDESTADDRREQ:	return "Destination address required";
+	case EMSGSIZE:		return "Message too long";
+	case EPROTOTYPE:	return "Protocol wrong type for socket";
+	case ENOPROTOOPT:	return "Protocol not available";
+	case EPROTONOSUPPORT:	return "Protocol not supported";
+	case ESOCKTNOSUPPORT:	return "Socket type not supported";
+	case EOPNOTSUPP:	return "Operation not supported on transport endpoint";
+	case EPFNOSUPPORT:	return "Protocol family not supported";
+	case EAFNOSUPPORT:	return "Address family not supported by protocol";
+	case EADDRINUSE:	return "Address already in use";
+	case EADDRNOTAVAIL:	return "Cannot assign requested address";
+	case ENETDOWN:		return "Network is down";
+	case ENETUNREACH:	return "Network is unreachable";
+	case ENETRESET:		return "Network dropped connection because of reset";
+	case ECONNABORTED:	return "Software caused connection abort";
+	case ECONNRESET:	return "Connection reset by peer";
+	case ENOBUFS:		return "No buffer space available";
+	case EISCONN:		return "Transport endpoint is already connected";
+	case ENOTCONN:		return "Transport endpoint is not connected";
+	case ESHUTDOWN:		return "Cannot send after transport endpoint shutdown";
+	case ETOOMANYREFS:	return "Too many references: cannot splice";
+	case ETIMEDOUT:		return "Connection timed out";
+	case ECONNREFUSED:	return "Connection refused";
+	case EHOSTDOWN:		return "Host is down";
+	case EHOSTUNREACH:	return "No route to host";
+	case EALREADY:		return "Operation already in progress";
+	case EINPROGRESS:	return "Operation now in progress";
+	case ESTALE:		return "Stale file handle";
+	case EUCLEAN:		return "Structure needs cleaning";
+	case ENOTNAM:		return "Not a XENIX named type file";
+	case ENAVAIL:		return "No XENIX semaphores available";
+	case EISNAM:		return "Is a named type file";
+	case EREMOTEIO:		return "Remote I/O error";
+	case EDQUOT:		return "Quota exceeded";
+	case ENOMEDIUM:		return "No medium found";
+	case EMEDIUMTYPE:	return "Wrong medium type";
+	case ECANCELED:		return "Operation Canceled";
+	case ENOKEY:		return "Required key not available";
+	case EKEYEXPIRED:	return "Key has expired";
+	case EKEYREVOKED:	return "Key has been revoked";
+	case EKEYREJECTED:	return "Key was rejected by service";
+	case EOWNERDEAD:	return "Owner died";
+	case ENOTRECOVERABLE:	return "State not recoverable";
+	case ERFKILL:		return "Operation not possible due to RF-kill";
+	case EHWPOISON:		return "Memory page has hardware error";
+	}
+	return NULL;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_ERRNO_PRINTF)
+static noinline_for_stack
+char *errno_string(char *buf, char *end, int errcode, struct printf_spec spec)
+{
+	char buffer[32];
+
+#if IS_ENABLED(CONFIG_ERRNO_PRINTF_VERBOSE)
+	const char *estr = errno_to_str(errcode);
+	if (estr != NULL)
+		return string(buf, end, estr, spec);
+#endif
+
+	snprintf(buffer, sizeof(buffer), "error %d", errcode);
+	return string(buf, end, buffer, spec);
+}
+#endif
+
 static noinline_for_stack
 char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec,
 		  const char *fmt)
@@ -1744,6 +1903,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
  * 'z' changed to 'Z' --davidm 1/25/99
  * 'Z' changed to 'z' --adobriyan 2017-01-25
  * 't' added for ptrdiff_t
+ * 'M' added for strerror()-like output --mtx 2017-06-25
  *
  * @fmt: the format string
  * @type of the token returned
@@ -1866,6 +2026,10 @@ int format_decode(const char *fmt, struct printf_spec *spec)
 		spec->type = FORMAT_TYPE_STR;
 		return ++fmt - start;
 
+	case 'M':
+		spec->type = FORMAT_TYPE_ERRNO;
+		return ++fmt - start;
+
 	case 'p':
 		spec->type = FORMAT_TYPE_PTR;
 		return ++fmt - start;
@@ -2047,7 +2211,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 		case FORMAT_TYPE_STR:
 			str = string(str, end, va_arg(args, char *), spec);
 			break;
-
+#if IS_ENABLED(CONFIG_ERRNO_PRINTF)
+		case FORMAT_TYPE_ERRNO:
+			str = errno_string(str, end, va_arg(args, int), spec);
+			break;
+#endif
 		case FORMAT_TYPE_PTR:
 			str = pointer(fmt, str, end, va_arg(args, void *),
 				      spec);
-- 
2.11.0.rc0.7.gbe5a750

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ