Commit 9ca71874 authored by Francis Laniel's avatar Francis Laniel Committed by Jakub Kicinski
Browse files

Modify return value of nla_strlcpy to match that of strscpy.



nla_strlcpy now returns -E2BIG if src was truncated when written to dst.
It also returns this error value if dstsize is 0 or higher than INT_MAX.

For example, if src is "foo\0" and dst is 3 bytes long, the result will be:
1. "foG" after memcpy (G means garbage).
2. "fo\0" after memset.
3. -E2BIG is returned because src was not completely written into dst.

The callers of nla_strlcpy were modified to take into account this modification.

Signed-off-by: default avatarFrancis Laniel <laniel_francis@privacyrequired.com>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 8eeb99bc
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -506,7 +506,7 @@ int __nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
		struct netlink_ext_ack *extack);
int nla_policy_len(const struct nla_policy *, int);
struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype);
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize);
ssize_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize);
char *nla_strdup(const struct nlattr *nla, gfp_t flags);
int nla_memcpy(void *dest, const struct nlattr *src, int count);
int nla_memcmp(const struct nlattr *nla, const void *data, size_t size);
+1 −1
Original line number Diff line number Diff line
@@ -512,7 +512,7 @@ tcf_change_indev(struct net *net, struct nlattr *indev_tlv,
	char indev[IFNAMSIZ];
	struct net_device *dev;

	if (nla_strlcpy(indev, indev_tlv, IFNAMSIZ) >= IFNAMSIZ) {
	if (nla_strlcpy(indev, indev_tlv, IFNAMSIZ) < 0) {
		NL_SET_ERR_MSG_ATTR(extack, indev_tlv,
				    "Interface name too long");
		return -EINVAL;
+25 −14
Original line number Diff line number Diff line
@@ -710,33 +710,44 @@ EXPORT_SYMBOL(nla_find);

/**
 * nla_strlcpy - Copy string attribute payload into a sized buffer
 * @dst: where to copy the string to
 * @nla: attribute to copy the string from
 * @dstsize: size of destination buffer
 * @dst: Where to copy the string to.
 * @nla: Attribute to copy the string from.
 * @dstsize: Size of destination buffer.
 *
 * Copies at most dstsize - 1 bytes into the destination buffer.
 * The result is always a valid NUL-terminated string. Unlike
 * strlcpy the destination buffer is always padded out.
 * Unlike strlcpy the destination buffer is always padded out.
 *
 * Returns the length of the source buffer.
 * Return:
 * * srclen - Returns @nla length (not including the trailing %NUL).
 * * -E2BIG - If @dstsize is 0 or greater than U16_MAX or @nla length greater
 *            than @dstsize.
 */
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
ssize_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
{
	size_t srclen = nla_len(nla);
	char *src = nla_data(nla);
	ssize_t ret;
	size_t len;

	if (dstsize == 0 || WARN_ON_ONCE(dstsize > U16_MAX))
		return -E2BIG;

	if (srclen > 0 && src[srclen - 1] == '\0')
		srclen--;

	if (dstsize > 0) {
		size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
	if (srclen >= dstsize) {
		len = dstsize - 1;
		ret = -E2BIG;
	} else {
		len = srclen;
		ret = len;
	}

	memcpy(dst, src, len);
	/* Zero pad end of dst. */
	memset(dst + len, 0, dstsize - len);
	}

	return srclen;
	return ret;
}
EXPORT_SYMBOL(nla_strlcpy);

+1 −1
Original line number Diff line number Diff line
@@ -939,7 +939,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
			NL_SET_ERR_MSG(extack, "TC action kind must be specified");
			goto err_out;
		}
		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) {
		if (nla_strlcpy(act_name, kind, IFNAMSIZ) < 0) {
			NL_SET_ERR_MSG(extack, "TC action name too long");
			goto err_out;
		}
+1 −1
Original line number Diff line number Diff line
@@ -223,7 +223,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
static bool tcf_proto_check_kind(struct nlattr *kind, char *name)
{
	if (kind)
		return nla_strlcpy(name, kind, IFNAMSIZ) >= IFNAMSIZ;
		return nla_strlcpy(name, kind, IFNAMSIZ) < 0;
	memset(name, 0, IFNAMSIZ);
	return false;
}
Loading