Implement strlcpy [BZ #178]
diff mbox

Message ID 5416EDEA.4080903@redhat.com
State New
Headers show

Commit Message

Florian Weimer Sept. 15, 2014, 1:47 p.m. UTC
This patch adds an implementation of strlcpy.

I think it shows that we can do much better than custom implementations 
in libbsd and random applications:

* This version is based on optimized strnlen and memcpy implementation.

* It has fortify support.

* In fortify mode, there a link-time warnings for common misuses.
   (The location of the warning could be improved,
   but this is a GCC issue.)

If this is patch is accepted, I will work on an implementation of 
strlcat along similar lines.

Comments

Rich Felker Sept. 15, 2014, 3:34 p.m. UTC | #1
On Mon, Sep 15, 2014 at 03:47:22PM +0200, Florian Weimer wrote:
> +size_t
> +strlcpy(char *__restrict dest, const char *__restrict src, size_t size)
> +{
> +  if (__glibc_unlikely (size == 0))
> +    return 0;

This is definitely wrong. strlcpy always returns strlen(src),
regardless of what it can or cannot store. See the specification here:

http://www.openbsd.org/cgi-bin/man.cgi?query=strlcpy

> +  size_t src_length = strnlen (src, size);
> +  if (__glibc_unlikely (src_length >= size))
> +    {
> +      /* Copy the leading portion of the string, excluding the NUL
> +	 character.  The last character will be overwritten, but the
> +	 destination size is usually a multiple of a small power of
> +	 two, so writing it twice should be more efficient.  */
> +      memcpy (dest, src, size);
> +      dest[size - 1] = '\0';
> +      return size - 1;
> +    }
> +  else
> +    {
> +      /* Copy the string and its terminating NUL character.  */
> +      memcpy (dest, src, src_length + 1);
> +      return src_length;
> +    }
> +}
> +libc_hidden_def (strlcpy)

And likewise this is wrong. You need strlen, not strnlen. I agree in
many respects an interface that returned something like strnlen would
have been nicer, but the only thing worse than having applications
provide their own buggy and incompatible versions of this function is
having the system libc provide an incompatible version. If this kind
of incompatibility made it into glibc, the amount of hackery trying to
determine whether the system libc's strlcpy is usable or needs to be
replaced would vastly increase (probably in ways that break
cross-compiling due to trying to perform runtime tests) and we'd have
an utter mess.

Rich
Paul Eggert Sept. 15, 2014, 3:53 p.m. UTC | #2
It would not be a good idea to add this to glibc, not only because this 
implementation would be incompatible with OpenBSD's, but more generally 
because the interface is poorly designed.

It's *particularly* not a good idea to add propaganda to the manual, 
with phrases calling strlcpy "more useful".  I mean, c'mon.
Rich Felker Sept. 15, 2014, 4:20 p.m. UTC | #3
On Mon, Sep 15, 2014 at 08:53:06AM -0700, Paul Eggert wrote:
> It would not be a good idea to add this to glibc, not only because
> this implementation would be incompatible with OpenBSD's, but more
> generally because the interface is poorly designed.

This has already been discussed over and over. We know you don't like
the interface. I don't either. But it should be in glibc. I'm not
going to repeat the reasons; you can read the archive where it was
stated that there is no longer any fundamental(ist) opposition to
including it as long as a correct implementation is proposed following
the usual rules for adding stuff to glibc.

Rich
Rich Felker Sept. 15, 2014, 4:21 p.m. UTC | #4
On Mon, Sep 15, 2014 at 08:53:06AM -0700, Paul Eggert wrote:
> It's *particularly* not a good idea to add propaganda to the manual,
> with phrases calling strlcpy "more useful".  I mean, c'mon.

I'm perfectly fine with the manual addition stating that this function
is not recommended for use in new code. In fact that's what I would
prefer too.

Rich
Florian Weimer Sept. 15, 2014, 4:36 p.m. UTC | #5
On 09/15/2014 05:53 PM, Paul Eggert wrote:
> It would not be a good idea to add this to glibc, not only because this
> implementation would be incompatible with OpenBSD's, but more generally
> because the interface is poorly designed.

How is it incompatible with the OpenBSD implementation?

> It's *particularly* not a good idea to add propaganda to the manual,
> with phrases calling strlcpy "more useful".  I mean, c'mon.

The original documentation for strncpy already called it “rarely 
useful”, otherwise I wouldn't have used this phrasing.
Paul Eggert Sept. 15, 2014, 4:45 p.m. UTC | #6
On 09/15/2014 09:36 AM, Florian Weimer wrote:
>
> How is it incompatible with the OpenBSD implementation?
>

As Rich Felker mentioned, OpenBSD strlcpy always returns the length of 
the source, regardless of what was stored.

> The original documentation for strncpy already called it “rarely 
> useful”, otherwise I wouldn't have used this phrasing.
>

strlcpy is rarely useful as well.  I agree with Rich that if we document 
strlcpy, we should say that it's not recommended for new code.  We 
should also mention the above problem, which unfortunately is an 
all-too-common misunderstanding of how strlcpy works.

But really, it'd be better to keep leaving it out.  It's just a mess.
David Miller Sept. 15, 2014, 4:56 p.m. UTC | #7
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 15 Sep 2014 09:45:07 -0700

> On 09/15/2014 09:36 AM, Florian Weimer wrote:
>>
>> How is it incompatible with the OpenBSD implementation?
>>
> 
> As Rich Felker mentioned, OpenBSD strlcpy always returns the length of
> the source, regardless of what was stored.
> 
>> The original documentation for strncpy already called it “rarely
>> useful”, otherwise I wouldn't have used this phrasing.
>>
> 
> strlcpy is rarely useful as well.  I agree with Rich that if we
> document strlcpy, we should say that it's not recommended for new
> code.  We should also mention the above problem, which unfortunately
> is an all-too-common misunderstanding of how strlcpy works.
> 
> But really, it'd be better to keep leaving it out.  It's just a mess.

This is really confusing.

If glibc never had strlcpy before, it's an oxymoron to say it shouldn't
be used for new code because that's the only possible usage of it.

If people are just going to start using the glibc copy when available
instead of their own home-grown tree local implementation, which seems
to be the only remaining "suggested" usage, I say that's bogus too.

So we're providing an interface for people using strlcpy, but at the
same time we don't want people to use strlcpy and rather have them
use "something else."

Our actions are going to encourage them to continue using strlcpy.
Florian Weimer Sept. 15, 2014, 6:05 p.m. UTC | #8
On 09/15/2014 06:56 PM, David Miller wrote:
>> But really, it'd be better to keep leaving it out.  It's just a mess.
> 
> This is really confusing.
> 
> If glibc never had strlcpy before, it's an oxymoron to say it shouldn't
> be used for new code because that's the only possible usage of it.
> 
> If people are just going to start using the glibc copy when available
> instead of their own home-grown tree local implementation, which seems
> to be the only remaining "suggested" usage, I say that's bogus too.
> 
> So we're providing an interface for people using strlcpy, but at the
> same time we don't want people to use strlcpy and rather have them
> use "something else."
> 
> Our actions are going to encourage them to continue using strlcpy.

We could point out that using strlcpy with statically sized buffers is
against the GNU Coding Standards, which recommend dynamic, on-demand
buffer allocation.

Here's some more background why I'm proposing this.  Fedora has over 60
source packages which compile to binary packages which define strlcpy or
strlcat.  Many of these packages will not go away, ever.  Only a subset
of the software has a strong (Open)BSD affinity.

The implementations I have seen bypass fortify protection.  We could
make libbsd the canonical implementation and bring it up to current
glibc standards, but it would be a Fedora-only effort with limited
benefit.  And I'd rather wish libbsd would go away (the fgetln
implementation is sufficient reason for that).
Jonathan Nieder Sept. 15, 2014, 6:08 p.m. UTC | #9
Florian Weimer wrote:

> The implementations I have seen bypass fortify protection.  We could
> make libbsd the canonical implementation and bring it up to current
> glibc standards, but it would be a Fedora-only effort with limited
> benefit.

Why would that be a Fedora-only effort with limited benefit?

Curious,
Jonathan
Adhemerval Zanella Sept. 15, 2014, 6:10 p.m. UTC | #10
On 15-09-2014 13:56, David Miller wrote:
> From: Paul Eggert <eggert@cs.ucla.edu>
> Date: Mon, 15 Sep 2014 09:45:07 -0700
>
>> On 09/15/2014 09:36 AM, Florian Weimer wrote:
>>> How is it incompatible with the OpenBSD implementation?
>>>
>> As Rich Felker mentioned, OpenBSD strlcpy always returns the length of
>> the source, regardless of what was stored.
>>
>>> The original documentation for strncpy already called it “rarely
>>> useful”, otherwise I wouldn't have used this phrasing.
>>>
>> strlcpy is rarely useful as well.  I agree with Rich that if we
>> document strlcpy, we should say that it's not recommended for new
>> code.  We should also mention the above problem, which unfortunately
>> is an all-too-common misunderstanding of how strlcpy works.
>>
>> But really, it'd be better to keep leaving it out.  It's just a mess.
> This is really confusing.
>
> If glibc never had strlcpy before, it's an oxymoron to say it shouldn't
> be used for new code because that's the only possible usage of it.
>
> If people are just going to start using the glibc copy when available
> instead of their own home-grown tree local implementation, which seems
> to be the only remaining "suggested" usage, I say that's bogus too.
>
> So we're providing an interface for people using strlcpy, but at the
> same time we don't want people to use strlcpy and rather have them
> use "something else."
>
> Our actions are going to encourage them to continue using strlcpy.
>
I also don't seem useful to add these interfaces to GLIBC. From last discussion, the
examples discussed showed no advantage using them and in some cases they in fact
clobbered real issues by the (wrong) assumption that truncate is better than buffer
overrun.

The only reasonable suggestion I noted was that since programs uses it, for GLIBC
they tend to use external implementations that may have not correctly implementations.
However this suggestion falls in the logic you just noted: we will provide an interface
that we will suggest to *not* use for security reasons and we will also need to sync
somewhat with other implementation that might be sub-par as well.
David Miller Sept. 15, 2014, 6:53 p.m. UTC | #11
From: Florian Weimer <fweimer@redhat.com>
Date: Mon, 15 Sep 2014 20:05:55 +0200

> On 09/15/2014 06:56 PM, David Miller wrote:
>>> But really, it'd be better to keep leaving it out.  It's just a mess.
>> 
>> This is really confusing.
>> 
>> If glibc never had strlcpy before, it's an oxymoron to say it shouldn't
>> be used for new code because that's the only possible usage of it.
>> 
>> If people are just going to start using the glibc copy when available
>> instead of their own home-grown tree local implementation, which seems
>> to be the only remaining "suggested" usage, I say that's bogus too.
>> 
>> So we're providing an interface for people using strlcpy, but at the
>> same time we don't want people to use strlcpy and rather have them
>> use "something else."
>> 
>> Our actions are going to encourage them to continue using strlcpy.
> 
> We could point out that using strlcpy with statically sized buffers is
> against the GNU Coding Standards, which recommend dynamic, on-demand
> buffer allocation.
> 
> Here's some more background why I'm proposing this.  Fedora has over 60
> source packages which compile to binary packages which define strlcpy or
> strlcat.  Many of these packages will not go away, ever.  Only a subset
> of the software has a strong (Open)BSD affinity.

I think the fact that there are 60 such cases supports my arguments
even more strongly, because that is how many strlcpy users are even
less likely to ever change if glibc supports strlcpy too.

I'm not really strongly apposed to adding strlcpy to glibc.  But we
should be completely honest about why we are doing this, what the
effects on existing strlcpy users actually is, and what we should
genuinely recommend to people writing new code.
Russ Allbery Sept. 17, 2014, 2:09 a.m. UTC | #12
David Miller <davem@davemloft.net> writes:

> I think the fact that there are 60 such cases supports my arguments even
> more strongly, because that is how many strlcpy users are even less
> likely to ever change if glibc supports strlcpy too.

I'm pretty sure I have a package for which I'm upstream in Fedora, which
means I represent one of those uses.  (And there's at least INN, for which
I was responsible for introducing strlcpy.)  Based on the previous
conversation, I'll probably eventually end up removing strlcpy entirely in
favor of other techniques, but all my packages that currently use strlcpy
only optionally compile it if it's not in libc.  If it's in libc, the
system version is preferred, since it's presumably more optimized and
possibly safer.

I suspect this is not uncommon among strlcpy users.  (Basically, using
AC_REPLACE_FUNCS.)
Florian Weimer Sept. 17, 2014, 12:53 p.m. UTC | #13
On 09/17/2014 04:09 AM, Russ Allbery wrote:
> David Miller <davem@davemloft.net> writes:
>
>> I think the fact that there are 60 such cases supports my arguments even
>> more strongly, because that is how many strlcpy users are even less
>> likely to ever change if glibc supports strlcpy too.
>
> I'm pretty sure I have a package for which I'm upstream in Fedora, which
> means I represent one of those uses.  (And there's at least INN, for which
> I was responsible for introducing strlcpy.)  Based on the previous
> conversation, I'll probably eventually end up removing strlcpy entirely in
> favor of other techniques, but all my packages that currently use strlcpy
> only optionally compile it if it's not in libc.  If it's in libc, the
> system version is preferred, since it's presumably more optimized and
> possibly safer.
>
> I suspect this is not uncommon among strlcpy users.  (Basically, using
> AC_REPLACE_FUNCS.)

Yes, that's what I meant with that anything we do outside glibc would be 
a distribution-specific effort.  It's not just AC_REPLACE_FUNCS, 
autoconf checks like this one

AC_LINK_IFELSE(
         [AC_LANG_PROGRAM(
                 [[#include <string.h>
                 #include <stdlib.h>]],
                 [[char *a = malloc(6);
                 strlcpy(a, "hello", 6);]]
         )],
         [AC_MSG_RESULT(yes)
         AC_DEFINE(HAVE_STRLCPY, 1, [Define if strlcpy is available 
(most BSDs.)])],
         [AC_MSG_RESULT(no)]
)

are used as well.  In theory, we could overlay <string.h> from libbsd on 
top of the glibc headers, but really want to do this only for a libbsd 
subset (because some of the things in libbsd are extremely gross).  This 
would avoid the need to change the autoconf detection logic in all 
packages, but it's still distribution-specific work, just less of it. 
On the other hand, it's just pie-in-the-sky because such build hacks are 
unlikely to be acceptable to Fedora and Debian, and perhaps rightly so.

Having these commonly used functions inside glibc proper would make 
things much easier.

Patch
diff mbox

From 4d3e24a591e818c4e01d02a3b98f64df9c120c0a Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Mon, 15 Sep 2014 15:45:56 +0200
Subject: [PATCH] Implement strlcpy [BZ #178]

This change may cause application code not to compile anymore, but
strlcpy is in the implementaton namespace (per C11 7.31.13), so this
is an application issue.

2014-09-15  Florian Weimer  <fweimer@redhat.com>

	[BZ #178]
	* string/Makefile (routines): Add strlcpy.
	(tests): Add tst-strlcpy.
	* string/Versions (2.21): Export strlcpy.
	* string/strlcpy.c: New file.
	* string/tst-strlcpy.c: Likewise.
	* include/string.h (strlcpy): Declare as hidden.
	* manual/string.h (Copying and Concatenation): Document strlcpy.
	Update strncpy documentation.
	* debug/Makefile (routines): Add strlcpy_chk.
	* debug/Versions (2.21): Export __strlcpy_chk.
	* debug/tst-chk1.c (doit): Test strlcpy.
	* debug/strlcpy_chk.c: New file.
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Add.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/arm/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/hppa/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/ia64/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/sh/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
	(GLIBC_2.21, strlcpy, __strlcpy_chk): Likewise.

diff --git a/NEWS b/NEWS
index 680c265..a24e178 100644
--- a/NEWS
+++ b/NEWS
@@ -9,7 +9,7 @@  Version 2.21
 
 * The following bugs are resolved with this release:
 
-  17363, 17370.
+  178, 17363, 17370.
 
 Version 2.20
 
diff --git a/debug/Makefile b/debug/Makefile
index c284c51..c5a69bf 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -30,6 +30,7 @@  headers	:= execinfo.h
 routines  = backtrace backtracesyms backtracesymsfd noophooks \
 	    memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \
 	    strcat_chk strcpy_chk strncat_chk strncpy_chk stpncpy_chk \
+	    strlcpy_chk \
 	    sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \
 	    printf_chk fprintf_chk vprintf_chk vfprintf_chk \
 	    gets_chk chk_fail readonly-area fgets_chk fgets_u_chk \
diff --git a/debug/Versions b/debug/Versions
index 0482c85..054f301 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -55,6 +55,9 @@  libc {
   GLIBC_2.16 {
     __poll_chk; __ppoll_chk;
   }
+  GLIBC_2.21 {
+    __strlcpy_chk;
+  }
   GLIBC_PRIVATE {
     __fortify_fail;
   }
diff --git a/debug/strlcpy_chk.c b/debug/strlcpy_chk.c
new file mode 100644
index 0000000..02dcb98
--- /dev/null
+++ b/debug/strlcpy_chk.c
@@ -0,0 +1,29 @@ 
+/* Copyright (C) 1991-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <memcopy.h>
+
+size_t
+__strlcpy_chk (char *__restrict s1, const char *__restrict s2,
+	       size_t n, size_t s1len)
+{
+  if (__glibc_unlikely (s1len < n))
+    __chk_fail ();
+
+  return strlcpy (s1, s2, n);
+}
diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c
index 3393153..48fb4a5 100644
--- a/debug/tst-chk1.c
+++ b/debug/tst-chk1.c
@@ -360,6 +360,10 @@  do_test (void)
   strncpy (a.buf1 + (O + 6), "X", l0 + 4);
   CHK_FAIL_END
 
+  CHK_FAIL_START
+  strlcpy (buf, "", sizeof (buf) + 1);
+  CHK_FAIL_END
+
 # if !defined __cplusplus || defined __va_arg_pack
   CHK_FAIL_START
   sprintf (a.buf1 + (O + 7), "%d", num1);
diff --git a/include/string.h b/include/string.h
index 8323412..107db84 100644
--- a/include/string.h
+++ b/include/string.h
@@ -89,6 +89,7 @@  libc_hidden_proto (__strtok_r)
 extern char *__strsep_g (char **__stringp, const char *__delim);
 libc_hidden_proto (__strsep_g)
 libc_hidden_proto (strnlen)
+libc_hidden_proto (strlcpy)
 libc_hidden_proto (memmem)
 libc_hidden_proto (__ffs)
 
diff --git a/manual/string.texi b/manual/string.texi
index ba5a2c7..0571099 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -576,17 +576,42 @@  there is no null terminator written into @var{to}.
 
 If the length of @var{from} is less than @var{size}, then @code{strncpy}
 copies all of @var{from}, followed by enough null characters to add up
-to @var{size} characters in all.  This behavior is rarely useful, but it
-is specified by the @w{ISO C} standard.
+to @var{size} characters in all.
 
 The behavior of @code{strncpy} is undefined if the strings overlap.
 
-Using @code{strncpy} as opposed to @code{strcpy} is a way to avoid bugs
+Not guaranteeing null termination and always overwriting the entire
+destination buffer makes @code{strncpy} rarely useful, but this behavior
+is specified by the @w{ISO C} standard.  See @code{strlcpy} below for a
+more useful alternative.
+@end deftypefun
+
+@comment string.h
+@comment BSD
+@deftypefun size_t strlcpy (char *restrict @var{to}, const char *restrict @var{from}, size_t @var{size})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+This function is similar to @code{strcpy}, but copies at most @var{size}
+characters into @var{to}, including the terminating null character.
+
+If the length of @var{from} is equal to or more than @var{size}, then
+@code{strlcpy} copies just the first @samp{@var{size} - 1} characters.
+As a special case, if @var{size} is zero, no bytes are written to
+@var{to}.
+
+If the length of @var{from} is less than @var{size}, then @code{strlcpy}
+copies all of @var{from}, followed by a single null character.
+
+The return value of @code{strlcpy} is the length of the string @var{to}
+after the function call, or zero if @var{size} is zero.
+
+The behavior of @code{strlcpy} is undefined if the strings overlap or if
+the source or destination are null pointers.
+
+Using @code{strlcpy} as opposed to @code{strcpy} is a way to avoid bugs
 relating to writing past the end of the allocated space for @var{to}.
-However, it can also make your program much slower in one common case:
-copying a string which is probably small into a potentially large buffer.
-In this case, @var{size} may be large, and when it is, @code{strncpy} will
-waste a considerable amount of time copying null characters.
+Unlike @code{strncpy}, @code{strlcpy} ensures that the destination
+string is always null-terminated (unless the buffer size is zero), and
+it does not fill the remaining part of the buffer with null characters.
 @end deftypefun
 
 @comment wchar.h
diff --git a/string/Makefile b/string/Makefile
index 98c2961..1033852 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -41,7 +41,7 @@  routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
 				     addsep replace)			\
 		   envz basename					\
 		   strcoll_l strxfrm_l string-inlines memrchr		\
-		   xpg-strerror strerror_l
+		   xpg-strerror strerror_l strlcpy
 
 strop-tests	:= memchr memcmp memcpy memmove mempcpy memset memccpy	\
 		   stpcpy stpncpy strcat strchr strcmp strcpy strcspn	\
@@ -54,7 +54,7 @@  tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 		   tst-strtok tst-strxfrm bug-strcoll1 tst-strfry	\
 		   bug-strtok1 $(addprefix test-,$(strop-tests))	\
 		   bug-envz1 tst-strxfrm2 tst-endian tst-svc2		\
-		   tst-strtok_r
+		   tst-strtok_r tst-strlcpy
 
 xtests = tst-strcoll-overflow
 
diff --git a/string/Versions b/string/Versions
index 59bf35a..b73526b 100644
--- a/string/Versions
+++ b/string/Versions
@@ -80,4 +80,7 @@  libc {
   GLIBC_2.6 {
     strerror_l;
   }
+  GLIBC_2.21 {
+    strlcpy;
+  }
 }
diff --git a/string/bits/string3.h b/string/bits/string3.h
index 7606090..ffe8f0b 100644
--- a/string/bits/string3.h
+++ b/string/bits/string3.h
@@ -38,6 +38,7 @@  __warndecl (__warn_memset_zero_len,
 #  undef stpcpy
 # endif
 # ifdef __USE_MISC
+#  undef strlcpy
 #  undef bcopy
 #  undef bzero
 # endif
@@ -149,3 +150,29 @@  __NTH (strncat (char *__restrict __dest, const char *__restrict __src,
 {
   return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
 }
+
+#ifdef __USE_MISC
+__warndecl (__warn_strlcpy_size_zero,
+	    "strlcpy used with a size argument of zero");
+__warndecl (__warn_strlcpy_size_large,
+	    "strlcpy used with a size argument which is too large");
+extern size_t __strlcpy_chk (char *__dest, const char *__src, size_t __n,
+			     size_t __destlen) __THROW;
+
+__fortify_function size_t
+__NTH (strlcpy (char *__restrict __dest, const char *__restrict __src,
+		size_t __len))
+{
+  if (__builtin_constant_p (__len == 0) && __len == 0)
+    {
+      __warn_strlcpy_size_zero ();
+      return 0;
+    }
+  if (__builtin_constant_p (__len > __bos (__dest)) && __len > __bos (__dest))
+    __warn_strlcpy_size_large ();
+  if (__builtin_constant_p (__bos (__dest) == (size_t) -1)
+      && __bos (__dest) == (size_t) -1)
+    return strlcpy (__dest, __src, __len);
+  return __strlcpy_chk (__dest, __src, __len, __bos (__dest));
+}
+#endif
diff --git a/string/string.h b/string/string.h
index c79debc..a635918 100644
--- a/string/string.h
+++ b/string/string.h
@@ -578,6 +578,13 @@  extern char *stpncpy (char *__restrict __dest,
      __THROW __nonnull ((1, 2));
 #endif
 
+#ifdef __USE_MISC
+/* Copy at most N characters from SRC to DEST.  */
+extern size_t strlcpy (char *__restrict __dest,
+		       const char *__restrict __src, size_t __n)
+  __THROW __nonnull ((1, 2));
+#endif
+
 #ifdef	__USE_GNU
 /* Compare S1 and S2 as strings holding name & indices/version numbers.  */
 extern int strverscmp (const char *__s1, const char *__s2)
diff --git a/string/strlcpy.c b/string/strlcpy.c
new file mode 100644
index 0000000..1ddfafb
--- /dev/null
+++ b/string/strlcpy.c
@@ -0,0 +1,46 @@ 
+/* Copyright (C) 2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+
+#undef strlcpy
+
+size_t
+strlcpy(char *__restrict dest, const char *__restrict src, size_t size)
+{
+  if (__glibc_unlikely (size == 0))
+    return 0;
+
+  size_t src_length = strnlen (src, size);
+  if (__glibc_unlikely (src_length >= size))
+    {
+      /* Copy the leading portion of the string, excluding the NUL
+	 character.  The last character will be overwritten, but the
+	 destination size is usually a multiple of a small power of
+	 two, so writing it twice should be more efficient.  */
+      memcpy (dest, src, size);
+      dest[size - 1] = '\0';
+      return size - 1;
+    }
+  else
+    {
+      /* Copy the string and its terminating NUL character.  */
+      memcpy (dest, src, src_length + 1);
+      return src_length;
+    }
+}
+libc_hidden_def (strlcpy)
diff --git a/string/tst-strlcpy.c b/string/tst-strlcpy.c
new file mode 100644
index 0000000..c1ee9d3
--- /dev/null
+++ b/string/tst-strlcpy.c
@@ -0,0 +1,72 @@ 
+/* Copyright (C) 1998-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define CHECK(cond)					\
+  if (!(cond))						\
+    {							\
+      printf ("%s:%d: FAIL\n", __FILE__, __LINE__);	\
+      exit (1);						\
+    }
+
+static int
+do_test (void)
+{
+  struct {
+    char buf1[16];
+    char buf2[16];
+  } s;
+
+  memset (&s, '@', sizeof (s));
+  CHECK (strlcpy (s.buf1, "Hello!", 0) == 0);
+  CHECK (memcmp (&s, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+
+  memset (&s, '@', sizeof (s));
+  CHECK (strlcpy (s.buf1, "Hello!", sizeof (s.buf1)) == 6);
+  CHECK (memcmp (&s, "Hello!\0@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+
+  memset (&s, '@', sizeof (s));
+  CHECK (strlcpy (s.buf1, "Hello, world!!!", sizeof (s.buf1)) == 15);
+  CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+		 sizeof (s)) == 0);
+
+  memset (&s, '@', sizeof (s));
+  CHECK (strlcpy (s.buf1, "Hello, world!!!", sizeof (s.buf1)) == 15);
+  unsigned i;
+  for (i = 0; i < sizeof (s); ++i) {
+    printf ("   %u: %u\n", i, (unsigned) ((char *)&s)[i]);
+  }
+  CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+		 sizeof (s)) == 0);
+
+  memset (&s, '@', sizeof (s));
+  CHECK (strlcpy (s.buf1, "Hello, world!!!!!!!!", sizeof (s.buf1)) == 15);
+  for (i = 0; i < sizeof (s); ++i) {
+    printf ("   %u: %u\n", i, (unsigned) ((char *)&s)[i]);
+  }
+  CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+		 sizeof (s)) == 0);
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index aeee312..dd6bec6 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2081,3 +2081,7 @@  GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
  _mcount F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 980e088..8d5c64a 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2012,6 +2012,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index ce45208..0cd75dd 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -89,6 +89,10 @@  GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.4
  GLIBC_2.4 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 58407fc..b2548f5 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1860,6 +1860,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 3cb314d..71c7f9b 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2023,6 +2023,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 067552d..9ed65fd 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1881,6 +1881,10 @@  GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
  getunwind F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index f06cc8e..298aed0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -90,6 +90,10 @@  GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.4
  GLIBC_2.4 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 9010ea7..d11b097 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1979,6 +1979,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 6e8d993..fd7c888 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2080,3 +2080,7 @@  GLIBC_2.18
  xencrypt F
  xprt_register F
  xprt_unregister F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 1c3490c..5e6c63a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1951,6 +1951,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index d8fd823..652b03d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1949,6 +1949,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 3e6ed35..659c9f4 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1947,6 +1947,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index c7e46aa..8e98919 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1941,6 +1941,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index f27b48b..580c85d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1983,6 +1983,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index a54382e..3f65044 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1989,6 +1989,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 195b587..f21e487 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -90,6 +90,10 @@  GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 0194f0b..372fb0b 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1984,6 +1984,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 807f702..6fdf3af 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1880,6 +1880,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index a653292..457c2ac 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1864,6 +1864,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 9defbdf..1f89cfe 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1975,6 +1975,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 35987fa..a1d0243 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1908,6 +1908,10 @@  GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index caf74b8..e9a5540 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2091,3 +2091,7 @@  GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index 68d975b..0c699ef 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2091,3 +2091,7 @@  GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index caf74b8..e9a5540 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2091,3 +2091,7 @@  GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 914b590..0e8714a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1854,6 +1854,10 @@  GLIBC_2.2.5
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 0f64c8d..f4b638f 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2089,3 +2089,7 @@  GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.21
+ GLIBC_2.21 A
+ __strlcpy_chk F
+ strlcpy F
-- 
1.9.3